我应该如何实现hook_menu()?


103

实施的基本原则是hook_menu()什么?

我希望看到单个问题涵盖了基础知识,从而避免了一遍又一遍地回答相同但相似的问题。

Answers:


148

该信息对Drupal 6和7有效。在Drupal 8中,hook_menu()已被新的路由系统替换。下面我们hook_menu()通过三个简单的步骤来实现。

第一步

按照如何创建空模块中的说明创建空模块。在此处显示的代码中,假定该模块名为helloworld

第二步

将以下代码添加到模块文件中。

/**
 * 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!';
}

第三步

启用该模块,然后访问http://example.com/hello。(将example.com替换为服务器的域名。)
您应该看到消息“ Hello world!”。而已!您已经完成了工作hook_menu()。以下是有关的各种更高级的主题hook_menu()。特别是,您可能想阅读有关权限的信息,因为任何人都可以查看上面的页面。

争论

如果要将更多数据传递给页面回调,则可以使用页面参数来实现。页面参数应该是传递给页面回调的参数数组。如果使用整数作为参数,它将代表URL的一部分,从0开始,每个斜杠(/)递增一次。在以下示例中,这意味着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()文档提供了有关钩子最复杂用例的更多信息。


3
太棒了!仅出于完整性考虑,title所有从hook_menu()
Clive

1
我知道文档是这样说的,但是当我在D7中进行测试时,情况并非如此。我可以将其添加到我猜到的第一个示例中,但是我想将事情保持在绝对最低限度以使其尽可能容易。
Letharion

1
我想说的是,在页面上添加标题是您可以使用hook_menu()要做的绝对最低限度的工作之一,但这是您的帖子:P也许值得修复语法错误(代码示例2、4、5和6),这样人们就可以复制和粘贴
克莱夫(Clive)

1
恩,起初我很努力地运行代码,但是随着时间的流逝,我变得更加草率,开始复制粘贴。修复了语法错误,至少是我看到的那些错误;)好吧,您当然应该有一个标题,所以我确实在初始示例中添加了一个标题。
Letharion

1
如何使用hook_menu将php文件注册到路径?这是一个自定义的书面php文件,其中包含drupal引导程序,使用drupal会话变量并接受作为用户ID的参数。
ЕлинЙ.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.