P164の「menuコールバックの変更」についてP164の「menuコールバックの変更」について

はじめまして
Drupal2週間目のtitou36jpともうします。

早速ですが、ご質問させてください。
タイトルの掲題の件ですが
自分の理解ですと「administer nodes」権限を持つユーザーは「管理者」であると認識しています。
また、「hook_menu_alter()」がDrupalからコールされるタイミングは
モジュールを有効にした場合のみ
つまり、「管理者」以外はモジュールを有効に出来ないと理解しています。
※間違った理解でしたら、申し訳ありません。

従いまして
if (!user_access('administer nodes')) {
$callbacks['node/add/joke']['access callback'] = FALSE;
unset($callbacks['node/add/joke']['access arguments']);
}
の条件が通り、上記のif文内のブロックが実行される場合は有るのでしょうか?
例えば
if (!user_access('create joke')) {
$callbacks['node/add/joke']['access callback'] = FALSE;
unset($callbacks['node/add/joke']['access arguments']);
}
であれば、何となく理解できます。

未だ、Drupalを学習中の身である為
意味不明な質問となっていますが
宜しくお願いします。

p.164の修正案

Takafumiさんのユーザアバター

p.164 の当該箇所の説明を以下のように修正しようと思いますが、いかがでしょうか? > titou36jpさん、0829さん、あるいはすべての読者の皆さん

ここでの説明は、『「コンテンツの作成」ページにリンクを追加するために hook_menu() は不要』ということと、『必要に応じてそれらも変更可能』ということを説明しているのだと思いますし、パーミッション云々はこの後で説明と実装がされていますので、この段階で説明するのは適当ではないように思います。
ですので、単に『ダイレクトリンクを追加したくない場合は削除可能』という点に絞った説明とコードに変更してみました。
ちなみに変更後のコードは、リンクは非表示となりますが、ダイレクトにアクセスすることは可能というものです。

セクションのタイトル

■ menuコールバックの変更
↓↓↓
■ メニュー項目の変更

文章

ダイレクトリンクを追加したくない場合は、hook_menu_alter()を使用して削除することが
できます。例えば次のコードは、「ノードの管理」 権限を持たないユーザからページを削除す
るコードです。
↓↓↓
ダイレクトリンクを追加したくない場合は、hook_menu_link_alter()を使用して削除することが
できます。例えば次のコードは、「jokeの作成」ページへのダイレクトリンクを非表示にする
コードです。

コード

/**
 * hook_menu_alter()の実装
 */
function joke_menu_alter(&$callbacks) {
  // ユーザが「ノードの管理」権限を持たない場合、
  // access callbackをFALSEに設定してjokeメニュー項目を無効にする
  if (!user_access('administer nodes')) {
    $callbacks['node/add/joke']['access callback'] = FALSE;
    // デフォルトのアクセスコールバックとしてuser_access()を使用されないために、
    // access argumentsを破棄する必要がある
    unset($callbacks['node/add/joke']['access arguments']);
  }
}

↓↓↓

/**
 * hook_menu_link_alter()の実装
 */
function joke_menu_link_alter(&$item, $menu) {
  // 「jokeの作成」ページへのダイレクトリンクを非表示にする
  if ($item['link_path'] == 'node/add/joke') {
    $item['hidden'] = 1;
  }
}

了解しました

お手数おかけしました。
有難うございます。

CMS、PHP共に初体験なため
意味不明な質問をするかと思いますが
これからも宜しくお願い致します。

ありがとうございました

Takafumiさんのユーザアバター

titou36jpさんの疑問から、結果的に書籍内の誤りを修正することができ、感謝しています。
今後も何か疑問に感じた点があれば遠慮なくご投稿ください。

Re: p.164の修正案

見当違いな指摘ではなかったようで、安心しました。^^;

修正案に関しましては、密かに hook_menu_link_alter() を使った方が... と思っていましたので、コードに対する説明文も含め、良いと思います。

ご指摘ありがとうございました

Takafumiさんのユーザアバター

0829さんからのご指摘がなければコードの不具合に気づかないところでしたので感謝しています。
なお、セクションのタイトルは「ダイレクトリンクの削除」の方が適当かと思いましたので、そのように変更し、言及しておきました。

Re: ご指摘ありがとうございました

いえ、私も、titou36jp さんからご質問をいただくまでは全く気付いていませんでしたので...^^;
titou36jp さんに感謝です。 ありがとうございました。

なお、タイトルに関しても、文章およびコードの変更に合致させるため、変更ということで良いと思います。(念の為)

認識の誤りです

Takafumiさんのユーザアバター

P174の「menuコールバックの変更」について

正しくは p.164 ですのでタイトルを修正しました。

自分の理解ですと「administer nodes」権限を持つユーザーは「管理者」であると認識しています。
また、「hook_menu_alter()」がDrupalからコールされるタイミングは
モジュールを有効にした場合のみ
つまり、「管理者」以外はモジュールを有効に出来ないと理解しています。

根本的な認識に誤りがあるようです。
Drupalでは、自動的にすべての権限を持つスーパーユーザ(ユーザIDが1)以外は、ロールごとにあらゆる権限の許可・不許可を設定することができ、「administer nodes」権限も例外ではありません。
おそらく、他のCMSなどに見られる単純な権限区分(管理者・登録ユーザ・ゲストなど)が念頭にあるのだと思いますが、Drupalではその「管理者」の定義は当てはまりません。
また、hook_menu_alter()がコールされるタイミングは、モジュールが有効で、かつ、メニューが構築される際です。

従いまして
if (!user_access('administer nodes')) {
$callbacks['node/add/joke']['access callback'] = FALSE;
unset($callbacks['node/add/joke']['access arguments']);
}
の条件が通り、上記のif文内のブロックが実行される場合は有るのでしょうか?

このコードは正しく動作します。

ご指摘ありがとうございます

ご指摘通り
administer nodes」権限も無しでモジュールのインストール可能なロールを設定して確認したところ
動作致しました。
ご指摘ありがとうございました。

ただ、一点ご質問させてください。
「hook_menu_alter()がコールされるタイミングは、モジュールが有効で、かつ、メニューが構築される際」
と、ご指摘されているタイミングなのですが
それは、例えば「joke」モジュールが有効であり、かつ「コンテンツの作成」リンクを押下するタイミングでしょうか?
私の知識不足なのでしょうが、「joke」モジュールを「無効」→「有効」に切り替えるタイミングでしか
hook_menu_alter()がコールされません。
確認方法としては、ログ出力とPDTでブレークポイントを貼ってステップ実行して確認しているのですが
ご教授して頂けると有りがたいです。

hook_menu_alter()

Takafumiさんのユーザアバター

「hook_menu_alter()がコールされるタイミングは、モジュールが有効で、かつ、メニューが構築される際」
と、ご指摘されているタイミングなのですが
それは、例えば「joke」モジュールが有効であり、かつ「コンテンツの作成」リンクを押下するタイミングでしょうか?
私の知識不足なのでしょうが、「joke」モジュールを「無効」→「有効」に切り替えるタイミングでしか
hook_menu_alter()がコールされません。

正しくは「menu_routerテーブルが再構築されるタイミング」となり、p.92 や p.32 にいくつかの例が掲載されていますので参考にしてください。(メニュー再構築の必要がある箇所が書籍内に何箇所かあると思います)

なお、先の私のコメントで「コードは正しく動作します」と書きましたが、0829さんから「このコードは誤りではないか?」とのご指摘を受け、再度検証してみました。
その結果、コード自体は動作するものの、書籍で説明している内容のとおりにはゆかず、権限を所有しているかどうかにかかわらず、すべてのユーザがアクセス不可となることがわかりました。
これは、先述のとおり、hook_menu_alter()がmenu_routerテーブルが再構築される際にしかコールされないため、権限をチェックして動的にアクセスコールバックを変更することができないためです。
これを回避するためには、アクセスコールバックに独自関数を定義し、その関数内で権限のチェックを行えばよいかと思いますが、このページで説明していることを実現する方法は他にもあるようにも思いますので、後ほど何らかのコードを考えてみたいと思います。
さしあたり、そのコードは原著の誤りであると認識してください。

Re: P164の「menuコールバックの変更」について

完全にすべての権限を持っているユーザを「管理者」とするのであれば、Drupal では、インストール時に作成する特別なユーザ(「ユーザ ID が "1" のユーザ」や「スーパーユーザ」などと呼ばれます)がそれに当たると思います。

ただ、Drupal では、ユーザ ID が "1" のユーザを除くすべてのユーザは、必ずいずれかのロールに属すことになり、それぞれのロール単位で詳細な権限の設定を行うことができるようになっていますので、どんなユーザでも、設定によっては "ノードの管理(administer nodes)権限は持たず、モジュールのインストール権限を持つユーザ" になり得ます。

ですので、「if (!user_access('administer nodes')) 」の条件を満たすことは可能かと...

なお、P.174 にて該当部分を見つけられませんでしたので、見当違いの回答になっていた場合にはご容赦ください。

[修正:該当箇所は P.164 ページだったようですので、タイトルのみ変更させて頂きました。]

Re: Re: P164の「menuコールバックの変更」について

ご回答ありがとうございます。
まず、ご指摘の該当ページの件ですが
おっしゃる通り、「P.164 」でした、申し訳ありません。

また、「ノードの管理(administer nodes)権限は持たず、モジュールのインストール権限を持つユーザ」に関しましても
ご指摘の通り、新規ユーザーを作成してロール単位で権限を設定したところ
動作する事が確認できました。

経験の浅い自分にとっては、大変ありがたいご指摘を頂き
有難うございます。