老葛的Drupal培训班 http://zhupou.cn
当一个Web浏览器向Drupal发送一个请求时,它向Drupal传递了一个URL。通过这一信息,Drupal必须指出要运行哪段代码以及如何处理这一请求。这也就是通常所说的路由或者分发。Drupal截掉URL的基部分并使用后面的部分,后者被称之为Drupal路径。举例来说,如果URL是http://example.com/?q=node/3,则Drupal路径就为node/3。如果你使用了Drupal的简洁URL特性,那么在浏览器中的URL就是http://example.com/node/3,但是在你的web服务器中,在Drupal收到这个URL以前,web服务器已将其重写为http://example.com/?q=node/3;所以,对于Drupal来说,这两者是一样的。在前面的例子中,不管是否启用了简洁URL,其Drupal路径都是node/3。此方面的更多详细,可参看第一章中的“Web服务器的角色”。
老葛的Drupal培训班 Think in Drupal
通常采用的方式如下所示:Drupal请求所有启用的模块来提供一个菜单项数组,每个菜单项都包含了一个数组,其中以路径为键,里面还包含了路径的一些相关信息。一个模块必须提供的一段信息就是页面回调(page callback)。在这里,回调就是一个PHP函数的名称,当一个浏览器请求一个特定的路径时就会调用它。当一个请求到达时,Drupal将执行以下步骤:
老葛的Drupal培训班 Think in Drupal
通过在你的模块中使用菜单钩子来钩住这一流程。这样你就可以定义包含在menu_router表中的菜单项。让我们构建一个名为menufun.module的示例模块,通过它来学习菜单系统。我们将Drupal路径menufun映射到PHP函数menufun _hello()上。首先,我们需要一个名为menufun.info的文件,位于sites/all/modules/custom/menufun/menufun.info:
前面所写的hook_menu()实现,还是非常简单的。让我们在里面添加一些键,这样就和我们通常所用的差不多了。
有时,你可能希望向映射到该路径上的函数提供更多的信息。首先,路径中的其它部分将会自动传递过来。让我们修改一下我们的函数:
老葛的Drupal培训班 Think in Drupal
如果你没有特别指定的话,那么Drupal会假定你把页面回调放在了.module文件中。在Drupal6中,对于每个页面请求,为了尽可能的降低为其加载的代码总量,许多模块被拆分成了多个部分。如果回调函数不在当前的.module文件中的话,可以使用菜单项中的file键,来指定哪个文件包含了该函数。我们在第2章中编写注释模块的时候,就用到了file键。
如果你定义了file键,那么Drupal将会在你的模块目录下查找该文件。如果你的页面回调是由其它模块提供的话,也就是说该文件不在你的模块目录中,那么你需要告诉Drupal在查找该文件时所用的文件路径。使用file path键,就可以轻松的实现这一点了。我们在第2章的“定义你自己的管理部分”就用到了它。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
到目前为止,在前面的所有例子中,我们都简单的将菜单项的access callback键设置为了TRUE,这意味着所有的用户都可以访问我们的菜单。一般情况下,通过在模块中使用hook_perm()来定义权限,并使用一个函数来测试这些权限,从而实现对菜单的访问控制。这里所用的函数的名字定义在菜单项的access callback键中,它一般为user_access。让我们定义一个名为receive greeting的权限;如果用户没有哪个角色具有该权限的话,当他/她访问页面http://example.com/?q=menufun时,将会收到一个“拒绝访问”消息。
Drupal支持多语言,它使用t()函数来翻译字符串。所以你可能会想,菜单项中的title键应该是这样定义的:
如果没有在菜单项中定义标题回调的话,Drupal将默认使用t()函数。我们也可以明确地给出这个回调函数的名字,在title callback键中声明它就是了:
Drupal的翻译函数,可以接受一个字符串和一个用来替换的数组(更多关于t()函数的详细,参看第18章),例如:
到目前为止,我们在菜单项中所用的都是普通的Drupal路径名字,比如menufun 和menufun/farewell。但是Drupal还经常使用这样的路径,比如user/4/track或node/15/edit,在这些路径中,有一部分是动态的。现在,让我们来看看动态路径是如何工作的。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
在实际中,一个Drupal路径的一部分通常是用来查看或者修改一个对象的,比如一个节点对象或者一个用户对象。例如,路径node/%/edit用来编辑一个节点,而路径user/%则用来根据用户ID来查看用户的相关信息。让我们看一下后者的菜单项,你可以在modules/user/user.module中的hook_menu()实现中找到它。这个路径匹配的URL应该看起来是这样的http://example.com/?q=user/2375。在你的Drupal站点上点击查看“我的帐号”页面,就能看到这样的URL了。
如果需要向加载函数传递额外的参数,那么可以使用load arguments键来定义它们。下面是来自节点模块的例子:一个用来查看节点修订本的菜单项。在这里需要向加载函数,也就是node_load(),传递节点ID和修订本的ID。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
模块通过实现hook_menu_link_alter(),就可以在Drupal将一个菜单项保存到menu_link表时,来修改该链接了。下面是如何将“登出”菜单项的标题改为“Sign off”(“结束”)的。
当你在菜单钩子中添加一个菜单项时,经常用到的一个键就是type。如果你没有定义类型,那么将会使用默认类型MENU_NORMAL_ITEM。Drupal将根据你指定的类型来对菜单项进行不同的处理。每一个菜单项类型都有一系列的标记或者属性组成。表4-2列出了菜单项类型的标记。
老葛的Drupal培训班 Think in Drupal
在这一部分,我们给出了一些常见问题的典型解决办法,这些问题都是程序员使用菜单时会经常遇到的。
用Drupal的公认晦涩的菜单行话来说,一个显示为标签的回调被认为是一个本地任务,它的菜单类型为MENU_LOCAL_TASK或者MENU_DEFAULT_LOCAL_TASK.本地任务的标题应该是一个简短的动词,比如“添加”或者“列出”。它通常作用在一些对象上,比如节点,或者用户。你可以把一个本地任务想象为一个关于菜单项的语义声明,通常显示为一个标签(tab)----这和<strong>标签类似,后者也是一个语义声明,通常用来显示加粗的文本。
老葛的Drupal培训班 Think in Drupal
启用Drupal的菜单模块,就可以为管理员提供一个方便的用户界面,来定制已有的菜单,比如导航菜单或者一级/二级链接菜单,或者来添加新菜单。当位于includes/menu.inc中的menu_rebuild()函数运行时,表示菜单树的数据结构将被存储在数据库中。当你启用模块时,当你禁用模块时,或者当其它的一些能够影响菜单树结构的事情发生时,都会运行menu_rebuild()函数。数据将被保存到数据库的menu_router表中,而关于链接的信息则被保存到了menu_links表中。
现在你刚刚在你的模块中实现了菜单钩子,但是你的回调没有响应,你的菜单没有显示,或者就是不能正常工作,也就是出了问题。那么对于下面这些地方,你需要好好的检查一下:
老葛的Drupal培训班 Think in Drupal
当读完这一章后,你应该可以: