web-dev-qa-db-ja.com

どのように私はhook_menu()を実装する必要がありますか?

hook_menu()の実装の基本は何ですか?

同じような質問に何度も答える必要がないように、1つの質問で基本を説明したいと思います。

102
Letharion

この情報は、Drupal 6および7に対して有効です。Drupal 8の場合 hook_menu() は、 新しいルーティングシステム 。以下では、3つの簡単な手順でhook_menu()を実装しています。

第一歩

空のモジュールを作成する方法 の指示に従って空のモジュールを作成します。ここに示すコードでは、モジュールの名前がhelloworldであると想定しています。

ステップ2

次のコードをモジュールファイルに追加します。

_/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'title' => 'Hello world!',
    'page callback' => 'helloworld_page',
    'access callback' => TRUE,
  );

  return $items;
}

/**
 * Page callback for /hello.
 */
function helloworld_page() {
  return 'Hello world!';
}
_

ステップ3

モジュールを有効にし、 http://example.com/hello にアクセスします。 (example.comをサーバーのドメイン名に置き換えます。)
「Hello world!」というメッセージが表示されます。それでおしまい!完全に機能するhook_menu()実装があります。以下は、hook_menu()に関するさまざまな高度なトピックです。特に、上のページはだれでも見ることができるため、アクセス許可について読むことをお勧めします。

議論

ページコールバックにより多くのデータを渡したい場合は、ページ引数を使用してこれを実現できます。ページ引数は、ページコールバックに渡す引数の配列である必要があります。整数が引数として使用される場合、0から始まり、スラッシュ(/)ごとに1ずつ増加するURLの一部を表します。次の例では、これは0が「hello」に変わることを意味します。

_function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(0),
  );

  return $items;
}

function helloworld_page($argument1) {
  return $argument1;
}
_

文字列は逐語的に送信されるため、array(0, 'world')を使用して_hello world_を再度取得できます。

_function helloworld_page($argument1, $argument2) {
  return $argument1 . ' ' . $argument2;
}
_

「ワイルドカード」は、URLから任意のデータを受け入れるために使用できます。

_function helloworld_menu() {
  $items['hello/%'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
  );

  return $items;
}

function helloworld_page($argument1) {
  return $argument1;
}
_

Hello/worldにアクセスすると、_$argument1_はworldと等しくなります。

引数の自動読み込み

多くの場合、URL引数は、エンティティなどを識別する番号になります。このIDを対応するオブジェクトに変換するコードの重複を避けるために、Drupalは「名前付き」ワイルドカードの自動ロードをサポートします。名前付きワイルドカードが使用される場合、Drupalはワイルドカードと同じ名前の関数に接尾辞__load_を付けた関数。そのような関数が見つかると、URLの値の値で呼び出され、ローダー関数によって返されるものはすべて元の値の代わりにページコールバックに渡されます。Drupalには、ノードをロードするためのこのような関数がすでにあるため、 node_load() なので、ノードは自動ロードされ、ページコールバックに渡されます。

_function helloworld_menu() {
  $items['hello/%node'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
  );

  return $items;
}

function helloworld_page($node) {
  return t('Hello node (ID = !nid)', array('!nid' => $node->nid));
}
_

高度なオートローディング

場合によっては、複数の引数に基づいてより多くを自動ロードする必要があります。デフォルトでは名前付き引数のみがローダーに渡されるため、ローダーに渡す追加のロード引数を明示的にDrupalに伝える必要があります。たとえば、特定のリビジョンのノードの場合、node_load()にノードIDとリビジョンIDを渡す必要があります。これは、次のコードで実行できます。

_function helloworld_menu() {
  $items['hello/%node/revision/%'] = array(
    'page callback' => 'helloworld_page',
    'page arguments' => array(1),
    'load arguments' => array(3),
  );

  return $items;
}

function helloworld_page($node) {
  return t('Hello node (ID = !nid, revision ID = !rid)', array('!nid' => $node->nid, '!rid' => $node->vid));
}
_

許可

_'access callback' => TRUE,_は、上記の簡単な例をまったく表示可能にするために必要ですが、これまで何も制御できないため、理想的とは言えません。/helloにアクセスしようとするすべてのユーザーにアクセスが許可されます。ある程度の制御手段を提供する最も簡単な方法は、上記のページコールバックと同様に、アクセスコールバックを提供することです。次のコードでは引き続き誰でもアクセスできますが、アクセス時に呼び出される関数にロジックを移動する方法を示しているため、より複雑なロジックを使用できます。

_/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'access callback' => 'helloworld_access',
  );

  return $items;
}

/**
 * Access callback for /hello.
 */
function helloworld_access() {
  return TRUE;
}
_

カスタム関数を使用するとコードが不必要に複製されることが多いため、これは必ずしも最良の方法ではありません。ほとんどの場合、より良い方法は user_access() を使用することです。アクセスコールバックを一緒に使用して、アクセス引数を設定できます。次のコードを使用して、アクセスユーザープロファイル権限を持つユーザーがページを表示できるようにすることができます。

_/**
 * Implements hook_menu().
 */
function helloworld_menu() {
  $items['hello'] = array(
    'page callback' => 'helloworld_page',
    'access callback' => 'user_access',
    'access arguments' => array('access user profiles'),
  );

  return $items;
}
_

デフォルトのアクセスコールバックはuser_accessであるため、上記のコードのように省略できます。

より高度なトピック

公式の hook_menu() ドキュメントには、フックの最も複雑なユースケースに関する多くの情報が記載されています。

147
Letharion