这里将介绍如何编写你自己的Drupal模块(module)。
关于Drupal API文档可以参看:http://api.drupal.org
下面列出一些模块编写教程,有的是中文原创,有的是翻译自drupal.org手册。
在开发新的模块或外观主题时,一定要注意不要与任何已有的模块或主题重名,否则将会引起冲突而不能正常工作。
本教程翻译自drupal.org的相关手册部分。
这篇教程讲述如何编写Drupal 5.x模块。本教程的内容基于Drupal 4.6的教程内容,大多数内容也适用于4.7。但你最好同时参阅Drupal API 文档以及如何升级模块等手册内容。
Drupal里面的一个模块(module - 也可以叫做插件,如果你更熟悉这个名称的话,但Drupal中通用的名字叫模块),实际上就是一套打包在一起的功能函数,用来实现Drupal缺省安装之外的扩展功能。在阅读了本教程后,你将可以自己编写一个基本的区块模块(block module),并在此基础上编写更高级功能的模块以及节点模块(node module)。
本教程知识介绍模块开发的最基本知识,不包括缓存(caching)、访问控制及一些安全性问题。但你可以在本教程的基础上,同时查看学习其它的模块是如何编写的,以及Drupal手册中相关的安全性及代码标准等内容。
本教程需要你具备以下知识:
本教程并不需要你具备任何关于Drupal模块内部功能的知识,同时也不能作为Drupal 4.5 以前版本的指导。
为更好理解这个手册,我们开始建立一个区块模块:列出一周前建立的blog或者forum讨论文章的连接。整个手册将教我们怎么样建立区域内容,写出连接和获得Drupal节点里的内容。
开始首先在你的drupal安装目录下建立一个文件夹:
sites/all/modules/onthisdate
你需要首先建立sites/all/modules这个文件夹, 然后在此文件夹里建立一个名叫onthisdate.module的php文件。对于Drupal 5.x,sites/all/modules里最好存放不是核心模块的模块(例如site/all/themes里最好存放不是核心模板的模板),因为这样站点本身文件会在他们自己的文件夹里。这会让你更容易更新核心文件和核心模块而不会删除你自己修改的地方。
<?php
/* $Id$ */根据代码书写标准,免去?>标签,并且使用完整的<?php标签。 在你给CVS提交文件的时候,$Id$字符串将帮助跟踪修改号码和时间。
在你模块里所有将被Drupal调用的功能,应该命名为{modulename}_{hook},"hook"是预先定义功能的后缀。Drupal将调用这些功能来得到具体数据,所以有了这些完整定义好的名字意味着Drupal知道在哪里寻找。我们将很快讲解hooks。
本模块现在还不可以运行,因为它还没有被激活。我们将在后面的讲解中激活此模块。
原文:http://drupal.org/node/82926
主要内容描述:让Drupal知道你模块的存在
Drupal"钩子“描述:hook_help
在Drupal 5.x里,hook_help将不在提供关于你模块的基本信息,名字和描述文字。所有模块现在需要一个名叫modulename.info的文件来包含所有关于该模块的信息。例如,在我们这个例子里,"onthisdate.info'。
一般格式是:
; $Id$
name = Module Name
description = A description of what your module does.没有该文件,你的模块在不会在模块列表里出现!
在我们的例子里,可以包含下列内容:
; $Id$
name = On this date
description = A block module that lists links to content such as blog entries or forum discussions that were created one week ago.在保存到你的模块文件夹sites/all/modules/onthisdate之前,把上面代码加入到一个名叫onthisdate.info文件里。
另外也可以选择加入(不是必须)下面两行代码:
dependencies = module1 module2 module3
package = "Your arbitrary grouping string"这两行代码在我们这个例子模块里没有作用,我们将不需要写入。如果你的模块需要其他模块的支持,只有在其他所有必须的模块都激活之后,Drupal才允许激活你的模块。
如果你把你的模块指派到一个包(package)里,在admin/build/modules页面里将会把所有在一个包里的模块放到同一个类别里。如果你不指派,它讲被列为无分类。不指派你的模块是完全可以的。一般来说,包是用在一起发放的模块或者需要用在一起的模块身上。如果任何怀疑的地方,可以在这一点上什么都不写。
一些已经存在得包区的例子:
这些文件使用ini格式并且包含; $Id$来使CVS插入文件ID信息。
请看PHP.net parse_ini_file documentation来获得更多ini文件信息。
我们还可以提供更多我们模块的帮助的附加信息。因为上述.info文件的使用,这个钩子(hook_help)现在是随意的(不是必须的hook)。但是实现它仍是不错的做法。这个函数的钩子名字叫'help',所以先来实现这个onthisdate_help函数。
<?php
function onthisdate_help($section='') {
}
?>$section是一个在Drupal或者模块帮助里提供帮助文字的变量。建议使用switch语句来处理这个变量。你将在其他模块里看到这种写代码的格式。
<?php
/**
* Display help and module information
* @param section which section of the site we're displaying help
* @return help text for section
*/
function onthisdate_help($section='') {
$output = '';
switch ($section) {
case "admin/help#onthisdate":
$output = '<p>'. t("Displays links to nodes created on this date"). '</p>';
break;
}
return $output;
} // function onthisdate_help
?>admin/help#modulename的情况是Drupal核在主要帮助页面(/admin/help or ?q=admin/help)添加一个连接。 你最终应该多加一些文字来为用户提供更好的帮助信息。
关于帮助钩的更多信息:
Drupal HEAD
把上面代码写到一个名叫onthisdate.module的文件,然后保存到你的Drupal安装目录里。
原文:http://drupal.org/node/82936
主要内容描述:权限
Drupal"钩子“描述:hook_perm
我们写的下一个函数(function)是用_perm钩子来实现的权限函数。在这里函数里,你可以定义你的模块权限的名字。这个函数并不准予和分配权限,它仅仅是定义了和这个模块相关的权限。基于这些权限的访问将在后面的函数{module}_access里定义,我们会在后面讲到。
现在,我们将用最常用的权限字符串,并把此权限给于所有通过"access content"字符串获得权限的,可以查看网站内容或者管理模块的人。这意味着,如果一个用户可以看到这个网站的内容,他/她也将能看到本模块所提供的内容。
<?php
/**
* Valid permissions for this module
* @return array An array of valid permissions for the onthisdate module
*/
function onthisdate_perm() {
return array('access content');
} // function onthisdate_perm()
?>相反,如果你要对你的模块进行更好的控制,并且可以在权限控制里选择相应的权限,你就应该扩展这个权限集。你可以加入有返回值的字符串数组。例如:
<?php
function onthisdate_perm() {
return array('access onthisdate', 'administer onthisdate');
} // function onthisdate_perm
?>在本教程里,先使用第一种方法。我们将在后面改用第二种。
你可以通过在 administer » accounts » permissions页面来修改谁可以查看你的模块。在后面,我们将使用user_access函数来检查访问权限。
你的权限字符串在你的模块里必须是唯一的。如果有重复,管理权限页面将会列出重复的权限。他们应该包含你的模块的名字,从而避免于其他模块的重复。
现在的命名方法是"行为动词 模块名" ("action_verb modulename")。例如
<?php
function newmodule_perm() {
return array('access newmodule', 'create newmodule', 'administer newmodule');
} // function newmodule_perm
?>现在我们已经完成了模块的设置,并可以在上面的模块文件里加入代码了。下面我们将开始写生成内容的代码。
关于帮助钩的更多信息:
Drupal HEAD
原文:http://drupal.org/node/82937
主要内容描述:区块内容
Drupal"钩子“描述:hook_block
有这样几类模块:区块模块和节点模块是其中的两个。区块模块一般(但不总是,也不是必须)建立简短内容并显示在页面左右两边。节点模块生成整页内容(例如blog,论坛或书籍页面)。
我们将从建立一个区块内容开始,之后再讨论节点模块,还有过滤内容。一个模块不仅可以为区块可以生成内容,也可以生成一整页的(blog模块就是一个好例子)。区块模块的钩可以被更确切的叫做区块,所以开始我们的下一个函数:
<?php
/**
* Generate HTML for the onthisdate block
* @param op the operation from the URL
* @param delta offset
* @returns block HTML
*/
function onthisdate_block($op='list', $delta=0) {
} // end function onthisdate_block
?>区块函数可以有两个参数:作用(operation)和弥补(offset, or delta)。弥补参数可以让你在同一个区块函数里为不同的区块建立不同的内容。现在我们将只关心作用参数。具体的,我们只关心区块被列在区块页面这个特殊的情况。在所有其他情况下,我们将显示区块内容。
当模块被列在区块页面时,$op(作用参数)的值应为'list':
<?php
/**
* Generate HTML for the onthisdate block
* @param op the operation from the URL
* @param delta offset
* @returns block HTML
*/
function onthisdate_block($op='list', $delta=0) {
// listing of blocks, such as on the admin/block page
if ($op == "list") {
$block[0]["info"] = t('On This Date');
return $block;
}
} // end onthisdate_block
?>下面,我们将来生成区块内容。
关于帮助钩的更多信息:
Drupal HEAD
原文:http://drupal.org/node/82955
主要内容描述:通过区块建立内容
Drupal"钩子“描述:hook_block
现在,我们需要在区块里生成'onthisdate'的内容。这里我们来看一种访问数据库的基本方法。
我们的目标就是得到一星期前建立的内容的列表(以'nodes'的形式存放在数据库里)。具体的说,我们要得到在当天午夜到一星期前的那天晚上11:59分之间建立的内容。当一个节点被建立的时候,建立的时间就会被储存到数据库里。我们将用它来找到我们需要的数据。
首先,我们来计算从一周前的午夜到一周前11:59分的时间(从epoch开始以秒计算, 到http://www.php.net/manual/en/function.time.php 来查看更多关于时间的信息) 。这一部分代码是何Drupal没有关系的,到PHP网站查看更详细的内容(http://php.net/)。
<?php
/**
* Generate HTML for the onthisdate block
* @param op the operation from the URL
* @param delta offset
* @returns block HTML
*/
function onthisdate_block($op='list', $delta=0) {
// listing of blocks, such as on the admin/block page
if ($op == "list") {
$block[0]["info"] = t('On This Date');
return $block;
} else if ($op == 'view') {
// our block content
// Get today's date
$today = getdate();
// calculate midnight one week ago
$start_time = mktime(0, 0, 0,
$today['mon'], ($today['mday'] - 7), $today['year']);
// we want items that occur only on the day in question, so
// calculate 1 day
$end_time = $start_time + 86400;
// 60 * 60 * 24 = 86400 seconds in a day
...
}
}
?>下一步是从数据库里得到我们想展示的内容的SQL语句。我们从节点table(Drupal内容的核心table)里取出内容。我们将用这条查询语句得到各类的内容类型:blog文章,论坛帖子等等。在本手册里,这样的做法是可以的。在真正的模块里,你应该调整SQL语句去选择具体内容的类型(通过加入'type'类型和一个WHERE语句来检查'type'列)。
注意:table名字包含大括号:{node}。只有这样,你的模块才能支持数据库table名字前缀。你可以通过阅读Drupal手册来获得更多关于这点的资料Table Prefix (and sharing tables across instances)。
<?php
$query = "SELECT nid, title, created FROM " .
"{node} WHERE created >= '" . $start_time .
"' AND created <= '". $end_time . "'";
?>Drupal使用数据库帮助函数来执行数据库查询。所以,你只需要去写你的数据库SQL语句而不需要担心后面具体是怎样执行的。
我们将用db_query()(例如数据库行)来得到满足我们SQL查询的记录,并用db_fetch_object()去查看具体每一条记录:
<?php
// get the links
$queryResult = db_query($query);
// content variable that will be returned for display
$block_content = '';
while ($links = db_fetch_object($queryResult)) {
$block_content .= l($links->title, 'node/' . $links->nid) . '<br />';
}
// check to see if there was any content before setting up
// the block
if ($block_content == '') {
/* No content from a week ago. If we return nothing, the block
* doesn't show, which is what we want. */
return;
}
// set up the block
$block['subject'] = 'On This Date';
$block['content'] = $block_content;
return $block;
}
?>注意,实际的URL要包含在l()函数里面。l函数可以生成<a href="link">连接,通过调整URL不仅可以设置成干净的URL连接:http://(sitename)/node/2, 还可以生成这种http://(sitename)/?q=node/2的形式。
同时,我们返回一个包含'主题'和'内容'('subject' and 'content')元素的数组。这就是Drupal希望的从区块函数里得到的东西。如果不包含这些,区块将不能正确运行。
你应该还注意到内容和版面设计混合在一起的编程手段。如果你要为其他人来写模块,你应该为其他人(特别是那些不是程序员的人)提供一种可以很简单就可以调整内容版面的方法。一种简单的方法就是在你的连接里包含类属性,或者围绕着标签的并且有模块专用的CSS类,但不必要在连接最后加上。我们在这里先忽视这一点,但是在为他人写模块的时候应该注意这点问题。
把上面所说的都放到一起,我们的区块函数将是这样的:
<?php
function onthisdate_block($op='list', $delta=0) {
// listing of blocks, such as on the admin/block page
if ($op == "list") {
$block[0]["info"] = t("On This Date");
return $block;
} else if ($op == 'view') {
// our block content
// content variable that will be returned for display
$block_content = '';
// Get today's date
$today = getdate();
// calculate midnight one week ago
$start_time = mktime(0, 0, 0,$today['mon'],
($today['mday'] - 7), $today['year']);
// we want items that occur only on the day in question, so
//calculate 1 day
$end_time = $start_time + 86400;
// 60 * 60 * 24 = 86400 seconds in a day
$query = "SELECT nid, title, created FROM " .
"{node} WHERE created >= '" . $start_time .
"' AND created <= '". $end_time . "'";
// get the links
$queryResult = db_query($query);
while ($links = db_fetch_object($queryResult)) {
$block_content .= l($links->title, 'node/'.$links->nid) . '<br />';
}
// check to see if there was any content before setting up the block
if ($block_content == '') {
// no content from a week ago, return nothing.
return;
}
// set up the block
$block['subject'] = 'On This Date';
$block['content'] = $block_content;
return $block;
}
}
?>把上述代码加到你的模块文件里。我们的模块现在就有功能了 - 我们可以安装,启动并且测试它了。
原文:http://drupal.org/node/82963