对非节点的内容进行索引:hook_update_index()
译者:老葛 Eskalate科技公司
在你需要封装搜索以对非Drupal节点的内容进行搜索时,你可以使用钩子函数正确的钩住索引器并向其中提供你需要的任何文本数据,从而使得Drupal能够搜索到它们。假定你的组织支持一个遗留应用系统,它用来输入和查看最近几年的关于产品的技术文件(note)。由于一些行政原因,你不能完全使用Drupal解决方案来代替这一遗留系统,但是你想在Drupal内部能够对这些技术文件进行搜索。当然可以。让我们假定遗留系统将它的数据放在了名为technote的数据库表中。我们将创建一个简短的模块,它使用hook_update_index()将这个数据库中的信息发送给Drupal的索引器,使用hook_search()将搜索结果展示出来。
注意 如果你想对非Drupal的数据库进行索引的话,更多关于连接多个数据库的信息,可参看第5章。
在sites/all/modules/custom下面创建一个名为legacysearch的文件夹。如果你需要一个用于测试的legacy(遗留)数据库的话,创建一个名为legacysearch.install的文件,并添加以下内容:
<?php
// $Id$
/**
* Implementation of hook_install().
*/
function legacysearch_install() {
switch ($GLOBALS['db_type']) {
case 'mysql':
case 'mysqli':
db_query("CREATE TABLE technote (
id int NOT NULL,
title varchar(255) NOT NULL,
note text NOT NULL,
last_modified int NOT NULL,
PRIMARY KEY (id)
) /*!40100 DEFAULT CHARACTER SET UTF8 */");
db_query("INSERT INTO technote VALUES (1, 'Web 1.0 Emulator',
'<p>This handy product lets you emulate the blink tag but in
hardware...a perfect gift.</p>', 1172542517)");
db_query("INSERT INTO technote VALUES (2, 'Squishy Debugger',
'<p>Fully functional debugger inside a squishy gel case.
The embedded ARM processor heats up...</p>', 1172502517)");
break;
case 'pgsql':
db_query("CREATE TABLE technote (
id int NOT NULL,
title varchar(255) NOT NULL,
note text NOT NULL,
last_modified int NOT NULL,
PRIMARY KEY (id)
) /*!40100 DEFAULT CHARACTER SET UTF8 */");
db_query("INSERT INTO technote VALUES (1, 'Web 1.0 Emulator',
'<p>This handy product lets you emulate the blink tag but in
hardware...a perfect gift.</p>', 1172542517)");
db_query("INSERT INTO technote VALUES (2, 'Squishy Debugger',
'<p>Fully functional debugger inside a squishy gel case.
The embedded ARM processor heats up...</p>', 1172502517)");
break;
}
}
/**
* Implementation of hook_uninstall().
*/
function legacysearch_uninstall() {
db_query('DROP TABLE {technote}');
}
这一模块一般不需要这个安装文件,这是由于遗留数据库已经存在了。我们在这里仅仅用它创建一个遗留数据库表并插入一些测试用的数据。你可以将模块中的查询语句连接到你的已存在的非Drupal表。下面的查询语句都假定了数据存放在非Drupal数据库中,它使用settings.php中$db_url['legacy']定义的数据库链接。
接着,向legacysearch.info添加以下内容:
; $Id$
name = Legacy Search
description = Enables searching of external content within Drupal.
version = "$Name$"
最后,在legacysearch目录下创建legacysearch.module,并向其添加以下代码:
<?php
// $Id$
/**
* @file
* Enables searching of non-Drupal content.
*/
继续,不要关闭你的文本编辑器中的legacysearch.module,我们将向它添加hook_update_index(),从而将遗留数据提供给HTML索引器。在创建了这些文件后,现在你就可以安全的启用你的模块了。
/**
* Implementation of hook_update_index().
*/
function legacysearch_update_index() {
// We define these variables as global so our shutdown function can
// access them.
global $last_change, $last_id;
// If PHP times out while indexing, run a function to save
// information about how far we got so we can continue at next cron run.
register_shutdown_function('legacysearch_update_shutdown');
$last_id = variable_get('legacysearch_cron_last_id', 0);
$last_change = variable_get('legacysearch_cron_last_change', 0);
// Switch database connection to legacy database.
db_set_active('technote');
$result = db_query("SELECT id, title, note, last_modified
FROM {technote}
WHERE (id > %d) OR (last_modified > %d)
ORDER BY last_modified ASC", $last_id, $last_change);
// Switch database connection back to Drupal database.
db_set_active('default');
// Feed the external information to the search indexer.
while ($data = db_fetch_object($result)) {
$last_change = $data->last_modified;
$last_id = $data->id;
$text = '<h1>' . check_plain($data->title) . '</h1>' . $data->note;
search_index($data->id, 'technote', $text);
}
}
每一内容片段被传递给search_index(),一同传递的还有一个标识符(在这里标识符的值来自于遗留数据库表中的ID列),内容的类型(我们将类型设为technote。对Drupal内容索引时类型一般为节点或者用户),还有要被索引的文本。
register_shutdown_function()指定了一个函数,在为请求执行完PHP脚本后执行这一函数。因为在索引完所有内容以前PHP可能会终止运行,所以使用它来追踪最后索引项目的ID。
/**
* Shutdown function to make sure we remember the last element processed.
*/
function legacysearch_update_shutdown() {
global $last_change, $last_id;
if ($last_change && $last_id) {
variable_set('legacysearch_cron_last', $last_change);
variable_set('legacysearch_cron_last_id', $last_id);
}
}
在这个模块中,我们需要实现的最后一个函数是钩子函数hook_search(),它将让我们为为我们的遗留信息使用内置的用户接口。
/**
* Implementation of hook_search().
*/
function legacysearch_search($op = 'search', $keys = NULL) {
switch ($op) {
case 'name':
return t('Tech Notes'); // Used on search tab.
case 'reset':
variable_del('legacysearch_cron_last');
variable_del('legacysearch_cron_last_id');
return;
case 'search':
// Search the index for the keywords that were entered.
$hits = do_search($keys, 'technote');
$results = array();
// Prepend URL of legacy system to each result. Assume a legacy URL
// for a given tech note is http://technotes.example.com/note.pl?3
$legacy_url = 'http://technotes.example.com/';
// We now have the IDs of the results. Pull each result
// from the legacy database.
foreach ($hits as $item) {
db_set_active('technote');
$note = db_fetch_object(db_query("SELECT * FROM {technote} WHERE
id = %d", $item->sid));
db_set_active('default');
$results[] = array(
'link' => url($legacy_url . 'note.pl?' . $item->sid, NULL, NULL, TRUE),
'type' => t('Note'),
'title' => $note->title,
'date' => $note->last_modified,
'score' => $item->score,
'snippet' => search_excerpt($keys, $note->note));
}
return $results;
}
}
在运行完cron并对信息索引以后,就可以搜索技术文件了,如图12-9所示:
图12-8 搜索外部的遗留数据库
总结
读完本章后,你应该可以:
• 创建一个定制的搜索表单
• 理解HTML索引器是如何工作的
• 使用索引器钩子索引各种内容类型