这个文章系列记录了开发一个开放源码的协作型 Web 站点的全过程。其中许多文章讨论开发过程以及 IBM Internet Technology Group 团队如何创建需求和代码。使用 Drupal 仅仅是解决方案的一个组成部分,但它是开发过程的中心。与其他有活力的软件一样,Drupal 仍然在发展,目前的版本是 5.1;当团队开始编写本系列时,我们使用的是 Drupal 4.7。
最后这一期讨论一些影响站点实现的重要问题,并描述我们如何将代码升级到 Drupal 5。
注意:不应该把本系列中的信息理解为必须遵循的严格的开发原则,而是应该作为使用 Drupal 时的起点。
对于创建内容管理系统(CMS),目前有许多开放源码的解决方案,而且情况一直在变化。尽管 第 1 部分 并非专门概述 CMS 解决方案,但是描述了我们选择 Drupal 的基本原因。更全面的 CMS 概述应该包含许多其他系统,包括 Plone 和 NukePHP。如果我们现在重新评估 CMS 的现状,还会包含 Joomla 和 Expression Engine 等系统。坚持选用开放源码的 CMS 解决方案可能会引发争论。但是,如果有时间限制,那么必须做出决定;而且对于这个项目,事实证明我们的选择是正确的。
无论使用哪种 CMS,都有一个学习的过程。尽管 Drupal 很容易管理,但是万事开头难。Drupal 有文档,但是并非总是能够在现有的 Drupal 手册结构中找到针对当前任务的信息。几乎没有描述如何将 CMS 集成进整个开发过程的文档。所以,在掌握了 Drupal 之后,我们意识到可以通过编写这些技术文章来帮助别人。我们相信这是回报开放源码社区的好方法。
Drupal 非常出色。需要新功能时,我们往往会发现现有模块就能够满足需要。即使没有合适的模块,也能够快速地构建自己的定制模块来扩展系统功能。许多开放源码 CMS 都具有这种可扩展性,这对于及时解决新出现的问题非常重要。
Drupal 社区很活跃,而且在不断扩大。Drupal Web 站点每个月有 800 万次点击。Web 站点上的 图书 不断增加,还提供 视频教程 并每年举行一次 会议。
本节总结这个项目的关键思想。
第 2 部分 讨论了我们设计和实现 Web 站点的过程。我们只将这个过程作为指导原则。根据项目的类型、客户需求和时间限制,我们以务实的方式选用这个过程的某些部分。任何过程都应该以务实的方式使用,从而适应不同的情况。有时候需要更深入地研究用户,而其他时候掌握简单的用户特征就够了。
了解虚构的 IBC 公司的业务目标,以及这个社区 Web 站点支持的用户的真实需求,这一点对于开发解决方案非常重要。业务目标帮助我们更好地描述和组织 IBC 内容。它还帮助我们建立一个低真实度的原型,我们可以利用这个原型让 IBC 社区参与到设计过程中。让客户参与设计过程意味着,我们能够在早期捕捉到许多真实的需求,从而明确设计范围,帮助避免在开发过程的后期才发现问题。对简化的关注确保只将最重要的需求包含在更高真实度的原型中。
为了获得既有用又易用的设计,一定要 “了解用户”。所以我们让用户(和所有者)从一开始就参与进来,让他们有参与感,感觉自己是项目的主人,这对于建立良好的关系是非常必要的。来自用户的信息还帮助我们在解决主机托管和部署问题时做出重要的决策。
从根本上说,对内容应用样式的效率和灵活性取决于内容的结构是否良好。因此,在生成内容时,一定要保持内容的结构与它的表示形式分离。如果 XHTML 尽可能保持语义正确,那么使用层叠样式表(CSS)就非常容易了。
Drupal 提供了用模板文件对 XHTML 结构进行模块化的方法。但是,我们发现了几种有用的技术,可以改进主题 CSS 中样式的结构和能力,包括:
- 将 Web 站点特定方面和区域的样式放在它们自己的文件中
- 按照字母次序列出所有样式,从而创建一致的次序
- 在 CSS 的注释块中使用便于搜索的字符,帮助快速找到样式
在开发过程中使用出色的工具是非常重要的。Eclipse 和 Concurrent Versions System(CVS)很适合我们。在 第 13 部分 中讨论调试时,讨论了如何使用强大的软件开发环境让开发过程更高效更有效。在团队开发中,CVS 是非常有用的,它可以跟踪代码更改,让我们能够同时进行开发,还可以向 Drupal 核心代码提供任何版本或修订版更新。
事实证明通过示例进行学习是非常有用的。花时间看看 Drupal 核心代码和模块、贡献的模块以及主题,了解系统是如何实现的。不要害怕研究源代码;研究别人的模块和主题是学习技术的好方法。试着添加或删除代码,看看 Drupal 的表现有哪些变化。更方便的是,因为代码存储在 CVS 中,所以随时可以恢复原来的文件。
下一节讨论 Drupal 5.0 提供了哪些新东西,以及它对典型的 Web 站点开发过程的影响。我们通过对 announcement 模块(最初在 第 6 部分 中讨论)进行升级来具体说明这些变化。
5.0 中出现了许多变化,但是与从 4.6 迁移到 4.7 相比,从 4.7 迁移到 5.0 要容易得多。Drupal 5 非常令人兴奋。本节讨论一些主要的变化,包括:
到编写本文时,5.1 版已经发布了。Drupal 站点指出:
“它提供了许多新特性,包括基于 Web 的安装系统、改进的管理工具和一个有意思的新主题!在幕后还有许多改进,比如包含了 jQuery JavaScript 库(http://jquery.com/),改进了节点访问系统(ACL),对 Form API 做了许多改进。”
请参考官方 Drupal 5.0 站点和介绍 5.0 中最新特性的 视频 [13 MB, 10 min, mp4]。
在本系列的 第 3 部分 和 第 4 部分 中,讨论了如何在 Windows® 和 Linux® 上安装和配置开发 Drupal Web 站点所需的所有开放源码软件。这些步骤包括安装和配置 Eclipse、PHP、MySQL 和 Drupal。对于 Drupal 5,安装过程更加简单。在按照第 3 部分和第 4 部分的描述安装和配置 Apache、MySQL 和 PHP 之后,下载 Drupal 5.1。与安装 Drupal 相关的一些新特性如下:
- 基于 Web 的安装程序
- 检查安装需求
- 自动生成数据库配置文件
- 安装预先准备好的 “安装配置文件” 或发行版
- 导入带自动表前缀的数据库结构
- 安装可以本地化
下载的 Drupal 文件包含安装过程的文档,包括 INSTALL.txt、INSTALL.mysql.txt 和 UPGRADE.txt。现在,Drupal 的所有配置都可以通过一个基于 Web 的界面进行设置。通过浏览器访问 Apache 支持的 Drupal 主目录。应该会看到一个用于数据库配置的安装页面,见 图 1。如果没有看到这个页面,那么可以访问 http://<yoursite>/install.php 来显式地运行安装脚本。不再需要手工编辑 settings.php 文件。可以检查安装的需求,并自动地创建数据库表。可以将预先准备好的安装配置文件 创建为发行版,安装还可以本地化。
图 1. 安装
要想对现有的 Drupal 进行升级,可以运行脚本 http://<yoursite>/update.php。在进行升级之前,应该对数据库进行备份,因为升级会修改数据库。图 2 显示数据库更新页面。
图 2. Drupal 5 数据库更新
图 3 显示 Drupal 的默认安装,其中使用了新的 Garland 主题。
图 3. Drupal 的默认安装和新的 Garland 主题
在使用 MySQL 和 PHP 组件的新版本时,可能会出现一些问题。Drupal 站点上通常记录了这些问题,但是很容易错过这些信息。我们在使用 beta 版本时遇到了下面描述的两个问题。如果遇到了任何安装和配置问题,那么可以在 Drupal Web 站点上寻找帮助。
如果使用 MySQL 5.0 或更高版本,那么在导入 database.mysql 文件时可能会遇到错误 1364。也可能会遇到其他问题,包括缺少侧栏和张贴内容导致错误 “user error: Field 'revisions' doesn't have a default value...”。这些错误是由 MySQL 5.0 的严格模式导致的,这个模式与几个 Drupal 查询不兼容。MySQL.com 提供的 Windows 安装程序在默认情况下会启用这个严格模式。
有几种纠正方法。一种是将 my.ini 文件(这个文件位于 MySQL 安装目录或 Windows 目录)中当前的 sql-mode 行替换为 sql-mode="MYSQL40"。更多信息参见 Error 1364。
对于 PHP 5.2.0,每个会话的用户 ID 设置为 uid 0。发生这种情况是因为在 sess_write() 会话处理程序中无法使用全局用户对象。由于这个问题,您可以登录,但是无法执行进一步的操作。对于 PHP 5.1.x,不会出现这个问题。更多信息参见 Drupal 站点 session doesn't keep userid with php5.2.0。
管理页面有显著的变化,包括:
- 管理页面已经完全重构了。
- 按照任务和模块访问菜单项。
- 管理页面很容易进行主题化。
- 提供一个状态报告页面,其中包含详细的 PHP 和 MySQL 信息。
图 4 显示供管理员使用的导航区块。它是按照任务和模块进行组织的。
图 4. 改进的管理导航
很容易独立于整个站点的主题对管理页面进行主题化。在 图 5 显示的管理员界面上,可以指定与主站点的主题不同的主题。在这里,我们保持设置为 System default,这使管理页面采用与 Web 站点其他部分相同的主题。
图 5. 用来修改管理页面的主题的管理员界面
与用户界面相关的主要修改如下:
- 使用新的默认主题 Garland(见 图 3)
- 颜色模块让用户能够修改主题的颜色方案
- 为用户配置文件增加了自动补全表单(AJAX)支持
- 可以立即给新创建的用户帐号分配角色
- 改进了联系人表单的可配置性
- 重新组织了设置页面
- 简化了对流行的搜索词的研究过程
- 允许以程序方式提交表单
- 改进了多步骤表单的 API
颜色选择器见 图 6。默认颜色集是在 garland 主题中指定的。这个颜色集中的每个主题颜色都可以独立地指定。颜色选择器让管理员能够轻松地改变主题中的颜色。
图 6. 颜色选择器
Drupal 现在支持 jQuery,这会影响需要编写的 JavaScript。更多信息请参见 Added jQuery to Drupal 和 jQuery。
Drupal 5.0 对主题化引擎做了一些重要的改进。这些改进影响了我们文章中基于 4.7 描述的一些 Web 页面设计技术。关于这些变化的更多信息,参见 Converting 4.7.x themes to 5.x。
比较重要的变化如下:
-
drupal_add_css替代theme_add_style,可以更精细地控制 CSS 文件的包含。这减少了对默认的drupal.css文件的依赖,可以避免在page.tpl.css文件中对 CSS 进行硬编码。为了提高性能,还可以让 Drupal 将所有 CSS 文件合并成一个文件,然后再将页面交付给浏览器。
- 在 4.7 中要调用
drupal_set_html_head()来添加 JavaScript 文件;现在通过调用drupal_add_js()添加 JavaScript 文件。更多信息参见 drupal_add_js()。
- 主导航链接的 XHTML 的结构性更强了,这使应用样式更容易了。
- 在 Drupal 5.0 中没有实现无需使用额外 XHTML 标记的清理浮动的方法。
- 现在可以基于站点 URL 中的路径创建页面模板文件。(参见 Using different page templates depending on the current path。)
- 不再需要在
_phptemplate_callback函数中指定主题模板文件,Drupal 5.0 允许定义一个文件名列表,可以使用这个列表寻找模板。 - 可以根据区域、模块等为区块模板命名。(参见 Using different block templates for different blocks, regions, etc.。)
- 现在,在使用
theme('page')函数创建自己的页面时,可以禁用标准区块。(参见 theme('page') may omit standard blocks 。) - 可以为管理页面启用单独的主题。
在对数据进行主题化时,我们强调代码与表示的分离以及结构与样式的分离。Drupal 的主题化系统可以帮助实现这个目标。新特性(比如基于 URL 路径寻找页面模板)增强了主题设计人员对模块提供的数据进行定制的能力。
覆盖现有的主题函数是主题定制的另一个重要方面。理解 Drupal 搜索主题函数的方式是非常重要的,因此有必要再总结一下。对于主题函数名(TFN) foo,Drupal 的消除过程如下:
- 是否有使用这个 TFN 的主题特定的函数?对于主题
ibc,函数名应该是ibc_foo(),这个函数可能在 ibc 主题目录中的 template.php 文件中。 - 如果没有主题特定的函数,那么是否有使用这个 TFN 的主题引擎特定的函数?如果当前主题使用 phptemplate 引擎,那么 Drupal 会寻找
phptemplate_foo()函数。这个函数可能在主题的 template.php 文件或 phptemplate.engine 文件中。为了进行演示,我们在示例模块中包含了主题引擎特定的模板。
- 如果没有主题引擎特定的函数,那么是否有使用这个 TFN 的默认函数?这个函数应该称为
theme_foo()。这个函数位于 Drupal 核心包含和模块文件中,或者在贡献的任何模块文件中。
根据这个过程,我们通常会搜索安装 Drupal 的目录,寻找 theme_[TFN] 函数。在覆盖函数时,这常常提供一个好起点。找到这个函数之后,可以将它的代码复制并粘贴到 phptemplate.php 文件中,在函数名前面加上主题名或主题引擎名,然后根据自己的需要修改函数代码。
关于将主题从 4.7 迁移到 5.0 的更多信息,参见 Converting 4.7.x themes to 5.x Drupal 5.x。
您应该了解 Drupal 5.0 对模块系统的一些改动,包括:
- 增加了用于模块元数据的 .info 文件
- 增加了对模块依赖项的支持
- 改进了模块安装屏幕
- 将核心模块转移到它们自己的目录中
- 增加了对模块卸载的支持
现在,所有模块使用一个额外的 <module_name>.info 文件。这个文件替代 hook_help 函数,所以可以从钩子函数中删除帮助信息。这个文件包含一个名称和描述,见 清单 1。如果这个文件不存在,那么模块就不会显示在模块列表中。还可以指定依赖项 和一个任意字符串,从而将您的模块集中在列表页面上的一个包 中。
清单 1. announcement 模块的 <module_name>.info 文件示例
; $Id: index.xml,v 1.5 2007/02/15 15:11:19 weitzman Exp $
name = Announcement
description = Provides for announcements to be published on your web site.
|
module.install 文件现在可以包含一个 hook_uninstall() 函数,它用来删除模块创建的任何表和变量。对于 announcement 模块,这个钩子的实现可能像 清单 2 这样。
清单 2. announcement 模块的卸载钩子
<?php
function announcement_uninstall() {
db_query('DROP TABLE {announcement}');
variable_del('announcement_block_max_list_count');
}
?>
|
hook_node_info
这个钩子使模块能够为它们的节点类型定义更多的属性。但是,如果采用这种方式,一项小改动会导致一些问题。base 数组子元素已经重命名为 module。如 清单 3 所示,所有节点类型现在有三个必需的属性:name、module 和 description。更多信息参见 Changes to hook_node_info() and the node type systems。
清单 3. Drupal 5.x 中对 hook_node_info 的小改动
function announcement_node_info() {
return array('announcement' => array('name' => 'announcement',
'module' => 'announcement',
'description' => 'Announcements...'));
}
|
定制的模块和主题应该放在 /sites/all/ 下面单独的目录中,以避免与 Drupal 代码和未来的版本冲突。更多信息参见 Converting 4.7.x modules to 5.x。
对区块系统的改动解决了社区发现的与主题模板中的 PHP 或 CSS 相关的问题。现在,当在 Administer > Site building > Blocks 下配置区块时,可以重写区块标题或者完全取消标题,见 图 7。在这个页面上,还可以将区块设置为只对某些角色可见。
图 7. User Login 区块的配置页面
现在,模块可以使用 hook_profile_alter() 函数在用户配置页面上添加、删除或修改表单元素。
如 图 8 所示,在 Administer > User management > User settings 页面上添加了一个复选框,用来关闭电子邮件检验。
图 8. 控制可选的电子邮件检验的控件
Administer > User management > Users 页面现在添加了对所有用户进行过滤和更新的新功能,见 图 9。
图 9. 用于用户管理的过滤和更新控件
那些使用 node_access 表限制用户查看、添加和编辑节点访问的模块,现在使用 hook_node_access_records() 函数操作访问值。在 node_access_example.module 上有一个说明如何使用这个函数的示例。
在 Drupal 5.0 中,Content Construction Kit 中创建定制内容类型的部分已经包含在核心中,可以通过 Administer > Content management > Content types 访问它。
节点内容现在存储在一个结构化数组中,存储方式与在 Form API 结构化数组中存储表单元素的方式相同,可以使用 drupal_render() 函数显示节点内容。
Drupal 5.0 现在实现了卸载模块的方法,从而能够清理数据库。新函数 db_table_exists() 判断一个数据库表是否存在。
与内容和主题化形式的分离相似,保持数据库的附加和修改与标准 Drupal 系统的分离也很重要。如果需要的话,应该为您的应用程序使用单独的表,而不是在现有的表中添加内容。另外,提供适当的安装和卸载钩子。
在 Drupal 5.0 中,对 Drupal 核心和性能做了许多改进,包括:
- 包含 jQuery JavaScript 库 1.0.3,所有内部核心代码都使用它
- 增加了对不同缓存后端的支持
- 增加了对泛型 sites/all 目录的支持
- 增加了默认的 robots.txt 来控制爬行器
- 改进了会话处理,减少了数据库开销
- 改进了访问检查,减少了数据库开销
- 支持基于内存缓存的会话管理
- 当出现 “404 Page not found” 时,忽略侧栏,这可以节省 CPU 时间和带宽
- 增加了一种激进的缓存策略
本系列介绍了构建协作型 Web 站点的全过程。在此期间,您学习了如何避开常见的陷阱。在本文中,研究了 Drupal 5.0 中的改动,以及我们的团队在开发这个开放源码项目期间学到的一些经验。我们希望您能够将这些技术应用于自己的下一个开发项目中,并对这个开发过程进行改进。
既然您已经了解了如何创建模块,就请为社区做些贡献吧!Drupal 社区的 指导方针 描述了如何将您的贡献提交给社区。在从头开发任何东西之前,建议您先看看目前已经有的模块。扩展或改进社区中现有的东西要比自己从零做起好得多。
因为我们已经掌握了 Drupal,我们在后续的项目中将它用作快速的原型系统。尽管 “快速” 只是相对而言的,但是我们确实能够非常快地建立一个可运行的站点并提供一个演示站点,这帮助我们收集意见并推动项目向前发展。我们正在探索改进 Drupal 功能的新方法,希望与更广泛的社区分享这些想法。
通过编写这个系列,我们在 Drupal 社区中结识了不少朋友,还与 IBM 中的许多 Drupal 用户建立了联系。
祝您一切顺利!
—— Stephen、Alister 和 Louie
- 关于 Windows 平台的相关下载,参见本系列的 第 3 部分。
- 关于 Linux 平台的相关下载,参见本系列的 第 4 部分。
- announcement 模块的完整源代码参见本系列的 第 14 部分。
学习
- 您可以参阅本文在 developerWorks 全球站点上的 英文原文 。
-
Converting 4.7.x modules to 5.x 描述模块界面的变化。
-
Converting 4.7.x themes to 5.x 提供对站点的主题化进行升级的详细信息。
- 了解 jQuery 的相关信息。这是一个快速简洁的 JavaScript 库,可以帮助您在 HTML 文档中移动、处理事件、执行动画以及在 Web 页面上添加 Ajax 交互。
- 随时关注 developerWorks 技术活动和网络广播。
获得产品和技术
- 使用 IBM 试用软件 构建您的下一个开发项目,这些软件可以从 developerWorks 直接下载。
讨论
- 参与论坛讨论。
- 通过参与 developerWorks blog 加入 developerWorks 社区。

Stephen Evanchik 是 IBM 的 Internet Technology Group 的软件工程师。他是许多开放源码软件项目的代码贡献者,其中最著名的是 Linux 内核中的 IBM TrackPoint 驱动程序。Stephen 当前从事语义 Web 技术。

