第9章 Drupal 区块(Drupal block)(3) 创建区块

No replies
philip
philip's picture
User offline. Last seen 1 day 9 hours ago. Offline
Joined: 04/11/2010
Points: 17022
Groups: 324

创建一个区块

在本例中,你将创建两个区块,它们使得内容修改更易于管理。首先,你将创建一个区块用于列出等待批准的评论,然后你将创建一个区块以列出未发布的节点。两个区块都提供了用于修改相应内容的编辑表单的链接。

让我们创建一个名为 approval.module 的模块。它将包含我们的区块代码。在路径 sites/all/modules/custom 下面创建一个名为 approval 的文件夹(如果 modules 和 custom 不存在的话,你需要创建它们)。

接下来,向文件中添加approval.info文件:


; $Id$
name = Approval
description = Blocks for facilitating pending content workflow.
version = "$name$"

然后,在添加 approval.module 文件:


<?php
// $Id$
/**
* @file
* Implements various blocks to improve pending content workflow.
*/

当你创建好这些文件后,在 Administer > Site building > Modules 下面启用该模块。你将继续使用 approval.module,所以不要关闭文本编辑器。

接下来我们添加区块钩子方法并实现 list 操作,我们的区块将出现在区块管理页面的区块列表中(参看图9-5)。


图9-5 在区块列表中,你可以看到你创建的区块了。

注意数组的键 info 不是区块启用时所展示给用户的区块标题。而是一个仅出现在管理员可以配置的区块列表页面的描述。你将在接下来的查看(view)情景中实现真正的区块标题。首先,你需要创建额外的配置选项,为了实现这一点,使用下面的代码来实现配置(configue)情景,你创建了一个新的表单字段,当你点击区块列表页面区块右边的配置链接时,即可看到它,如图9-6所示:


图9-6 带有区块定制字段的区块配置表单

当如图9-6所示的区块配置表单被提交后,它将触发下一步操作,这里是保存,你将使用它来保存表单字段值。


function approval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending comments');
return $blocks;
case 'configure':
$form['approval_block_num_posts'] = array(
'#type' => 'textfield',
'#title' => t('Number of pending comments to display'),
'#default_value' => variable_get('approval_block_num_posts', 5),
);
return $form;
case 'save':
variable_set('approval_block_num_posts',
(int) $edit['approval_block_num_posts']);
break;
}
}

通过使用 Drupal 自带的变量系统 variable_set(),你将区块所展示的评论的数目保存了下来。注意这里使用了类型转换,将其转换为整数,目的是对数据进行清洁检查,最后添加查看操作,当区块显示时,返回一个待定评论的列表。


function approval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending comments');
return $blocks;
case 'configure':
$form['approval_block_num_posts'] = array(
'#type' => 'textfield',
'#title' => t('Number of pending comments to display'),
'#default_value' => variable_get('approval_block_num_posts', 5),
);
return $form;
case 'save':
variable_set('approval_block_num_posts', (int)
$edit['approval_block_num_posts']);
break;
case 'view':
if (user_access('administer comments')) {
// Retrieve the number of pending comments to display that
// we saved earlier in the 'save' op, defaulting to 5.
$num_posts = variable_get('approval_block_num_posts', 5);
// Query the database for unpublished comments.
$result = db_query_range('SELECT c.* FROM {comments} c WHERE c.status = %d ORDER BY c.timestamp', COMMENT_NOT_PUBLISHED, 0, $num_posts);
// Preserve our current location so user can return after editing.
$destination = drupal_get_destination();
$items = array();
while ($comment = db_fetch_object($result)) {
$items[] = l($comment->subject, 'node/'. $comment->nid, array(),
NULL, 'comment-'. $comment->cid). ' '.
l(t('[edit]'), 'comment/edit/'. $comment->cid, array(),
$destination);
}
$block['subject'] = t('Pending comments');
// We theme our array of links as an unordered list.
$block['content'] = theme('item_list', $items);
}
return $block;
}
}

这里我们通过对数据库进行查询来获得待定的评论,将评论的标题展示为链接,同时为每一个评论追加一个编辑链接,如图9-7所示:


图9-7 “待定评论”列表区块在它启用后的情况。它展示了两个待定评论

在前面的代码中,注意我们是如何使用方法 drupal_get_destination() 的,这个方法将记住在你提交表单以前你所在的页面,所以当你更新一个评论以后(或者发布,或者删除),它将自动重定向到你原来所在的页面。

使用下面的代码,设置了区块的标题:


$block['subject'] = t('Pending comments');

现在待定区块已经完成,让我们在 approval_block() 钩子函数中定义另一个区块 - 它列出了所有未发布的节点,并提供了指向它们的编辑页面的链接。


function approval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending comments');
$blocks[1]['info'] = t('Unpublished nodes');
return $blocks;
}
}

注意这里是如何为每一个区块分配一个键值的($blocks[0], $blocks[1], . . . $blocks[n])。区块模块将最终使用这些键值作为 $delta 参数。这里我们将“待定评论”区块的 $delta ID 定义为0,“未发布节点”区块的 $delta ID 定义为1。在这里也可以使用“待定”和“未发布”作为键值。有程序员的习惯决定使用哪种键值,而键值不一定是数字形式。

下面是完整的例子,我们的新区块如图9-8所示:


function approval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending comments');
$blocks[1]['info'] = t('Unpublished nodes');
return $blocks;
case 'configure':
// Only in block 0 (the Pending comments block) can one
// set the number of comments to display.
if ($delta == 0) {
$form['approval_block_num_posts'] = array(
'#type' => 'textfield',
'#title' => t('Number of pending comments to display'),
'#default_value' => variable_get('approval_block_num_posts', 5),
);
}
return $form;
case 'save':
if ($delta == 0) {
variable_set('approval_block_num_posts', (int)
$edit['approval_block_num_posts']);
}
break;
case 'view':
if ($delta == 0 && user_access('administer comments')) {
// Retrieve the number of pending comments to display that
// we saved earlier in the 'save' op, defaulting to 5.
$num_posts = variable_get('approval_block_num_posts', 5);
// Query the database for unpublished comments.
$result = db_query_range('SELECT c.* FROM {comments} c WHERE c.status = %d ORDER BY c.timestamp', COMMENT_NOT_PUBLISHED, 0, $num_posts);
$destination = drupal_get_destination();
$items = array();
while ($comment = db_fetch_object($result)) {
$items[] = l($comment->subject, 'node/'. $comment->nid, array(),
NULL, 'comment-'. $comment->cid). ' '.
l(t('[edit]'), 'comment/edit/'. $comment->cid, array(),
$destination);
}
$block['subject'] = t('Pending Comments');
// We theme our array of links as an unordered list.
$block['content'] = theme('item_list', $items);
}
elseif ($delta == 1 && user_access('administer nodes')) {
// Query the database for the 5 most recent unpublished nodes.
// Unpublished nodes have their status column set to 0.
$result = db_query_range('SELECT title, nid FROM {node} WHERE status = 0 ORDER BY changed DESC', 0, 5);
$destination = drupal_get_destination();
while ($node = db_fetch_object($result)) {
$items[] = l($node->title, 'node/'. $node->nid). ' '. l(t('[edit]'), 'node/'. $node->nid .'/edit', array(), $destination);
}
$block['subject'] = t('Unpublished nodes');
// We theme our array of links as an unordered list.
$block['content'] = theme('item_list', $items);
}
return $block;
}
}


图9-8 区块启用后,列出了未发布节点列表

由于你有多个区块,你查看操作下,你使用了 if…elseif 来构建。在每一种情况下,你检查被查看区块的 $delta 以决定你是否该运行该段代码。在脚本形式里,它看起来如下所示:


if ($delta == 0) {
// Do something to block 0
}
elseif ($delta == 1) {
// Do something to block 1
}
elseif ($delta == 2) {
// Do something to block 2
}

在“未发布节点”区块启用后,区块的最终结果如图9-8所示。

额外例子:添加一个“待定用户”区块

如果你想扩展approval.module,你可以添加另一个区块,以展示等待站点管理员批准的用户帐号。这将作为作业留给读者自己动手将其放到 approval.module模块中去。这里展示了一个在假定的userapproval.module模块中的类似的例子:


function userapproval_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
$blocks[0]['info'] = t('Pending users');
return $blocks;
case 'view':
if (user_access('administer users')) {
$result = db_query_range('SELECT uid, name, created FROM {users} WHERE uid != 0 AND status = 0 ORDER BY created DESC', 0, 5);
$destination = drupal_get_destination();
// Defensive coding: we use $u instead of $user to avoid potential namespace
// collision with global $user variable should this code be added to later.
while ($u = db_fetch_object($result)) {
$items[] = theme('username', $u). ' '.
l('[edit]', 'user/'. $u->uid. '/edit', array(), $destination);
}
$block['subject'] = t('Pending users');
$block['content'] = theme('item_list', $items);
}
return $block;
}
}

在安装模块时,启用一个区块

有时,你想在安装模块时,将一个区块自动展示出来。这非常直接,通过查询语句直接将区块的设置信息直接插入到 blocks 表中即可。查询放在钩子方法 hook_install() 中,钩子方法位于模块的 .install 文件中。下面是一个例子,当 Drupal 被安装时,用户模块启用了用户区块(参看 modules/system/system.install):

db_query("INSERT INTO {blocks} (module, delta, theme, status) VALUES ('user', 0, '%s', 1)", variable_get('theme_default', 'garland'));

上面的数据库查询语句将区块插入到了区块表中,并将它的状态设置为1,所以它被启用了。

区块可视化例子

在区块管理接口里面,你可以在区块配置页面的“页面可视化配置”里面加入 php 代码片段。当一个页面被构建时,Drupal 将运行 php 代码片段来决定区块是否被显示。一些常用的代码片段例子如下所示。每一段代码返回 TRUE 或 FALSE 来指示区块对于特定请求是否可见。

将区块仅展示给登录用户

当 $user->id 不为0时,返回 TRUE


<?php
global $user;
return (bool) $user->uid;
?>

将区块仅展示给匿名用户

当 $user->id 为0时,返回 TRUE


<?php
global $user;
return !(bool) $user->uid;
?>

小结

在本章,你学到了以下几点:

  • 区块是什么以及它们与节点的区别
  • 区块的可视化和位置配置是如何设定的
  • 如何定义一个或多个区块
  • 如何在默认情况下启用区块
lamppr 网站示例:www.tatshanghai.cn tourismthailand.org.cn