使用开源软件设计、开发和部署协作型 Web 站点,第 14 部分: announcemen...

来源:百度文库 编辑:神马文学网 时间:2024/04/29 02:12:42
在这个文章系列中,在 IBM Internet Technology Group 团队的带领下使用一套可免费获得的软件为虚构的 International Business Council(IBC) 公司设计、开发和部署一个外部网 Web 站点。在本文中,将研究整个系列中作为示例使用的 announcement 模块,展示此模块中的所有函数,这些函数可从一个文件中下载。在最后一期(第 15 部分)中,将简要回顾整个系列。
本文研究在本系列中作为示例使用的 announcement 模块的源代码。这里讨论这个模块中的所有函数;大多数函数是第 6 部分 “在 Drupal 中构建定制模块” 中描述的 hook 接口的实现。这个模块是用 Drupal 4.7 编写的。下一篇文章(第 15 部分)将介绍如何将这个模块从 Drupal 4.7 迁移到 5.0。
这是 hook_help 的实现。这个函数让 announcement 模块能够向 Drupal 界面提供文档。(细节参见http://api.drupal.org/api/HEAD/function/hook_help。)
输入参数:$section
决定界面的哪个部分正在请求帮助内容。在这里,我们在管理界面 admin/modules#description 下返回模块描述的内容,并在表单的顶部添加一个新的公告 node/add#announcement。
返回值
一个包含帮助内容的字符串。
function announcement_help($section) { switch ($section) { case 'admin/modules#description': return t('Enables the creation of announcement pages ' . 'that are presented on the home page.'); case 'node/add#announcement': return t('An Announcement. Use this page to add an announcement page.'); } }
这是 hook_perm 的实现。这个函数提供 announcement 模块定义的权限。可以在 Drupal 用户权限管理页面上选择这些权限,从而限制通过 announcement 模块执行的操作。(细节参见http://api.drupal.org/api/HEAD/function/hook_perm。)
返回值
用来标识允许执行的操作的字符串数组。
function announcement_perm() { return array('create announcement', 'edit announcement'); }
定义一个或多个节点类型的模块都需要这个函数。它使 Drupal 能够判断 announcement 模块节点类型的名称和属性。(细节参见http://api.drupal.org/api/HEAD/function/hook_node_info。)
返回值
关于模块的节点类型的信息数组。至少需要返回可读的模块名、用来构建 hook 函数名的 Drupal 模块名以及对节点类型的简短描述。
function announcement_node_info() { return array('announcement' => array( 'name' => 'Announcement', 'description' => 'An Announcement. Use this page to add an announcement page.', 'module' => 'announcement')); }
这是 hook_access 的实现。这个函数使 announcement 模块能够根据当前执行的操作和 Drupal 用户权限管理页面上定义的权限,限制对它定义的节点类型的访问。(细节参见http://api.drupal.org/api/HEAD/function/hook_access。)
输入参数:$op
当前执行的 Drupal 操作。在这里,我们希望控制对 “create”、“view”、“update” 和 “delete” 操作的访问。
输入参数:$node
将执行此操作的节点对象。
返回值
一个布尔值,表示是否可以执行此操作。
function announcement_access($op, $node) { global $user; if ($op == 'create') { return user_access('create announcement'); } else if ($op == 'view') { return user_access('access content'); } else if ($op == 'update' || $op == 'delete') { if($user->uid == $node->uid || user_access('edit announcement')) { return true; } else { return false; } } else { return false; } }
这是 hook_menu 的实现。这个函数使 announcement 模块能够注册 URL 路径并判断如何处理这些请求。根据注册,可以将链接放在菜单中,也可以作为选项卡放在页面顶部。(细节参见http://api.drupal.org/api/HEAD/function/hook_menu。)
注意:对于版本 5.X,不使用 hook_settings 函数在管理 UI 中生成论坛,而是需要注册 URL 路径 admin/settings/announcement 来映射到创建这个表单的回调函数。
输入参数:$may_cache
这是一个布尔值,用来决定注册的 URL 路径是否应该缓存。通常情况下,包含某些动态值的 URL 路径不应该缓存。
返回值
注册的 URL 路径对象的数组。其中至少包含注册的 URL 路径、用作路径标题的文本字符串、通过测试访问列表建立的访问标志、用来决定应该如何使用这个注册的类型以及在请求这个 URL 路径时应该调用的回调函数的名称。
function announcement_menu($may_cache) { $items = array(); if ($may_cache) { $items[] = array('path' => 'announcements/add', 'title' => t('Add a new Announcement'), 'access' => node_access('create', 'announcement'), 'type' => MENU_CALLBACK, 'callback arguments' => array('announcement'), 'callback' => 'node_add'); $items[] = array('path' => 'announcements', 'title' => t('Announcements'), 'access' => user_access('access content'), 'type' => MENU_CALLBACK, 'callback' => 'announcement_all'); } else { $items[] = array('path' => 'announcements/pager', 'title' => t('Announcements Pager Example'), 'access' => user_access('administer site'), 'type' => MENU_CALLBACK, 'callback' => 'announcement_pager'); if(is_numeric(arg(1))) { $node = node_load(arg(1)); $items[] = array('path' => 'announcements/' . arg(1), 'title' => t('View an Announcement'), 'access' => node_access('view', $node), 'type' => MENU_CALLBACK, 'callback' => 'node_page'); $items[] = array('path' => 'announcements/' . arg(1) . '/view', 'title' => t('View an Announcement'), 'access' => node_access('view', $node), 'type' => MENU_CALLBACK, 'callback' => 'node_page'); $items[] = array('path' => 'announcements/' . arg(1) . '/edit', 'title' => t('Edit an Announcement'), 'access' => node_access('edit', $node), 'type' => MENU_CALLBACK, 'callback' => 'node_page'); $items[] = array('path' => 'announcements/' . arg(1) . '/delete', 'access' => node_access('delete', $node), 'type' => MENU_CALLBACK, 'callback' => 'node_delete_confirm'); } } return $items; }
这个函数构建一套主题化的链接(称为 pager),它们链接到标明页号的公告列表的每一页。这常常放在每个标明页号的页面底部。
返回值
一个用来显示 pager 的 XHTML 字符串。
function announcement_pager() { $result = pager_query(db_rewrite_sql("SELECT n.nid, n.created FROM {node} n " . "WHERE type = 'announcement' ORDER BY n.created DESC"), variable_get('default_nodes_main', 10)); while ($announcement = db_fetch_object($result)) { $output .= node_view(node_load($announcement->nid), 1); } $output .= theme('pager', NULL, variable_get('default_nodes_main', 10)); return $output; }
这是 hook_cron 的实现。这个函数使 announcement 模块能够在 cron.php 脚本运行(常常是通过 cron 系统)时插入自己的操作。这在执行周期性异步任务时很有用,比如在当前的情况中检查是否有公告过期了。我们使用这个 hook 将过期的公告标为未发布(unpublished),这样的话,非管理员用户就不能通过标准的节点机制在站点上看到它们。(细节参见http://api.drupal.org/api/HEAD/function/hook_cron。)
function announcement_cron() { $queryResult = db_query("UPDATE {node} AS n INNER JOIN {announcement} AS a " . "ON n.nid = a.nid SET n.status = 0 " . "WHERE n.type='announcement' AND n.status = 1 AND " . "a.expiration_date < %d", time()); }
这是 hook_link 的实现。这个函数使 announcement 模块能够将自己的链接插入 Drupal 生成的内容的特定部分中。在这个示例中,根据当前用户的访问权限,将 Add、Edit 和 Delete 链接添加到 Drupal 显示的公告中。(细节参见http://api.drupal.org/api/HEAD/function/hook_link。)
输入参数:$type
一个表示请求的链接类型的字符串。在这个示例中,就是放在公告节点下面的链接。
输入参数:$node
当前请求的节点对象。
输入参数:$teaser
一个布尔值,表示是显示整个公告,还是显示它的摘要。
返回值
l() 函数创建的链接对象的数组。
function announcement_link($type, $node = NULL, $teaser = FALSE) { global $user; $links = array(); if($type == 'node' && $node->type == 'announcement') { if(node_access('create', 'announcement')) { $links[] = l(t('Add'), "node/add/announcement", array('title' => t('Add a new announcement'))); } if(node_access('update', $node)) { $links[] = l(t('Edit'), "announcements/$node->nid/edit", array('title' => t('Edit Announcement ') . $node->title)); $links[] = l(t('Delete'), "announcements/$node->nid/delete", array('title' => t('Delete Announcement ') . $node->title)); } } return $links; }
这是 hook_settings 的实现。这个函数提供一个管理界面,用来控制 announcement 模块的各种设置。(细节参见http://api.drupal.org/api/4.7/function/hook_settings。)
注意:Drupal V5 中不使用这个 hook(http://drupal.org/node/64279#hook-settings)。
返回值
一个 Drupal Forms API 格式的元素数组描述,用来呈现设置界面。
function announcement_settings() { $form = array(); $form['announcement_block_max_list_count'] = array('#type' => 'textfield', '#title' => t('Maximum number of block announcements'), '#default_value' => variable_get('announcement_block_max_list_count', 3), '#description' => t('The maximum number of items listed in the announcement block'), '#required' => FALSE, '#weight' => 0 ); $form['announcement_display_classification'] = array('#type' => 'checkbox', '#title' => t('Display additional announcement classification'), '#default_value' => variable_get('announcement_display_classification', 1), '#description' => t('Insert the additional classification in the announcement modules'), '#required' => FALSE, '#weight' => 0 ); return $form; }
这是 hook_form 的实现。当要创建或编辑公告时,调用这个函数来创建要显示的表单。(细节参见http://api.drupal.org/api/HEAD/function/hook_form。)
输入参数:$node
要创建或编辑的节点。
返回值
一个 Drupal Forms API 格式的元素数组描述,用来呈现公告表单。
function announcement_form(&$node) { if ($node->expiration_date == NULL) { $node->expiration_date = time() + (365 * 86400); } if ($node->publish_date == NULL) { $node->publish_date = time(); } $form['title'] = array('#type' => 'textfield', '#title' => t('Title'), '#default_value' => $node->title, '#description' => t('Title of the announcement'), '#required' => TRUE, '#weight' => 1 ); $form['publication'] = array('#type'=> 'fieldset', '#collapsible' => FALSE, '#title' => t('Publication dates'), '#weight' => 5 ); $form['publication']['publish_date'] = array( '#prefix' => '
', '#suffix' => '
', '#type' => 'date', '#title' => t('Publication date'), '#default_value' => _announcement_unixtime2drupaldate($node->publish_date) ); $form['publication']['expiration_date'] = array( '#prefix' => '
', '#suffix' => '
', '#type' => 'date', '#title' => t('Expiration date'), '#default_value' => _announcement_unixtime2drupaldate($node->expiration_date) ); $form['abstract'] = array('#type' => 'textarea', '#title' => t('Abstract'), '#default_value' => $node->abstract, '#rows' => 3, '#description' => t('Short summary of the full announcement'), '#required' => TRUE, '#weight' => 9 ); $form['body'] = array('#type' => 'textarea', '#title' => t('Body'), '#default_value' => $node->body, '#description' => t('Full content for the announcement which is shown ' . 'with the abstract on the details page'), '#required' => TRUE, '#weight' => 10 ); return $form; }
这个函数创建一个主题化的公告列表。对于一般用户,只显示没有过期的公告。如果用户有权编辑公告,则显示所有公告。
返回值
显示所有公告的格式化内容。
function announcement_all() { if (user_access('edit announcement')) { $queryResult = db_query( "SELECT n.nid FROM node n INNER JOIN announcement a ON n.nid = a.nid " . "WHERE n.type='announcement' ORDER BY n.sticky DESC, A.publish_date DESC"); } else { $queryResult = db_query( "SELECT n.nid FROM node n INNER JOIN announcement a ON n.nid = a.nid " . "WHERE n.type='announcement' AND a.expiration_date > %d " . "ORDER BY n.sticky DESC, a.publish_date DESC", date("U")); } $page_content = array(); $page_content[] = "

Announcements

"; while ($announcement = db_fetch_object($queryResult)) { $announcement = node_load($announcement->nid); $announcement->url = url('announcements/' . $announcement->nid); $page_content[] = theme('announcement_compact', $announcement); } return implode('', $page_content); }
这是 hook_view 的实现。这个函数使 announcement 模块能够在 Drupal 系统显示任何公告节点之前添加额外的变量。在这里,我们将公告细节的 URL 插入公告节点对象。(细节参见http://api.drupal.org/api/HEAD/function/hook_view。)
输入参数:$node
要显示的节点。
输入参数:$teaser
是生成摘要,还是整个节点。
输入参数:$page
节点是否显示为单独的页面,也就是是否应该显示页面标题。
返回值
修改后的节点对象。
function announcement_view(&$node, $teaser = FALSE, $page = FALSE) { if ($page) { $node->url = url('announcements/' . $node->nid); } }
这是 hook_validate 的实现。当用户提交了创建或编辑表单之后,调用这个函数。在这里,我们检查过期日期是否在发布日期之后。(细节参见http://api.drupal.org/api/HEAD/function/hook_validate。)
输入参数:$node
要检验的节点。
function announcement_validate($node) { if ($node) { $publish_date = _announcement_drupaldate2unixtime($node->publish_date); $expiration_date = _announcement_drupaldate2unixtime($node->expiration_date); if ($publish_date >= $expiration_date) { form_set_error('publish_date', t('The publish date of an announcement must be before its expiration date.')); } } }
这是 hook_submit 的实现。这个函数使 announcement 模块能够在将数据保存到数据库中之前修改节点对象信息。在这里,我们将日期值转换为整数,并确保公告按照分类法正确地分类。(细节参见http://api.drupal.org/api/HEAD/function/hook_submit。)
输入参数:$node
要提交到数据库的节点。
function announcement_submit(&$node) { $node->publish_date = _announcement_drupaldate2unixtime($node->publish_date); $node->expiration_date = _announcement_drupaldate2unixtime($node->expiration_date); $now = time(); if($now > $node->publish_date && $now < $node->expiration_date) { $node->status = 1; } else { $node->status = 0; } $vocab = announcement_get_vocabulary_by_name('IBC'); $term = taxonomy_get_term_by_name('announcements'); $node->taxonomy = _announcement_merge_tid($vocab->vid, $term[0]->tid, $node->taxonomy); }
这个 helper 函数返回与给定的词汇表名称对应的词汇表对象。
输入参数:$name
要获取的词汇表的名称。
返回值
词汇表对象。
function announcement_get_vocabulary_by_name ($name) { $results = db_query('SELECT * FROM {vocabulary} WHERE name = "%s"', $name); if (db_num_rows($results) > 0) { return db_fetch_object($results); } else { return null; } }
这是一个本地函数(由函数名前面的下划线表示),它合并词汇表中的词汇。
输入参数:$vid
词汇表 id。
输入参数:$tid
词汇 id。
输入参数:$taxonomy
词汇所属的分类法。
返回值
更新后的分类法。
function _announcement_merge_tid($vid, $tid, $taxonomy) { $values = array_values($taxonomy[$vid]); // get all tid values for vocabulary if (!in_array($tid, $values)) { // if the tid is not there $taxonomy[] = $tid; // add it } return $taxonomy; }
这是 hook_load 的实现。这个函数使 announcement 模块能够在公告节点对象中添加额外的数据。在这里,我们合并来自 announcement 表的相关日期。(细节参见http://api.drupal.org/api/HEAD/function/hook_load。)
输入参数:$node
要从数据库装载的节点。
返回值
返回来自数据库的任何额外值,这些值将合并进节点中。
function announcement_load(&$node) { $additions = db_fetch_object(db_query('SELECT * FROM {announcement} ' . 'WHERE nid = %d', $node->nid)); return $additions; }
这是 hook_insert 的实现。这个函数使 announcement 模块能够在将新节点插入数据库时执行操作。在这里,我们使用节点对象中的数据在 announcement 表中插入一个新记录。(细节参见http://api.drupal.org/api/HEAD/function/hook_insert。)
输入参数:$node
要插入数据库中的节点。
function announcement_insert($node) { db_query("INSERT INTO {announcement} (nid, abstract, publish_date, expiration_date) " . "VALUES (%d, '%s', '%d', '%d')", $node->nid, $node->abstract, $node->publish_date, $node->expiration_date); }
这是 hook_update 的实现。这个函数使 announcement 模块能够在数据库更新现有的公告节点时执行操作。在这里,我们执行自己的数据库更新,比如将信息放进 announcement 表中。(细节参见http://api.drupal.org/api/HEAD/function/hook_update。)
输入参数:$node
数据库中要更新的节点。
function announcement_update($node) { db_query("UPDATE {announcement} SET abstract='%s', publish_date = '%s', " . "expiration_date = '%s' WHERE nid = %d", $node->abstract, $node->publish_date, $node->expiration_date, $node->nid); }
这是 hook_delete 的实现。这个函数使 announcement 模块能够在数据库中删除公告节点时执行操作。(细节参见http://api.drupal.org/api/HEAD/function/hook_delete。)
输入参数:$node
要从数据库中删除的节点。
function announcement_delete($node) { db_query('DELETE FROM {announcement} WHERE nid = %d', $node->nid); }
这是 hook_block 的实现。这个函数定义两个提供给 Drupal 系统的区块。站点管理员可以使用 Drupal 界面根据需要选择将它们放在页面上的什么位置。第一个区块列出最近更新的公告,第二个区块使用第 11 部分 “在 Drupal 中使用分类法” 中描述的 IBC 词汇表按类别列出公告。(细节参见http://api.drupal.org/api/HEAD/function/hook_block。)
输入参数:$op
要获取的关于公告区块的信息种类。
输入参数:$delta
要返回的区块号。
输入参数:$edit
如果 $op 是 ‘save’,那么这个变量包含提交的区块配置表单数据。
返回值
如果 $op 是 ‘list’,那么它返回一个数组的数组,每个子数组必须定义一个描述区块的 info 元素。如果 $op 是 ‘view’,那么它返回一个数组,这个数组定义 ‘subject’ 和 ‘content’ 元素,这些元素定义以 $delta 为索引的区块。
function announcement_block($op = 'list', $delta = 0, $edit = array()) { global $user; if ($op == 'list') { $blocks[0]['info'] = t('Recently updated announcements'); $blocks[1]["info"] = t('List nodes in the IBC vocabulary'); return $blocks; } else if ($op == 'view') { $block = array(); switch ($delta) { case 0: $announcement_items = array(); if (user_access('access content')) { $q = 'SELECT N.uid,N.nid,N.title,A.publish_date,N.status '. 'FROM {node} N JOIN {announcement} A USING(nid) '. "WHERE N.type='announcement' ". 'AND N.status = 1 '. 'AND A.publish_date < %d ' . 'AND A.expiration_date > %d ' . 'ORDER BY A.publish_date DESC '; $now = time(); $items = variable_get('announcement_block_max_list_count', 3); $announcements = db_query_range($q, $now, $now, 0, $items); while (db_num_rows($announcements) > 0 and $announcement = db_fetch_object($announcements)) { $announcement_items[] = $announcement; } } $block['subject'] = t('Announcements'); $block['content'] = theme('announcement_block_list', $announcement_items); break; case 1: if (user_access("access content")) { $vocabulary = announcement_get_vocabulary_by_name('IBC'); $block["subject"]= t('IBC'); $block["content"]= announcement_vocab_vert($vocabulary->vid); } } return $block; } }
这个函数来自 taxonomy_dhtml 模块,用来构建在按照词汇表分类的节点区块中显示的内容。它构建一个数组,其中包含当前词汇的所有子词汇。在 HREF 中构建正确的 or 值时需要这个函数。
输入参数:$vocabulary_id
词汇表的 ID。
输入参数:$op
一个可以添加进列出的节点 URL 的操作。
返回值
用来显示区块的内容。
function announcement_vocab_vert($vocabulary_id, $op = NULL) { $tree = taxonomy_get_tree($vocabulary_id); foreach ($tree as $term) { $url = "taxonomy/term/$term->tid"; if ($op) { $url .= "/$op"; } $link = l(t($term->name), $url, array("title" => t($term->description))); $out .= _taxonomy_depth($term->depth, " ")."- $link"; $count = taxonomy_term_count_nodes($term->tid); if ($count) { $out .= " ($count)"; $out .= _announcement_by_terms($term->tid); } else { $out .= " (0)"; } $out .= "
"; } return $out; }
这个本地函数返回一个主题化的链接列表,它们链接到与给定的词汇表词汇对应的公告。
输入参数:$tid
要呈现的词汇的 ID。
返回值
要输出的词汇。
function _announcement_by_terms($tid) { $result = ''; $tids = array( $tid ); $nodes = taxonomy_select_nodes($tids, 'or', 0, FALSE); while ($r = db_fetch_object($nodes)) { $url = "announcements/". $r->nid; $result .= "
  -  " . l($r->title, $url, array("title" => t($r->title))); } return $result; }
这是 hook_nodeapi 的实现。这个函数使 announcement 模块能够在 Drupal 意识到要执行特定操作时执行适当操作。在这里,如果当前的 Drupal 操作是 “update index”,就将这个公告的摘要添加到搜索索引中。(细节参见http://api.drupal.org/api/HEAD/function/hook_nodeapi。)
输入参数:$node
要处理的节点。
输入参数:$op
节点上要执行的操作,比如 “delete”、“update index”。
返回值
这取决于我们需要的操作,在我们的示例中返回要添加进索引的节点信息。
function announcement_nodeapi(&$node, $op) { switch ($op) { case 'update index': if ($node->type == 'announcement') { $text = ''; $q = db_query( 'SELECT a.abstract FROM node n LEFT JOIN announcement a ON '. 'n.nid = a.nid WHERE n.nid = %d', $node->nid); if ($r = db_fetch_object($q)) { $text = $r->abstract; } return $text; } } }
主题设计人员可以使用以下函数改变这个模块生成数据的方式。有两类主题函数:
theme_announcement
泛型的主题函数,适用于所有主题和主题引擎
phptemplate_announcement
由 phptemplate 引擎使用的主题函数
对于本系列来说,我们不在默认主题函数中插入任何数据构造代码,而是关注如何覆盖 phptemplate 主题函数来构造数据。通常情况下,这些 phptemplate 函数放在主题目录中的 phptemplate.php 文件中。
function theme_announcement($announcement) { return ''; } function theme_announcement_compact($announcement) { return ''; } function theme_announcement_block_list($announcement_list) { return ''; } function phptemplate_announcement($announcement) { return _theme_phptemplate_announcement($announcement, 'announcement'); } function phptemplate_announcement_compact($announcement) { return _theme_phptemplate_announcement ($announcement, 'announcement_compact'); } function phptemplate_announcement_block_list($announcement_list) { global $user; return _phptemplate_callback('announcement_block_list', array('announcements' => $announcement_list, 'user'=> $user)); } function _theme_phptemplate_announcement ($announcement, $announcement_template) { $expired = FALSE; if ($announcement->expiration_date < time()) { $expired = TRUE; } $variables = array( 'title' => $announcement->title, 'body' => $announcement->body, 'links' => $announcement->links ? theme('links', $announcement->links) : '', 'abstract' => $announcement->abstract, 'published' => format_date($announcement->publish_date,'custom','j M, Y'), 'expires' => format_date($announcement->expiration_date,'custom','j M, Y'), 'expired' => $expired, 'node' => $announcement ); return _phptemplate_callback($announcement_template, $variables); }
这是一个本地实用程序函数,它将一个包含日期的结构化数据数组转换为整数。
输入参数:$drupal_date
一个用数组表示的日期,数组中包含日、月和年信息。
返回值
日期的整数表示。
function _announcement_drupaldate2unixtime($drupal_date) { $year = $drupal_date["year"]; $month = $drupal_date["month"]; $day = $drupal_date["day"]; return mktime(0,0,0, (int)$month, (int)$day, (int)$year); }
这是一个本地实用程序函数,它将日期的整数表示转换为结构化数据数组。
输入参数:$unixtime
日期的整数表示。
返回值
一个用数组表示的日期,数组中包含日、月和年信息。
function _announcement_unixtime2drupaldate($unixtime) { return array('day' => format_date($unixtime, 'custom', 'j'), 'month' => format_date($unixtime, 'custom', 'n'), 'year' => format_date($unixtime, 'custom', 'Y')); }


将这篇文章提交到 Digg

发布到 del.icio.us

提交到 Slashdot!

本文介绍了 announcement 模块。除了提供下载文件之外,还描述了每个函数,提供了关于所使用的 Drupal hook 函数的更多信息。我们希望本文能够回答关于 announcement 模块源代码的一些常见问题。
下一篇文章是本系列的最后一篇,将总结已经学到的知识并展望 Drupal 5 的发展方向。




回页首
描述 名字 大小 下载方法
announcement 模块源代码 announcement.module 24KBHTTP

关于下载方法的信息
学习
您可以参阅本文在 developerWorks 全球站点上的英文原文 。
Eclipse:了解关于这种开放式开发平台的所有信息。
Eclipse PHP 调试器:进一步了解这个项目。
HTMLtidy:了解 HTML Tidy 程序的维护和进一步开发。
phpDocumentor:PHP 语言当前的标准自动文档工具。
阅读developerWorks 体系架构专区 中的参考资料来提高 IT 体系结构方面的技能。
随时关注developerWorks 技术活动和网络广播。
浏览技术书店 中关于这些主题和其他技术主题的图书。
本系列的 RSS feed。(了解关于RSS 的更多知识。)
获得产品和技术
下载Zend 调试器。
使用IBM 试用软件 构建您的下一个开发项目,这些软件可以从 developerWorks 直接下载。
讨论
参与论坛讨论。
通过参与developerWorks blog 加入 developerWorks 社区。



Alister Lewis-Bowen 是 IBM 的 Internet Technology Group 的高级软件工程师。他从 1993 年开始作为 IBM 英国职员从事互联网和 Web 技术方面的工作。Alister 后来到美国为 IBM 赞助的体育活动的 Web 站点工作,之后成为 ibm.com 的高级网管。他当前正在帮助创建语义 Web 原型。可以通过alister@us.ibm.com 联系 Alister。



Louis Weitzman 是 IBM 的 Internet Technology Group 的高级软件工程师。他从事设计和计算已经有 30 年了。他曾经帮助开发 ibm.com 使用的基于 XML 片段的内容管理系统,当前正在从事将设计过程融入新项目的工作。可以通过louisw@us.ibm.com 联系 Louis。



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

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)
将您的建议发给我们或者通过参加讨论与其他人分享您的想法.

使用开源软件设计、开发和部署协作型 Web 站点,第 14 部分: announcemen... 使用开源软件设计、开发和部署协作型 Web 站点,第 5 部分: Drupal 入门 使用开源软件设计、开发和部署协作型 Web 站点,第 13 部分: Eclipse 中的 ... 使用开源软件设计、开发和部署协作型 Web 站点,第 10 部分: 外部网 Web 站点的... 使用开源软件设计、开发和部署协作型 Web 站点,第 12 部分: 主机托管和部署 使用开源软件设计、开发和部署协作型 Web 站点,第 12 部分: 主机托管和部署 使用开源软件设计、开发和部署协作型 Web 站点,第 11 部分: 使用 Drupal 中... 使用开源软件设计、开发和部署协作型 Web 站点,第 8 部分: 使用 CSS 对主题化内... 使用开源软件设计、开发和部署协作型 Web 站点,第 1 部分: 简介和概述 使用开源软件设计、开发和部署协作型 Web 站点,第 4 部分: 在 Linux 中建立开... 使用开源软件设计、开发和部署协作型 Web 站点,第 2 部分: 设计有效的用户体验 使用开源软件设计、开发和部署协作型 Web 站点,第 6 部分: 在 Drupal 中构建... 使用开源软件设计、开发和部署协作型 Web 站点,第 3 部分: 在 Windows 中建... 使用开源软件设计、开发和部署协作型 Web 站点 .NET开发资源站点和部分优秀.NET开源项目 使用Ant进行Web开发(第二部分) 创建新的门户: 第 5 部分:开发、构建和部署门户 使用 PHP 和 DHTML 设计 Web 2.0 应用程序,第 1 部分: 使用这些技术打造有特色的应用 使用 PHP 和 DHTML 设计 Web 2.0 应用程序,第 2 部分: 使用 JavaScript 创建 HTML 动态元素 使用 PHP 和 DHTML 设计 Web 2.0 应用程序,第 2 部分: 使用 JavaScript 创建 HTML 动态元素 使用 Portlet Builder 开发和部署门户组件 使用 Axis2 和 JiBX 将 Java 类转换成 Web 服务,第 1 部分: 使用 XML 通过 Java 类定义 Web 服务 使用 WSDL 部署 Web 服务 使用 Spring Framework 设计和开发 SCA 组件,第 1 部分: 三剑客:Spring、SCA 和 Apache Tuscany