太多了,Drupal的手册拖动起来不灵活,希望这份译文能够帮助更多的人学会Drupal,尽管开始的时候,希望拿它卖钱的,结果非常惨淡,现在免费提供出来,希望能给需要的人提供帮助.
错误很多,希望大家共同改进,不过比第一版的相比,错误的数量应该降低了一个数量级,就像我说的,第一版的译文是错误千出,第2版是错误百出,限于译者的精力有限,就不一一改进了.
我也买过看过很多翻译的技术书籍,我相信,第2版的译文好于市面上的80%的技术书籍的译文,第一版翻译完,我从来不看中文的,因为我觉得错误太多了.第2版的中文,我经常拿来翻的.
不多说了,加速连载中.
分类是对事物的划分归类。Drupal自带了一个分类模块,它允许你对节点(也就是主要的“事物”)进行分类。在本章中,你将看到Drupal支持的不同种类的分类。你还将看到数据是如何存储的,如何在你自己的模块中查询分类数据库表。最后,你将会看到,当分类改变时,你的模块如何收到相关通知,并且我们将介绍一些常用的分类相关的任务。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
下面是一些常见任务, 在你使用分类时可能会碰到。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
Taxonomy: 分类,分类系统, 分类法
Hierarchy:层级
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
模块常常需要进行昂贵的数据查询或者调用远程web服务。对于这些耗费资源的操作,不需要每次都重复进行一次,模块可以将它们的数据缓存到Drupal中为缓存保留的数据库表中,或者模块也可以创建一个新的数据库表,并将缓存数据存储在那里。当下次用到这些数据时,通过一个简单的查询就可以快速的将其取回。你将在本章的后面看到,Drupal的缓存后端是可插拔的,所以尽管这里所指的是数据库表,实际的后端也可以采用其它的存储,比如直接使用文件或者一个基于内存的缓存。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
Drupal将大多数的管理设置存储在variables表中,并将该表的所有数据缓存到cache表中,以加快查找配置数据的速度。这类变量的例子,包括你站点的名称、评论和用户的设置、以及files目录的位置。所有的这些变量都被缓存到cache表的一行记录当中了,这样在需要每个变量时,就可以快速的将其取回,而不是每次都进行一次数据库查询。它们被存储为一个PHP数组,所以缓存值将被序列化从而保留它的结构。如果一个变量使用variable_set()和variable_get()作为设置器(setter)和读取器(getter)函数,那么将以这种方式来存储和缓存它。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
许多Drupal函数使用一个静态变量来缓存数据。在一个HTTP请求的生命周期内,在第2次调用它时,将会立即返回数据。下面是一个来自于节点模块的例子:
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
这样当单个浏览器请求网站页面时,PHP就可以对其进行追踪了。32位字符串ID,也就是会话ID,它有两种功能,首先它可以作为键来读取Drupal存储的会话信息,另外它允许Drupal将会话与单独的用户关联起来。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
你可以在安装Drupal时选择一个英语以外的语言,也可以在安装后添加一个语言翻译。我们将讲解这两种可能。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
到目前为止,我们所讲的主要是Drupal用户界面的翻译。但是,内容该怎么办呢?一旦判定了当前语言设置,那么用户极有可能想查看该语言下的站点内容!现在,让我们学习一下内容翻译的工作原理。
老葛的Drupal培训班 Think in Drupal
能够使用多个语言创建内容固然不错。然而,大多数的站点,都不会有一篇内容使用英语,另外一篇内容使用法语,两者没有任何关系。相反,法语内容通常是英语内容的一个翻译(或者反之亦然)。当把内容类型的“多语言支持”设为“已启用,带有翻译”(参看图18-24)时,那就变成可能的了。它涉及到以下步骤:
老葛的Drupal培训班 Think in Drupal
有时,想知道是由Drupal中的哪一部分负责某一本地化或翻译功能的,这是非常困难的。表18-1给出了这些文件和它们的职责。
文件
|
职责
|
includes/bootstrap.inc
|
运行DRUPAL_BOOTSTRAP_LANGUAGE阶段,判定当前语言
|
includes/language.inc
|
如果启用了多语言,那么它将被引导指令包含进来。可用来选择语言和将内部URL重写为特定于语言的
|
includes/common.inc
|
t()所在的地方,另外还有drupal_add_css(),后者支持从右到左的语言。
|
includes/locale.inc
|
包含了用户界面和管理语言翻译的函数。
|
modules/locale/locale.module
|
当安装或启用模块/主题时,它用来提供字符串替换和翻译导入。它向路经、节点、节点类型的表单中添加语言设置界面。
|
modules/translation/translation.module
|
管理源节点和对应的翻译
|
modules/translation/translation.admin.inc
|
当点击翻译标签时,它提供翻译概览页面(参看图18-31)。
|
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
几乎每天我们都可以看到关于安全漏洞的头条消息,这种或者那种软件出现了漏洞。对于每个严谨的开发者来讲,将恶意用户拒之门外就是头等大事。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
当在一个像Drupal这样的系统中处理文本时,由于用户输入将会作为站点的一部分展示出来,所以如果将用户输入看作一个带有类型的变量,那么就能帮我们很好的理解这个系统。如果你使用过强类型语言写过程序,比如JAVA,那么你将熟悉强类型变量。例如,在Java中,一个整数就是一个整数。在PHP(弱类型语言)中,使用PHP的自动类型转换,根据上下文,你既可以把整数看作字符串,也可以看作整数。但是优秀的PHP程序员都会仔细的考虑类型,并恰到好处的利用自动类型转换。同样,尽管是通过用户输入得到的,节点提交表单中的“Body”(主体)字段,也可以作为一个文本进行处理,如果我们把它看作具有特定类型的文本,那么就会更好的理解的它的本质。用户输入的是纯文本么?用户输入的文本中是否带有HTML标签,如果带有的话是否将它们也一同显示出来?如果带有HTML标签的话,这些标签中是否允许带有恶意的标签,比如JavaScript,它可以将你的页面替换成一个手机铃声的广告?在展示给用户的页面中,采用HTML格式;用户输入是各种文本格式类型的变体,在展示它们以前,必须安全的将其转化为HTML。如果我们使用这种方式来考虑用户输入的话,这能够帮助我们理解Drupal的文本转换功能的工作原理。文本输入的常见类型,还有将文本转化为另一种格式的函数,如表20-1所示。
老葛的Drupal培训班 Think in Drupal
Plain text(纯文本)
老葛的Drupal培训班 Think in Drupal
当你对你用到的文本不信任,并且你不想在文本中有任何markup(标识字体)时,那么就可以使用check_plain()。
跨站点脚本(XSS)是攻击网站的一种常用方式,攻击者可以向一个网页插入他/她自己的代码,然后使用这些代码进行各种破坏活动。
有时你想让你的模块为后台管理页面生成HTML。由于我们对后台管理页面进行了访问控制,所以我们可以假定这些可以访问后台管理页面的用户比普通用户更可信。你可以为后台管理页面建立一个特定的过滤器并使用过滤器系统,但是这有点麻烦。因此,Drupal提供了函数filter_xss_admin()。它使用一组更加自由的可用标签列表,简单的对filter_xss()做了封装,除了<script> 和 <style>标签以外,它包含了所有的其它标签。使用它的一个例子是在主题中展示站点的宗旨(mission):
模块常常处理用户提交的URLs并显示它们。我们需要一些机制来确保用户提供的值确实是一个合法的URL。Drupal提供了函数check_url(),它实际上是仅仅对filter_xss_bad_protocol()做了封装。它通过检查来确保URL中的协议是该Drupal站点所允许的协议(参看“使用filter_xss()阻止跨站点脚本攻击”部分的第5步),并使用check_plain()来处理URL。
攻击网站的一个常见方式称为SQL注入。让我们看一个没有考虑安全性的程序员编写的模块。他仅仅想用一种简单的方式,来列出特定类型节点的所有标题:
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
如果在你的SQL中,有多个只有在运行时才能确定的变量,这并不妨碍让你使用占位符。你将需要使用占位符比如'%s' 或者 %d,通过编程来创建你的SQL,接着你需要传递一组值来填充这些占位符。如果你自己直接调用db_escape_string(),那么你就做错了。下面的例子展示了占位符的使用,这里假定我们想取出,匹配特定节点类型的已发布节点的ID和标题:
当你编写自己的模块时,需要注意的另一个方面是“access arguments”键,你会在菜单钩子定义中的每个菜单项中用到它。在前面我们用来说明不安全代码的例子中,我们使用了下面的access参数:
老葛的Drupal培训班 Think in Drupal
在处理文件和文件路径时,Drupal面对的危险和其它web应用是一样的。
如果一个启用的模块允许文件上传,那么文件就应该放到一个特定的目录下,并通过代码来强制访问。
不要相信用户提供的文件名或者文件路径!当你编写一个模块时,你的代码期望能够收到somefile.txt,实际上它可能得到了其它文件,比如
老葛的Drupal培训班 Think in Drupal
并不是Drupal自带的所有文件,都是生产站点所必须的.例如,如果在一个生产站点上,有CHANGELOG.txt文件可用的话,那么互联网上的任何人都可以查看你的Drupal版本了(当然,一些高手黑客可用多种方式来探测你的网站是不是使用的Drupal;参看http://www.lullabot.com/articles/is-site-running-drupal)。表20-3列出了Drupal安装后,为了正常工作所需要的文件和目录;其它的都可以从生产站点上删除(不过要保留一份备份哦!)当然,你也可以采用另外一种方式,那就是限制对这些文件的读权限。
在Drupal中,有些周期性的调度任务是必须执行的,比如清理日志文件,更新统计等等。对于Unix系统,你可以使用cron任务,对于Windows,你可以使用任务调度器,来运行cron.php文件。可以通过命令行或者通过web服务器来运行该文件。在这个文件的执行中,它简单的做了一个完整的Drupal引导指令,并调用includes/common.inc中的drupal_cron_run()函数。这个函数使用信号量来阻止cron的重负运行(一个cron周期运行多次);尽管如此,特别小心的用户可能还想阻止任何用户访问http://example.com/cron.php。你可以通过在Drupal根目录下的.htaccess文件中添加以下代码,来实现这一点:
SSL支持
老葛的Drupal培训班 Think in Drupal
使用表单API的一个好处就是,它为你处理了许多安全性问题。例如,Drupal通过检查来保证,用户从下拉选择框中选择的值,确实是Drupal生成的选项中的一个。表单API使用了一系列的事件集,比如表单构建、验证、和执行。在验证阶段前面,你不能够使用用户输入,因为用户输入还没有被验证。例如,如果你使用的值来自$_POST,那么你就不能确保用户是否操作了该值。还有就是,使用#value元素在表单中传递信息,尽可能的使用它来代替隐藏域,因为恶意用户可以操作隐藏域,但是访问不了#value元素。
获取一个Drupal网站密码的最简单的方式是,打个电话给这个网站的秘书,这样说“你好,我是Joe。<一对客套话>。我是给你们的网站提供技术支持的,在技术支持中,我们遇到了问题。需要使用用户名和密码进行登录,你的用户名和密码是多少?”不幸的是,很多人会轻易的将这一私密信息告诉他人。尽管技术对此有所帮助,但是对于这种攻击,最好的办法还是对用户进行教育。
老葛的Drupal培训班 Think in Drupal
千万不要使用它。使用PHP函数eval(),你可能觉得它是进行元编程的极好的方式,或者想用它来减少多行代码,这个函数将一个字符串文本作为输入,并使用PHP解释器对其求值。这完全是一个错误。如果有任何方式允许一个用户使用eval()来操作输入的话,那么你就会将PHP解释器的威力暴露给用户。这距离泄露私密数据的时间也不会太长了,因为用户就可能使用这一方式来获取你的数据库中的用户名和密码。
读完本章后,你应该知道:
老葛的Drupal培训班 Think in Drupal
在本章中,我们给出了许多的代码小提示和最佳实践,它能帮你成长为一个合格的Drupal开发者,并帮你摆脱电脑的折磨。我们首先学习Drupal的编码标准,接着学习如何为模块创建文档以方便其它开发者理解代码。还介绍了如何在Drupal的核心中快速的查找东西,介绍了版本控制,并详细的说明了如何维护一个第3方模块,最后我们讨论了如何调试和剖析代码。
老葛的Drupal培训班 Think in Drupal
老葛的Drupal培训班 Think in Drupal
标签就是一个特定分支在某个时间的快照。在Drupal世界中,标签用来标记beta,bug-fix,和安全发布。这样就得到了更小的版本,比如Drupal 6.1 和 6.2。规范的标签名有DRUPAL-4-7-1,DRUPAL-4-7-2, DRUPAL-5-7, DRUPAL-6-0, DRUPAL-6-1, 和DRUPAL-6-2(再次注意,在Drupal5中,命名规范改变了)。Drupal核心使用的标签名字的完整列表,可参看http://drupal.org/node/93997。
Drupal遵循大多数的Doxygen注释样式指南。所有的文档区块必须使用下面的语法:
Devel模块是个大杂烩,里面包含了许多实用功能,开发者可用它来调试和检查代码的各种细节。
老葛的Drupal培训班 Think in Drupal
函数文档应该使用下面的语法:
我们将学习如何在命令行中使用CVS。现在有许多图形化的CVS客户端,一旦学会了这些基本的命令以后,你应该能够很容易的实用这些图形化的CVS客户端了。Windows用户通过安装Cygwin环境(参看http://drupal.org/node/150036),就可以使用CVS命令行了。如果你使用的是CVS命令行客户端,那么这会便于你与社区中的其它开发者交流CVS问题。
如果你想将你的站点更新到最新的Drupal代码上,甚至更新到下一个新版本上,那么你可以使用cvs update命令来实现这一点。首先测试一下cvs update命令将做出哪些变更,运行下面的命令:
egrep是一个Unix命令,用来在文件中搜索匹配给定正则表达式的位置。不,它不是一个鸟儿(那是egret(白鹭))。如果你是一个Windows用户,并想学习一下这些例子,你可以先安装一个预编译的版本(参看http://unxutils.sourceforge.net)或者安装Cygwin环境(http://cygwin.com),这样就可以使用egrep了。否则,你只能使用操作系统内置的搜索功能,而不能使用egrep。
我们在前面的“从CVS签出Drupal”一节中,已经学到了如何根据DRUPAL-6分支上的一个标签来获取代码的一个版本。我们以此为基础,做些变通,来取回各种标签和分支下的代码,并把它们放在当前目录中的drupal文件夹下。
老葛的Drupal培训班 Think in Drupal
在http://drupal.org/project/coder,你将找到一个宝贝,它能帮你节省不少的时间,减轻你的烦恼。这就是编码器模块:一个用来评估其它模块代码的模块。
函数调用
当Drupal7出来以后,我们想继续开发Drupal6下的模块。而现在, DRUPAL-5分支的开发工作基本上停止不前了。但是我们也不能在HEAD上同时开发Drupal 7和Drupal 6下的版本啊?现在需要为Drupal 6创建一个分支,将特定于Drupal 6的开发放在那里进行。首先,我们需要确定我们使用的是HEAD的最近版本。接着,为Drupal 6创建分支。
让我们继续前进,来创建分支:
我们已经为Drupal5创建了一个分支,并在该分支上创建了一个标签。现在让我们把精力主要放在Drupal 6上,来添加对badger(徽章)模块的依赖关系。但是首先,我们需要做出一个决定。我们是应该立即创建一个分支呢?还是应该简单的使用HEAD?由于我们可以在任何想要的地方创建标签,所以这个问题就是,又没有必要创建一个DRUPAL-6分支?让我们检查一下这两种不同的方式。
我们知道,还有许多懒惰的用户还在使用Drupal5,现在让我们看看如何为他们创建一个分支。
为了使那些不熟悉CVS的人也可以下载你的模块,你应该在drupal.org上创建一个发布节点。一个发布节点提供了给定发布标签的相关信息,而drupal.org上的打包脚本能够自动的为发布标签指示的文件构建一个tarball(沓包)。例如,你能为你模块的DRUPAL-6--1-3标签创建一个发布节点。打包脚本从DRUPAL-6—1分支取出DRUPAL-6--1-3标签所标示的文件,然后为其创建一个tarball(沓包)和一个链接,这样drupal.org上的访问者就可以下载这个tarball(沓包)了。而tarball(沓包)的名字则应该为foo-6.x-1.3.tar.gz。
现在到了关键时刻了。是时候将你的文件提交到资源库中了!是不是有点紧张。检查/path/to/local/copy/of/contributions/modules/foo,看看它是不是包含了所有的文件并且里面包含了你想要提交的代码。接着,输入决定性的命令。使用一个简洁的句子来描述你模块的功能,接着继续前进:
对于任何软件项目,版本控制都是必须的,同样Drupal也不例外。版本控制用来追踪Drupal中的每个文件上的所有变更。它保存了所有修订本的历史以及每个修订本的作者。你可以从中得到一个逐行的报告,里面包含谁做了变更以及什么时间什么原因。版本控制也可以简化新版本的发布流程。Drupal社区使用久经锤炼的可靠的CVS软件,来维护它的修订本历史。
老葛的Drupal培训班 Think in Drupal
由于你把你的模块贡献给了社区,如果能够使用一种结构化的方式,让模块的其它用户能与你进行交互,这应该是再好不过了。这样,你就不会经常收到哪些不期而遇的电子邮件了,而且还有一种标准的方式用来追踪请求的特性、bug修正、等等。登录到drupal.org以后,访问http://drupal.org/node/add/project,或者使用站点导航菜单导航到“创建内容➤工程”,然后填充表单;你需要格外注意一下“完整描述”字段,在这里你可以描述你的模块(或者主题)。填完表单以后,你就可以访问你的工程了,工程地址为:http://drupal.org/project/yourprojectname。
Drupal的核心代码使用了CVS的,然而你工程的其余部分,可能完全没有使用版本控制,也可能使用了一个不同的版本控制系统。
下面是一个例子,如何使用devel模块识别缓慢的查询,从来提高站点的性能。假定我们已经编写了一个自定义节点模块task(任务),而且使用hook_load()来向节点对象添加关于任务的附加信息。表的模式如下:
老葛的Drupal培训班 Think in Drupal
在命令行中运行下面的命令,来测试是否安装了一个CVS客户端:
当你从drupal.org的下载页面,下载了Drupal压缩包时,代码的这份拷贝没有带有任何版本信息;版本信息可用来告诉你基准代码的当前状态。
老葛的Drupal培训班 Think in Drupal
现在你有了一份贡献资源库中modules子目录的拷贝,你可能想现在就可以将你的模块其它上千个模块放到一起了。我们先不要急!首先,花点时间调查一下资源库中是不是已经有一个模块解决了你的问题。下面是一些资源,可帮你确定这一点:
常量
老葛的Drupal培训班 Think in Drupal
下面的PHP调试器和集成开发环境(IDE),提供了一些强大工具,能够帮你快速找到Drupal的瓶颈所在;它们也能够帮你找出模块中的低效算法:
读完本章后,你应该能够:
控制结构体是程序中用来控制执行流程的指令,比如条件语句和循环语句。条件语句有if, else,elseif,和 switch语句。循环语句有while,do-while,for,和foreach。
如果你的签出正常工作了,那么在sites/all/modules/contrib下,应该包含以下内容:
老葛的Drupal培训班 Think in Drupal
文件名应该是小写的。例外情况就是文档文件,它们全部大写并使用.txt后缀,例如:
让我们从头到脚仔细的看看一个模块的基干,同时将不同类型的文档从中选出来进行单独说明。
打开页面http://example.com/?q=admin/settings/devel(如果你启用了开发区块的话,那么还可点击“Devel 设置”链接),选中“Collect query info”(收集查询信息) 和 “Display query log”(显示查询日志)旁的复选框。
你可以使用cvs log命令来查看一个文件的历史。让我们看看foo.info文件的两次提交:
现在模块已经可用于Drupal 5了。让我们继续前进,来创建一个发布。我们将通过创建一个标签来实现这一点。
打标签和做分支是许多修订本控制系统的标准练习。我们将学习一下,如何在Drupal核心和贡献的模块中使用这些概念。花点时间好好的理解一下这些概念,可帮你节省不少的时间,并减轻不少的烦恼。
在分支名字比如DRUPAL-6—1和标签名字比如DRUPAL-6--1-3中,我们看到有两个连字符是连着的。如果你把紧挨着6的连字符看作是Drupal的一个发布的通配符,那么就不难理解了。也就是说,DRUPAL-6--1-3标签,对应于你模块的6.x-1.3发布,它与Drupal 6的任意发布都兼容(Drupal 6.1, Drupal 6.2, Drupal 6.3,等等)。把标签名中主版本号后面的连字符,想象成可以翻译为发布号的x,如下所示:
永远不要在模块名字中使用下划线。为了理解这一点,考虑以下情景:
老葛的Drupal培训班 Think in Drupal
http://drupal.org/project/module_builder中,有一个很好的模块,它能帮你方便构建出模块的骨架。它向你询问你想要创建的钩子,并帮你创建它们,而且还带有示例代码。接着,你就可以在它的基础上开始工作了!
软件测试就是将一个程序隔离成不同的部分,来判定它们的行为和预期的是否一致。在Drupal的接下来的版本中,测试将会是一个主要的目标。事实上,在Drupal 7中,测试将成为核心的组成部分。测试的好处包含以下几点:
现在,你的模块已被提交到资源库中了,这和其它的第3方模块一样,你可以将它从CVS签出,并放在你的Drupal本地开发拷贝中(你可能首先需要创建modules和contrib目录):
我前面提到了,drupal.org有两个资源库,一个用于核心代码,一个用于贡献的代码包括模块和主题。对于前者,只有很少的人能够访问;而对于后者,许多开发者都可以访问。你可以以匿名或者登录用户的身份,来签出贡献资源库。如果你是为了一个站点从贡献资源库签出代码的话(例如,你只想使用CVS获取一个模块的拷贝,这样你就可以运行它了),那么最好使用匿名用户的身份进行签出。否则,当下一个人来维护你创建的Drupal站点时,他想从CVS上更新模块代码,而系统则提示需要输入你设置的密码,那么此时他会晕死的!
在本节中,我们将详细的学习一下,如何在drupal.org上创建和维护一个模块。我们将覆盖大多数的常见任务。
Drupal社区认为,它的基本代码必须拥有一个标准的外观,从而提高可读性,也使得初学者更容易学习。社区也鼓励第3方模块的开发者采用这些标准。实际上,让我老实的告诉你:如果你没有遵守编码标准,那么你的模块在Drupal社区就不会得到认真对待。我们首先学习一下具体的标准,接着介绍了一些用来检查代码的自动工具(甚至为你纠正代码!)
老葛的Drupal培训班 Think in Drupal
如果你修改了Drupal的核心代码,那么当你执行CVS更新时就可能出现冲突。运行完cvs update命令以后,对于那些带有冲突的文件将会使用一个“C”将其标出,由于这些冲突的存在(CVS插入的用来标记冲突的文本,不是有效的PHP),所以你的站点也将不再工作。CVS尝试着合并文件的新版本和旧版本,但是它没有成功,所以现在需要人工干预,来手工的检查冲突文件。发生冲突时,包含冲突的文件就像下面的这样:
想检查开发小组中是否有人修改了核心文件?对于核心文件上所做的任何变更,想为其生成一个报告?cvs diff命令,根据代码的不同之处(也就是更新和修改),为用户生成一个逐行的输出。
老葛的Drupal培训班 Think in Drupal
有两种主要的方式,可用来检查你的编码风格是否符合Drupal的编码标准:一种方式是使用一个Perl脚本,另一种方式是使用一个第3方模块。
Coding Standards: 编码标准
在前面的例子中,我们假定在一个Drupal主版本下只存在模块的一个主版本,但是这也有例外的情况。例如,假定我们发布了foo模块的6.x-1.3版本。接着,灵感爆发了。我们想到了另外的一种实现方式,只需要一半的代码量,就可以实现同样的功能,而且跑得更快。不过,这需要修改API,而与foo模块相关的一切将全被打乱。解决的方案是使用新API发布一个2.0版本。由于模块仍然兼容于Drupal 6,所以我们使用DRUPAL-6--2-0作为标签名,而对应的发布号就是6.x-2.0。
Drupal的内核架构非常简洁并且非常灵活。然而,这种灵活性是有代价的。当启用的模块增加时,处理一个请求的复杂度也会增加。这意味着将耗费更多的服务器资源,必须实现一些策略,在一个站点日渐流行同时,来保证Drupal特有的简明。通过适当的配置,Drupal可以很容易的满足用户的需求。在本章中,我们将讨论性能(performance)和可升级性(scalability)。性能指的是你的站点响应一个请求所用的时间。可升级性指的是你的系统可以同时处理多少个并发请求,通常用“请求数/秒”来度量。
当数据必须使用缓慢的设备比如一个硬盘进行交互时,系统通常会遇到一个性能问题。如果你能够为数据绕过这一操作,而且你能够承受得起数据的丢失(比如session数据),那会怎么样呢?此时我们可以使用memcached,这个系统将读写操作都放到内存中进行。与本章中介绍了其它解决方案相比,Memcached更加复杂,而且更难设定。,但是当你的系统需要在可升级性方面有所提高时还是值得考虑这一方案的。
PHP最优化措施
Web服务器进程处理一个请求时,用到RAM的地方包括,web服务器加载所有的模块(比如Apache的mime_module, rewrite_module,等等),还有PHP解释器使用的内存。启用的web服务器和Drupal模块越多,处理单个请求耗费的RAM就越多。
优化表结构
为了让你的web服务器更有效的运行,这里有一些其它的措施。
多个数据库服务器带来了额外的复杂性,因为数据将被重复插入和更新,或者数据库被分割到多个服务器中。
在本章,你学到以下几点:
如果你的网站运行性能达不到预期,第一步要做的就是分析问题所在。可能的原因包括web服务器,操作系统,数据库,和网络。
Drupal需要进行大量的数据库操作,特别是对于登录的用户和定制的模块。数据库常常会成为产生瓶颈的原因。这里有一些基本的策略用于优化Drupal中数据库的使用。
文件上传和同步
Drupal可用的架构就是那些其它的LAM堆栈软件,以及使得Drupal具有可升级性的技术。因此,我们将为你讲述不同的架构,并主要针对Drupal来讨论相关的技巧。
大多数针对Drupal的最优化措施,都在软件堆栈的其它层次中进行,也有一些专门针对Drupal本身的最优化措施,这也能使性能得到极大提升。
独立的数据库服务器和web服务器集群
管理已验证用户的访问
识别耗费资源的页面
运行cron
当你安装Drupal时,会有一些模块被启用,一些特定的配置被选择,但是这些默认的设置可能并不是你所需要的。Drupal安装器使用了一个默认的安装过程轮廓,用来决定所有的这些配置。通过创建你自己的安装轮廓,你可以定制Drupal的初始安装,从而使你的站点带有你想要的模块和设置。假定你在为某一高校工作,你想创建一个安装过程profile,从而能够启用一个与学校单点登录系统相绑定的定制模块,能够为站点管理员创建一个新角色,能够在安装完成时向你发送e-mail。Drupal的安装器系统,允许你通过创建一个安装轮廓来定制安装时的各种操作。在本章你将学到如何做到这一点。
导入了用户以后,那么将会调用importusers_optimize()。最后,当该操作也完成后,那么将会调用我们在finished键中指定的回调(importusers_finished())。下面是importusers_import()函数:
使用批处理API
当Drupal的安装器启动时,它扫描profiles目录以查看有多少个可用的轮廓。如果它发现有多个轮廓时,它将显示所有的轮廓以供用户选择。例如,在创建了我们的university.profile文件,并向其中添加了university_profile_details()函数以后,访问http://example.com/install.php,将会产生一个如图23-1所示的界面。(当然,安装轮廓现在实际上还不能工作---还有很多工作需要去做。)
我们在前面提到,一组处理又被称为一个批处理集。批处理API可以处理多个批处理集,而无须混合它们。可以按照先后顺序来处理多个批处理集,同时为每个批处理集使用一个新的进度指示器。
注意图23-1中左边栏中的任务列表(“选择轮廓,”“选择语言,” “验证需求,”等等)。让我们通过在我们的安装轮廓中定义一些任务,来将它们也添加到这个列表中。我们将编写一个函数,它的名字为:我们的轮廓名字+_profile_task_list:
在本章,你学到了以下几点:
通过添加函数university_profile_modules(),我们告诉Drupal我们的安装轮廓想要启用哪些模块(还有,我们知道这个函数的名称是由我们的轮廓名称加上_profile_modules合成)。这个函数返回一个数组,里面包含了轮廓所要启用的模块名称。对于数组中模块名称出现的顺序,你要小心一点,因为模块之间可能是存在依赖关系的,以需要正确的处理这种可能存在的依赖关系。
渐进式批处理集就是一个普通的批处理集,它使用一个进度指示器向用户提供反馈。然而,当时想通过drupal_execute()来使用程序提交表单时,你应该不需要渐进式批处理集。所以,在这种情况下,表单API认出这是由程序提交的表单,并将批处理集设置为激进式。激进式批处理集将在单个请求中执行所有的操作。渐进式和激进式批处理集的设置,如图23-6所示。
老葛的Drupal培训班 Think in Drupal
设置Drupal变量
编写安装轮廓需要更多的技巧。在我们的例子中,尽管我们没有在university_profile_modules()中包含评论模块,但是我们需要把评论模块包含在范围内,这样就可以使用它的一些常量来设置首选项了。我们在输入分类术语时,使用了程序的方式来提交表单,在这里我们需要定义一个$form_state['clicked_button']条目,尽管看起来它是没用的,但是该表单的提交处理器需要这个条目。在你的安装轮廓中,你也需要花点时间注意一下类似的细节。
你的Drupal站点已经包含了一个安装轮廓。它是Drupal自带的默认安装轮廓,位于profiles/default/default.profile。我们想创建一个新的名为“university”(大学)的轮廓,所以我们首先需要在profiles/university/university.profile创建一个新文件。现在,我们向这个文件中添加一个单独的函数:
在安装的profile阶段,将运行我们在university_profile_task_list()中指定的任务。在该阶段期间,安装器将重复的调用university_profile_tasks(),并向其传递参数$task和$url,其中$task变量包含了任务名字,而$url则是一个在表单函数中可能用到的URL。安装器初次调用它时,$task将包含字符串profile。
我们的第一个自定义安装任务为用户显示了一个交互式的表单。现在让我们定义该表单。我们可以使用标准的表单API,但是在这里需要仔细一点,我们把$form['#redirect']设置为FALSE,把表单的动作设为安装器提供的URL。表单的处理由一个提交处理器负责,这和普通的表单一样。下面是表单定义和提交处理器。表单如图23-4所示。
错误处理
installer:安装器
这个附录描述了Drupal核心的数据库表和字段。这里的描述来源于核心模块的.install文件,其中为了表意清晰我稍微做了一点改动。把这一信息放在这里,是为了大家使用时的方便。
#drupal
actions_aid(触发器模块)
aggregator_item(聚合器模块)
blocks(区块模块)
boxes (block module) (区块模块)
cache_filter(过滤器模块)
cache_page
contact (contact module)(联系模块)
filters(过滤器模块)
languages(本地模块)
menu_links(菜单模块)
menu_router
node_comment_statistics(评论模块)
node_type (节点模块)
node(节点模块)
poll(民意测验模块)
profile_values(轮廓模块)
search_total(搜索模块)
system
term_relation(分类模块)
users(用户模块)
variable
watchdog(数据库日志模块)
网管
Parenthese: 括号(又名圆括号):()
老葛的Drupal培训班 Think in Drupal
对于Drupal开发者来说,有很多可以利用的资源。我们在这里列出了最常用的一些。
老葛的Drupal培训班 Think in Drupal
论坛