メニュー項目にアクセス条件を追加するにはどうすればよいですか?


17

メニュー項目が表示されるかどうかを決定する既存の条件の上に新しい条件を追加するにはどうすればよいですか?これらの条件は、アクセス許可の設定に限定されるべきではありません。

ユースケースの例として(必ずしもこの質問の理由ではありません):ユーザーが1つのノードのみを作成できるコンテンツタイプがあるとします。そのタイプのコンテンツを追加するためのメニュー項目があります。しかし、ユーザーが既にそのコンテンツタイプのノードを作成している場合は、メニュー項目を非表示にします。最初に考えたのは、現在のユーザーが作成した特定のコンテンツタイプのノードの存在を確認するクエリを実行することです。存在する場合は、メニュー項目を非表示にします。

このタイプの機能はhook_menu_alter()、そこに必要なロジックを追加する必要があると思います。しかし、ユーザーがその種類のコンテンツを作成する権限を持っているかどうかを確認するなど、既存のチェックをバイパスせずにそれを行う方法がわかりません。自分の条件にそのロジックを含める必要がありますか?または、既存のアクセスロジックを上書きせずに追加できますか?


編集:「コンテンツタイプのノードを1つだけ作成するようにユーザーを制限するにはどうすればよいか」という質問に集中する人もいます。ここでの質問ではありません。問題は、メニュー項目にカスタムアクセス条件を追加する方法です。

回答:


11

あなたがする必要があるのは、hook_menu_alter()経由でコールバックを追加することです。そして、コールバック内でロジックを実行し、元のコールバック経由でデータを返します。

他のhook_menu_alter()の変更を上書きしないようにするには、アクセス引数を介して以前のコールバックをコールバックに渡す必要があります。

これはすべて理論的ですが、コードは次のようになります。

MYMODULE_menu_alter(&$items) {
  $items['menu']['access arguments'] = array_merge(array($items['menu']['access callback']), $item['menu']['access arguments']);
  $items['menu']['access callback'] = 'MYMODULE_access_callback';
}

MYMODULE_access_callback() {
  $args = func_get_args();

  // Do Stuff.
  if ($something == FALSE) {
    return FALSE;
  }

  $function = array_shift($args);
  return call_user_func_array($function, $args);
}

新しいアクセスコールバック関数を割り当てると、元のコールバックが確実に上書きされますか?
ショールキー

はい、メニュー項目ごとにアクセスコールバックは1つしか持てないため、元のコールバックに確実に戻るようにしてください。パーミッションが重いモジュールの1つであるこのようなことを行うモジュールを見たことがありますが、どのモジュールを覚えていないのでしょう。
2011年

$ argsのarray_shiftは何をしていますか?
-Chaulky

「アクセス引数」から最初の引数を取り出し、古い「アクセスコールバック」を作成しました。したがって、古いコールバックが 'MYMODULE2_access_callback'であった場合、それがarray_shiftが返しているものです。また、配列からそれを削除して、コールバックが予期している引数のみを渡すようにします。
解読します。

1

上記のコメントに応えて、D7の解決策は以下を使用することです。

/**
 * Implements hook_node_access().
 */
function mymodule_node_access($node, $op, $account) {
  $type = is_string($node) ? $node : $node->type;

  if ($op == 'create' && $type == 'mynodetype' && db_query("SELECT 1 FROM {node} WHERE type = :type AND uid = :uid", array(':type' => $type, ':uid' => $account->uid))->fetchField()) {
    // If the user has already created a node of a specific type, they cannot
    // create any more.
    return NODE_ACCESS_DENY;
  }

  // Otherwise do not affect any node access.
  return NODE_ACCESS_IGNORE;
}

1
これはメニュー項目とは何の関係もないようです。私はまだD7に精通していませんが、これはノード作成に固有のようです。質問は、一般的にメニュー項目に焦点を当てています。
-Chaulky

なるほど...これは、ノード制限モジュールを指す回答で提案されたD7ソリューションの詳細を求める私のコメントへの応答です。まだ少し話題から外れていますが、ありがたいです。
-Chaulky

作成mynodetypeリンクの視認性のDrupal 7にこのフックを呼び出すことになるnode_access()関数によって制御されているので
デイブ・リード

1

チェーンメニューアクセスAPIモジュールを探しています。

チェーンメニューアクセスAPIを使用すると、モジュールは独自のメニューアクセスコールバック関数を他のモジュールのメニュールーターエントリにチェーンできます。

Drupal Stack Exchangeには、使用方法の少なくとも1つの例があります。


-1

1つのオプションは、コンテンツタイプのコンテンツ作成権限を持つ新しいロールを作成することです。ユーザーがそのタイプのノードを作成したら、そのロールを削除すると、それ以上作成できなくなります。


-1

おそらく、ノード制限モジュールを試してください。

プロジェクトページから:

ノード制限モジュールを使用すると、管理者はロールまたはユーザーが作成できる特定のタイプのノードの数を制限できます。たとえば、サイトに「広告」ノードを作成できる「広告主」ロールがある場合、ノード制限管理者はそのロールのすべてのユーザーを特定の数のノードに制限できます。また、ユーザーごとにユーザーを制限することもあります。


1つのノードに制限することは、カスタムアクセスコールバックメソッドを追加するための単なる使用例です。また、Node Limitはメニュー項目を削除せず、ユーザーがそのコンテンツタイプの別のノードを追加できないようにします。
Chaulky

モジュールの説明をもう一度確認すると、それは事実です。これがDrupal 7にある場合、実際に簡単になるのは、ノードタイプの作成リンク自体の可視性に影響するhook_node_access($ node、 'create'、$ account)を使用できるためです。
デイブリード

それは面白い。間もなくD7に移行する予定です。もっと詳しく書いて答えを投稿してくれませんか?
-Chaulky

回答のD7バージョンが投稿されました。
デイブリード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.