Drupal专业开发指南 第4章 Drupal 菜单(menu)系统(3)

                                  译者:老葛

常用任务

在这一部分,我们展示了程序员使用菜单面临的常用问题的一些典型解决办法。

 

分配回调而不向菜单添加一个链接

 

你可能经常会遇到将一个URL映射到一个函数,同时不需要创建一个可见的菜单项的情况。你可以通过为你的菜单项指定类型为MENU_CALLBACK来完成这一任务,下面是从node.module中取出来的例子:

$items[] = array(

'path' => 'rss.xml',

'title' => t('RSS feed'),

'callback' => 'node_feed',

'access' => user_access('access content'),

'type' => MENU_CALLBACK

);

 

将菜单项展示为标签

Drupal的公认地晦涩的行话来说,一个展示为标签的回调被看作是一个本地任务(local task)并拥有类型MENU_LOCAL_TASK或者MENU_DEFAULT_LOCAL_TASK.本地任务的标题应该是一个简短的动词,比如“添加”或者“列出”。本地任务通常使用在特定的一些对象上,比如节点(node),用户(user),或者工作流(workflow).

  为了使标签可以被展示,本地任务必须有一个父菜单项。一个常用的实践是将一个回调指定到一个根路径比如milkshake上,然后将本地任务指定到扩展了这一路径的子路径,比如milkshake/prepare,milkshake/drink,等等。Drupal内建支持了两级可标签化的本地任务。

  标签的展示顺序由菜单项标题的值的字母顺序来决定。如果你不喜欢这种顺序,你可以为你的菜单项添加一个键weight(重量),然后它们将按重量排序。下例展示了使用默认本地任务的代码生成了两个主标签和两个次标签:

/**

* Implementation of hook_menu().

*/

function milkshake_menu($may_cache) {

$items = array();

if ($may_cache) {

$items[] = array(

'path' => 'milkshake',

'title' => t('Milkshake flavors'),

'callback' => 'milkshake_overview',

'type' => MENU_CALLBACK

);

$items[] = array(

'path' => 'milkshake/list',

'title' => t('List flavors'),

'type' => MENU_DEFAULT_LOCAL_TASK,

'access' => user_access('list flavors'),

'weight' => 0

);

$items[] = array(

'path' => 'milkshake/add',

'title' => t('Add flavor'),

'callback' => 'milkshake_add',

'type' => MENU_LOCAL_TASK,

'access' => user_access('add flavor'),

'weight' => 1

);

$items[] = array(

'path' => 'milkshake/list/fruity',

'title' => t('Fruity flavors'),

'callback' => 'milkshake_list',

'type' => MENU_LOCAL_TASK,

'access' => user_access('list flavors'),

);

$items[] = array(

'path' => 'milkshake/list/candy',

'title' => t('Candy flavors'),

'callback' => 'milkshake_list',

'type' => MENU_LOCAL_TASK,

'access' => user_access('list flavors'),

);

}

return $items;

}

function milkshake_overview() {

$output = t('The following flavors are available...');

// ... more code here

return $output;

}

 

4-7展示了在Drupal的Bluemaringe主题(theme)下的结果。

4-7 本地任务和可标签化的菜单

 

注意页面的标题来自于父回调,而不是来自默认本地任务。如果你想使用一个不同的标题,你可以使用drupal_set_title()来设置它。

 

手工修改已存在的菜单

当你在你的模块中实现菜单钩子的时候,你完全可以为其他模块的路径添加入口,或者甚至可以覆盖它们。这通常可以使用menu.module提供的方便的web接口来完成,menu.module是Drupal自带的一部分,但是你可能也有需要使用编程来完成的情况。

 

包裹指向菜单项的调用

例如,devel.module(如果你想做一些严谨的Drupal开发的话,你可能会用到)拥有一个菜单项用来清楚Drupal的缓存表。现在让我们包裹这一函数从而首先调用我们的函数。首先,我们通过在我们的菜单钩子内部声明具有相同路径的菜单项来覆写devel.module的菜单项。

/**

* Implementation of hook_menu().

*/

function mymodule_menu($may_cache) {

$items = array();

if (!$may_cache && module_exist('devel')) {

 // Make sure devel.module is enabled.

$items[] = array(

'path' => 'devel/cache/clear', // Same path that devel.module uses.

'title' => t('Wrap cache clear'),

'callback' => 'mymodule_clear_cache',

'type' => MENU_CALLBACK,

'access' => user_access('access devel information')

// Same as devel.module.

);

}

}

function mymodule_clear_cache() {

drupal_set_message('We got called first!');

// Wrap the devel function normally called.

devel_cache_clear();

}

现在当我们进入http://example.com/?q=devel/cache/clear,我们的模块将先被调用,然后它将调用原本应该调用的函数。下面是执行结果:

---------------------------------------------------

We got called first!

Cache cleared.

-------------------------------------------

当你想修改Drupal的默认行为而不改变底层代码,这是一个非常有用的技术。

 

-------------------------------------------------------------------------------注意:由于我们模块的菜单钩子调用位于devel.module的之后,所以在本部分展示的技术才正常工作。模块被调用的顺序由它们位于表system中的重量决定。当覆写路径时,当$may_cache为FALSE时通常容易添加你的菜单项,这是因为这些菜单项在最后时刻被添加,而此时大多数路径都已到位(因此可被覆写)。

 

删除已存在的菜单

 

使用在“包裹指向菜单项的调用”一节中所展示的方式,你可以通过覆写它们的路径来删除已存在的菜单项。比如由于一些原因,你想删除菜单项”create content”以及添加内容的能力:

$items[] = array(

'path' => 'node/add',

'title' => t('This should not show up'),

'callback' => 'drupal_not_found',

'type' => MENU_CALLBACK

);

注意:在这种情况下,你不能在保留创建特定内容类型的同时删除’create content’页面,这是因为他们是同一概念:这一菜单项所映射函数node_add,它使用了Drupal内建的根据路径来传递参数,所以node/add和node/add/story调用了同一个函数。在后一种情况,’stary’作为一个参数被传递。一个保留创建内容类型的可选的方式是使用menu.module的接口来禁用菜单项’create content’,这将使低于’create content’的菜单项可被访问。

 

向已有的菜单中添加菜单项

你可以通过使用一个聪明的路径来将你的菜单项添加到已存在的菜单中去。例如,假如你感觉非常暴躁,想为用户管理接口添加一个标签用来删除所有的用户。通过检查user.module中的菜单钩子,你决定把路径admin/user作为你的基础路径。下面是你从eradicateusers.

Module中返回的菜单项:

$items[] = array(

'path' => 'admin/user/eradicate',

'title' => t('Eradicate all users'),

'callback' => 'mymodule_eradicate_users',

'type' => MENU_LOCAL_TASK,

'access' => user_access('eradicate users')

);

这将菜单项作为本地任务来添加,如图4-8所示:

4-8 向另一模块的菜单添加本地任务

 

如果你想在管理菜单区块中展示这一菜单项,那么你需要使用类型MENU_NORMAL_ITEM来代替MENU_LOCAL_TASK。如果你想在两个地方同时显示,你需要这样:

'type' => MENU_NORMAL_ITEM | MENU_LOCAL_TASK

这样菜单项就同时拥有了两个菜单项类型属性。

 

使用menu.module

当位于includes/menu.inc中的函数menu_rebuild运行时,代表着菜单树的数据结构将被镜像到数据库中。它发生在你启用或者禁用模块的时候,或者其他的影响菜单树的组成的一些事件时。数据被保存到了数据库表menu中,该表的结构是这样的(来自于modules/system/system.install):

CREATE TABLE {menu} (

mid int unsigned NOT NULL default '0',

pid int unsigned NOT NULL default '0',

path varchar(255) NOT NULL default '',

title varchar(255) NOT NULL default '',

description varchar(255) NOT NULL default '',

weight tinyint NOT NULL default '0',

type int unsigned NOT NULL default '0',

PRIMARY KEY (mid)

) /*!40100 DEFAULT CHARACTER SET UTF8 */

注意访问信息没有保存到数据库中。在为每次请求构建菜单树的流程中,Drupal首先根据从模块的菜单钩子中收到的信息来构造树,然后使用从数据库中取出来的信息来覆盖这些信息。这一行为使得你可以使用menu.module来改变菜单树的属性:父亲,路径,标题以及描述---你没有改变底层的菜单树,实际上,实际上创建了覆盖在它上面的数据。

注意 菜单项类型,比如MENU_CALLBACK 或者 DEFAULT_LOCAL_TASK,在数据库中是以其数字代码来表示的。

Menu.module也为节点表单添加了一节,用来将当前发布的内容作为一个菜单项使用。

 

常见错误

现在你刚刚在你的模块中实现了菜单钩子,但是你的回调没有被触发,你的菜单没有被显示,或者其他的不能正常工作的事情。下面是一些通常需要检查的地方:

你为一个函数设置的键access的返回是否为FALSE?

在你的菜单钩子的结尾你是不是忘记了添加rerurn $items?

你清空了你的菜单缓存了吗?

如果你使用表达式来指定键path,那么这个表达式是不是解析为一个合法的路径?

如果你通过指定类型为MENU_LOCAL_TASK从而将菜单项展示为标签的话,你制定了一个带有回调函数的父菜单项了吗?

如果你使用了本地任务,那么在一个页面你至少拥有两个标签了吗(为了展现这是必须的)?

如果你想修改/覆盖/删除一个存在的路径时,你能确保你的模块中菜单钩子的调用位于定义你所覆写路径的菜单钩子之后么?当$may_cache为FALSE时试着返回你的菜单项,以使你的菜单项定义位于流程的后面。

 

小结

当读完这一章后,你应该可以:

URL映射到函数上

为菜单树添加入口

创建带有映射到函数上的标签(本地任务)的页面

理解访问控制是如何工作的

通过代码来添加,修改,删除已存在的菜单项

 

-------------------------------------------------------------------------------注意:更多的阅读,可参看menu.inc的注释,它值得一读。当然,也可参看http://api.

drupal.org/api/5/group/menu。

-------------------------------------------------------------------------------

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值