作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
通过了解Drupal自身的文件夹结构,我们对Drupal有了初步的认识。我们还需要对Drupal中的常用概念,或者说专有术语,有更好的界定。这能够帮助我们更好的学习使用Drupal。常用的术语有模块、钩子、主题、节点、菜单、区块、字段、实体等等。Drupal相关术语不仅仅是这里所列的这么几个,还有更多的相关术语。有兴趣的读者,可以参看http://drupal.org/node/19828。
作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
我们浏览Drupal核心文件夹的modules目录,就会发现这里包含了许多子文件夹,正如前文中所述的那样,每个下面都有一个模块。而每一个模块,都实
现了特定的功能。通过模块的安装与卸载,我们就可以为Drupal站点添加或者删除特定功能。Drupal作为一个框架,其最大的一个优势,就是完全的模
块化。当我们建设一个站点时,我们只需要根据需求组装相应的模块就可以了;当然,这里所说的只是大多数时候。
Drupal7的模块我们大致可以分为4类:核心必选模块、核心可选模块、第3方模块、自定义的模块。核心必选模块,位于modules目录,有字段(Field)、字段SQL存储(Field SQL storage) 、文本字段(Text)、过滤器(Filter)、节点(Node)、系统(System)、用户(User),这里需要注意的是modules/field目录下,包含了多个模块,其中3个模块是核心必选模块。modules目录中,除去必选模块以外,剩余的就是核心可选模块,核心可选模块的info文件中,不包含 “required = TRUE”
这句话。第3方模块,就是由Drupal的社区成员,贡献到drupal.org上的模块,目前(2011年5月),drupal.org上有7000+
多个第3方模块,而且这个数量正在稳步增加。自定义模块,就是为了实现网站的特殊需求,程序员自己开发的模块,通常没有上传到drupal.org上。
Drupal
本身是不向下兼容的,每个主版本之间,差别往往很大。随着主版本的升级,一些模块,原来是Drupal核心可选模块,后来变成了第3方模块,比如
drupal.module;有一些模块,原来是核心必选模块,后来变成了核心可选模块,比如block.module;也有一些模块,原来是第3方模
块,后来变成了核心可选或者必选模块,比如simpletest,cck。如果你自己定义的模块,贡献到了drupal.org上,那么这个模块就变成了第3方模块。Drupal的模块,就像大自然一样,是在不断演化的,而且也存在优胜劣汰这样的自然法则。
作者:老 葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
谈到模块,就不得不提到钩子这个概念。我有时也喜欢把钩子称作钩子机制,我们可以把钩子看做Drupal的内部事件。有时也可以钩子看作是特殊的回调函数。
模块就是通过钩子,与Drupal核心系统无缝整合在一起了。钩子是一个很抽象的概念,我们通过代码来理解一下钩子机制。
function module_invoke_all() {
$args = func_get_args();
$hook = $args[0];
unset($args[0]);
$return = array();
foreach (module_implements($hook) as $module) {
$function = $module . '_' . $hook;
if (function_exists($function)) {
$result = call_user_func_array($function, $args);
if (isset($result) && is_array($result)) {
$return = array_merge_recursive($return, $result);
}
elseif (isset($result)) {
$return[] = $result;
}
}
}
return $return;
}
代码参考地址:
http://api.drupal.org/api/drupal/includes--module.inc/function/module_invoke_all。
函数module_invoke_all是理解钩子的关键,而这里面,foreach循环中,函数module_implements是理解钩子的又一关键,它用来获取所有实现了钩子$hook的模块。而在这个循环体代码里面,第一句给出了钩子的命名规范。模块在实现钩子的时候,必须采用“模块名_钩子名”形式。其余代码的含义,就是如果这个具体的钩子函数存在(function_exists($function)),那么就调用这个钩子函数(call_user_func_array($function, $args))。
Drupal中的钩子大致可以分为3类,采用module_invoke_all调用的钩子是一类,也是最常见的;采用module_invoke调用的钩子是一类,这种钩子在Drupal核心中经常出现;还有一个就是主题钩子,比如theme_item_list,这里的item_list有时也被称为主题钩子。
上面提到了module_invoke,让我们看一下它的代码:
<?php
function module_invoke() {
$args = func_get_args();
$module = $args[0];
$hook = $args[1];
unset($args[0], $args[1]);
if (module_hook($module, $hook)) {
return call_user_func_array($module . '_' . $hook, $args);
}
}
?>
在这个函数中,call_user_func_array函数只调用了一次,而在前面的module_invoke_all函数的代码中,它被循环调用了多次。这就是两类钩子之间的区别。
有关钩子的更多信息,可以参看api.drupal.org上的在线文档,http://api.drupal.org/api/drupal/includes--module.inc/group/hooks/7。此外,如果一个模块对外提供了钩子,那么在这个模块的文件夹下面,通常会有一个modulename.api.php这样的文件,里面包含了钩子的具体说明,比如在用户模块下面,就有一个这样的文件user.api.php,里面包含了用户模块对外提供的所有钩子。
作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
我们在前面的Drupal文件结构的分析中,提到过themes文件夹,这里面放置的就是Drupal核心自带的主题。Drupal中的主题主要负责把原始
数据转化为格式化的HTML输出。通常一个Drupal主题,由info文件、模板文件、template.php、CSS文件、JS文件、图片构成。我
们打开一个Drupal主题,比如garland,就会看到在模板文件中,里面包含了html代码片断和PHP变量。主题对外观的控制,就是通过这样的模
板文件和主题函数实现的。除了Drupal核心自带的这些主题外,Drupal.org还有很多第3方的主题可用,比较常用的有Zen、fusion、tao等等(http://drupal.org/project/themes)。
前面所说的主题,指的是具体的主题。在Drupal中,主题系统,所包含的含义就会更加广泛一些。除了上面的所说的具体的主题外,它还包含Drupal的主
题机制,包含在Drupal核心模块中、第3方模块中的各种模板文件和主题函数,以及Drupal的主题覆写。Drupal通过自己的主题系统,将逻辑层
与表现层作了分离;将逻辑与外观分离,这也是Drupal的最佳实践之一。在includes文件夹下,有一个theme.inc文件,里面的代码包含了Drupal的主题覆写机制,也包含了各种预处理函数、处理函数、还有常用的主题函数,阅读这些代码,有助于大家熟悉Drupal的主题系统。
Drupal
通过主题系统来控制网站的外观,我们可以通过定制自己的主题,来实现自己的具体外观。在定制主题的过程中,对于Drupal核心或者第3方模块的默认输
出,我们通常有两种定制方式:一种就是使用CSS的覆写机制,重新定义CSS规则,保留原有的markup输出;这种方式的优点是,简单方便,缺点就是有
大量的垃圾html输出,在后续过程中,不易复用。另一种方式就是在自己的主题中通过覆写模板与主题函数实现,这样可以完全使用自己的markup输出、
使用自己的CSS规则;这种方式的优点是html代码干净、浏览器兼容性比较好,易于复用,缺点就是比较复杂,前期成本高。
作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
区块一般指的是放置在模板中的边栏、页首、或者页尾中,主内容外的内容片断。通过区块管理界面,可以启用或者禁用这些信息。举例来说,我们通常在站点的页脚
处,显示的“版权信息”,就可以处理成区块;常常显示在站点边栏的“热门内容”,每个站点的主导航链接,都可以处理成区块;比如“用户登录”和“我的帐
号”功能,可以结合在一起,处理成区块显示,这样匿名用户看到的就是“用户登录”表单,而注册用户看到的就是“我的帐号”链接。
我们可以控制单个区块的显示位置,比如显示在特定页面,显示给特定角色的用户,显示在特定节点类型的页面中,显示在特定的主题区域下。区块通常是放在区域中的,而区域的定义则位于主题的info文件中。
作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
在Drupal中,菜单有两层含义:一种是处理请求的路由系统,它会将页面请求所提供的URL映射到Drupal内部的回调函数上,这是Drupal程序员所关心的;另一种就是页面上的导航,它负责组织站点的内容关系。
菜单具有层级的树形结构,一个菜单项下面可以有多个子菜单项,子菜单项下面又可以包含菜单项。需要注意的是Drupal菜单的层级,最多可以有9级,超过了9级,系统就不能正常工作了,而在实际的站点导航中,很难遇到包含9级的导航。
作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
对于你站点的每位访问者,无论他拥有你站点的一个账号,或者是匿名访问,在Drupal中,都会将其处理成用户。每个用户都具有一个ID,注册用户还具有用
户名、电子邮件等信息。用户本身是实体的一个具体实现,所以我们可以为用户添加更多的字段;此外,使用profile2模块,就可以定义不同的
profile类型,并将其与用户关联起来。
ID为0的用户为匿名用户,我们可以为匿名用户启用缓存。ID为1的用户,是Drupal站点的超级管理员,具有站点操作的各种权限。Drupal通过角色来
管理不同注册用户的权限。一个角色就代表着一组权限的集合。Drupal自带了3中角色:匿名用户、注册用户、管理员。根据站点的需求,可以添加更多的角
色,比如“站内编辑”。
作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com
字段和实体,是Drupal7中新引入的两个概念。在Drupal7以前,人们使用CCK模块来扩展节点类型,为节点类型添加各种字段。这种方式渐渐的演变成为了主流方式,并最终在Drupal7中进入了Drupal内核。
以
前,人们尝试着,将所有的内容都统一到节点上去,比如区块,评论,分类,用户profile,都存在相应的第3方模块将其实现为相应的节点类型。在
Drupal7中,核心开发者将这方面的努力做了进一步的抽象,把核心中的节点、分类、评论、用户都抽象成为了实体。实体具有相同的增删改查,可以为实体
添加更多的字段。
第3方模块,Entity API正在成为Drupal7中的CCK模块,基于这个模块,我们可以方便的定义出来新的实体类型,比如在Ubercart和Commerce模块中,就基于这个模块将订单实现成为了一种新的实体类型。