web-dev-qa-db-ja.com

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

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

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

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


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

16
Chaulky

あなたがしなければならないことは、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);
}
11
Decipher

Chain Menu Access API モジュールを探しています。

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

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

1
crantok

上記のコメントに応じて、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
Dave Reid