Hook_menu Drupal 7 通过模块创建页面
在上一课中,我们学习了如何通过 Drupal API 从数据库中输出信息,具体来说使用了钩子 hook_block_info() 和 hook_block_view()。在本课中,我们将学习如何输出页面,也就是使用钩子 hook_menu,将页面连接到 Drupal 的其他部分,如菜单、翻译模块、模板等。
我们从简单的开始,创建一个页面,用于输出最近 10 条新闻的标题和描述。这样就能得到一个简短的新闻列表。我们将使用 hook_menu()。以下是它的说明,之后我们会进行实际使用。
hook_menu()
定义菜单项并返回页面。
当模块中调用此钩子时,它会注册路径,并指定 Drupal 处理的顺序。路径既可以仅用于处理请求,也可以被添加到菜单中,例如导航菜单。路径及其相关信息称为 menu router item。此钩子只在特定情况下被调用(例如启用模块时),其结果会被缓存到数据库中。因此,在修改模块中的钩子后,通常需要清除缓存。
hook_menu() 返回一个关联数组,其中的键表示路径,值是另一个包含该路径属性的关联数组(这些属性在下面说明)。
每个路径的定义包括返回页面的回调函数,当该路径被请求时会调用此函数。如果没有其他路径与该 URL 匹配,钩子将返回页面。例如,您的模块可以注册路径 “abc/def”。
<?php function mymodule_menu() { $items['abc/def'] = array( 'page callback' => 'mymodule_abc_view', ); return $items; } function mymodule_abc_view($ghi = 0, $jkl = '') { // ... } ?>
当请求路径 “abc/def” 且 URL 中没有更多内容时,不会传递额外参数。而当请求路径 “abc/def/1/Omsk” 时,页面会接收参数 “1” 和 “Omsk”。这在我们创建页面模板时非常有用。
路径中的附加参数可以定义为一个关联数组。参数列表可以包含简单的数值或复杂的值。当数字用于路径时,并且调用了回调函数(返回页面的函数),对应模块路径将被数字替换。例如,可以使用 arg(0) 调用第一个参数,arg(1) 调用第二个参数,依此类推。
<?php function mymodule_menu() { $items['abc/def'] = array( 'page callback' => 'mymodule_abc_view', 'page arguments' => array(1, 'foo'), ); return $items; } ?>
当访问路径 “abc/def” 时,返回的页面将接收 “def” 作为第一个参数,固定的 “foo” 作为第二个参数。钩子的完整说明可在此页面查看:http://api.drupal.org/api/drupal/modules--system--system.api.php/functio...
现在我们来创建一个简单的页面:
function sitemade_menu(){ $items = array(); // 初始化菜单项数组 $items['page_example'] = array( // 添加路径 'page_example' 的页面 'title' => '页面示例', // 页面标题 'description' => '普通页面', // 页面描述 'page callback' => '_page_example', // 返回页面内容的函数 'access callback' => TRUE, // 允许所有人访问该页面 'expanded' => TRUE, ); return $items; // 返回页面列表 } function _page_example($content = NULL) { $content = ''; // 初始化内容为空 $query = db_select('node_revision', 'n'); // 选择 node_revision 表,其中存储节点的修订版本 $query->innerJoin('field_revision_body', 'b', 'b.revision_id = n.vid'); // 关联 field_revision_body 表(包含正文) $query->innerJoin('node', 'd', 'n.nid=d.nid'); // 关联 node 表(包含节点标题) $query->fields('n', array('title'), array('nid'), array('vid')); // 选择字段 $query->fields('b', array('body_value')); $query->condition('d.type', 'news'); // 限制为内容类型 news $query->orderBy('n.timestamp', 'DESC'); // 按时间降序排列 $query->range(0, 10); // 仅选择最近 10 条 $result = $query->execute(); // 执行数据库查询 while($nodes = $result->fetch()){ // 处理结果 $content .= '<h3>' . $nodes->title . '</h3>'; // 输出标题 $content .= $nodes->body_value; // 输出正文 } return $content; // 返回内容 }
我们还可以使用钩子属性 type,将页面放入不同的菜单中,例如后台菜单或主菜单(main menu)。
让我们来试试:
function sitemade_menu(){ $items = array(); // 初始化菜单项数组 $items['page_example'] = array( // 添加路径 'page_example' 的页面 'title' => '页面示例', // 页面标题 'description' => '普通页面', // 页面描述 'page callback' => '_page_example', // 返回页面内容的函数 'access callback' => TRUE, // 允许所有人访问该页面 'expanded' => TRUE, 'type' => MENU_NORMAL_ITEM, 'menu_name' => 'main-menu', ); return $items; // 返回页面列表 }
刷新缓存后,该页面的链接就会出现在菜单中。
除了普通菜单项外,还可以将页面显示在 Drupal 管理后台中:
function sitemade_menu(){ $items = array(); // 初始化菜单项数组 $items['admin/config/content/page_example'] = array( // 添加路径 'admin/config/content/page_example' 的页面 'title' => '页面示例', // 页面标题 'description' => '普通页面', // 页面描述 'page callback' => '_page_example', // 返回页面内容的函数 'access arguments' => array('administer site configuration'), // 仅限管理员访问 ); return $items; // 返回页面列表 }
现在,该页面仅对管理员可见,并且可以在后台菜单中找到链接:
该链接会出现在后台菜单中,因为 Drupal 会自动在路径 admin/config/content/* 下添加链接。如果我们将路径设置为 admin/config/people/*,那么链接会出现在“用户”部分(* 可替换为自定义名称,例如本例中的 page_example)。
现在我们已经学会了创建区块和页面,我认为这些是输出内容时最常用的钩子,它们将在您的模块中经常使用。
下一课我们将学习 hook_perm(),用于为用户创建新的访问权限。