Drupal专业开发指南 第14章 使用分类(Taxonomy)

分类是对事物的划分归类。Drupal自带了一个分类模块,它允许你对节点(也就是主要的“事物”)进行分类。在本章中,你将看到Drupal支持的不同种类的分类。你还将看到数据是如何存储的,如何在你自己的模块中查询分类数据库表。最后,你将会看到,当分类改变时,你的模块如何收到相关通知,并且我们将介绍一些常用的分类相关的任务。

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 什么是分类

 

分类涉及到把事物放进不同的类别中。在管理界面“管理➤内容管理➤分类”下面(如果在这里没有的话,请确认启用了分类模块),你将找到Drupal对分类的支持。当涉及到Drupal的分类系统时,用词的准确性是非常重要的。让我们学习一下你将会遇到的一些常用词。
 
术语
    术语就是一个实际的标签,它将要应用到节点之上。例如,假定你有一个包含产品评估的网站。你可以使用术语“劣”,“合格”,“优”来为每个评估加个标签。术语有时也称为标签,将一个术语分配到一个对象(比如说一个产品评估节点)上的动作称之为标签化。
 
抽象层次
    过一会,当你查看数据结构时,你将会看到,Drupal为输入的所有术语添加了一个抽象层次,在内部是通过数字ID来引用它们的,而不是通过名字。例如,如果你输入了前面的那些术语,但是你的经理觉得“差”字儿比“劣”字儿更好一些,没关系。你简单的编辑这个号码为1的术语,将它从“劣”改为“差”,这就可以了。因为Drupal在内部看到的是术语的号码,所以在Drupa内部一切将继续正常工作。
 
同义词
    当你定义一个术语时,你可以输入该术语的同义词;同义词是具有同样语义的又一术语。Drupal中的分类功能允许你输入同义词,并提供了用来存储的数据库表,以及提供了一些实用函数比如taxonomy_get_synonyms($tid)和taxonomy_get_synonym_root($synonym),但是这些功能的用户界面的实现则留给了第3方模块,比如术语表模块(http://drupal.org/project/glossary)。
 
词汇表
    一个词汇表包含了一组术语。Drupal允许你将一个词汇表与一个或多个节点类型关联起来。这一松散的关联,在跨节点类型归类时非常有用。例如,如果你有一个站点,允许用户可以提交旅游相关的游记和图片,那么你可以使用一个词汇表,在里面使用国家名字作为术语;这样你就可以方便的查看带有“比利时”标签的所有游记和图片。词汇表编辑界面如图14-1所示。
 
必须的词汇表
    词汇表可以是必须的,也可以不是必须的。如果一个词汇表是必须的,那么用户在提交节点表单以前必须为节点选择一个术语。如果不是必须的,那么用户提交表单时,可以使用默认术语“没有选择任何选项”。
 
受控的词汇表
    当词汇表中的术语数量被限定时(也就是说,用户不能添加新的术语),此时它被称为受控的词汇表。对于一个受控的词汇表,其中的术语一般都通过下拉选择框显示给用户。当然,管理员,或者拥有管理分类权限的用户可以添加,删除,或者修改术语。
 
标签
    一个标签实际上就是一个术语。然而,“标签化”这个词儿,一般隐含了由网站用户来创建标签这层含义。这与受控的词汇表刚好相反。当用户提交一个节点时,可以输入他们自己的术语,而不是从一个词汇表中选择一个术语。如果术语还不是词汇表的一部分,那么它将被添加进来。在词汇表的编辑界面,如果标签复选框被选中了,那么词汇表的用户界面将显示为一个文本输入框(启用了JavaScript自动完成),而不是受控的词汇表所使用的下拉选择框。
14-1 添加词汇表所用的表单
 
单个VS多个术语
    在词汇表编辑界面,通过使用“多重选择”复选框,Drupal允许你声明,对于一个给定的节点,是使用单个术语还是使用多个术语。如果声明了多个术语,那么节点提交表单中的用户界面也将改变,从简单的下拉选择框变成了多选下拉字段。
 
提示:“多重选择”选项仅仅适用于受控的词汇表,对于启用了标签的词汇表不适用。
 
上层
    当添加或编辑一个术语时,在表单的“高级选项”部分(如图14-2所示),可以选择一个上一层术语。这个在术语之间定义了一个层级关系。
 
14-2. 用来添加术语的表单
 
相关术语
    如果一个词汇表允许使用相关术语,那么当你定义一个新术语或者编辑一个已有术语时,将会显示一个多选字段,这样你就可以从已有术语中选出与该术语相关的了。该字段出现在表单的“高级选项”部分(如图14-2所示)。
 
重量
    每个词汇表都有一个重量,从-10到10(如图14-1所示)。这用来控制词汇表在节点提交表单中的位置。词汇表的重量越小,在词汇表字段集(Vocabularies fieldset)中的位置越靠前;重量越大,位置越靠后。
    每个术语也都有一个重量。术语的重量,是用来决定它在用户下拉选择框中的位置。这一顺序与“管理➤内容管理➤分类➤列出术语”中的一致。
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 分类的种类

 

这有几个不同类型的分类。最简单的仅有一列术语,而最复杂的则有多层级关系。另外,术语可以有同义词或者与其它术语相关。让我们从最简单的开始。
 
单层的
一个仅包含了一列术语的词汇表是非常简单的。表14-1展示了我们如何在一个简单的单层词汇表中对编程语言进行分类,我们将把这个词汇表叫做“编程语言”。
 
表14-1词汇表中的简单术语
术语 ID                   术语名字
1                       C
2                       C++
3                        Cobol
 
分层级的
现在,让我们引入一个概念“层级”,在这里每个术语都可能与其它术语存在一种关系。如表14-2所示。
 
表14-2 词汇表中分层级的术语(子术语位于它们的父术语的下面并缩进)
术语 ID                术语名字
1                   Object-Oriented
2                      C++
3                       Smalltalk
4                  Procedural
5                       C
6                       Cobol
 
14-3明确的展示了这种分层级的关系。在这个例子中,Procedural是一个父亲而Cobol是一个孩子。注意,每个术语都有它自己的ID,这与它是父亲还是孩子没有关系。
14-3 一个分层级的词汇表,其术语之间具有父子关系
   
    当创建术语时,在“添加术语”表单的“高级选项”部分中的上层字段里面,你可以为其选择一个上一层术语,或者你也可以使用拖放来调整术语的位置,这样你就可以将术语安排到层级里面。当添加了多个术语以后,导航到“管理➤内容管理➤分类”,点击该词汇表的“列出术语”连接,你就可以看到托放界面了。托放界面如图14-4所示。
 
14-4.使用托放界面,将术语安排到一个层级中。
 
多层级的
    一个词汇表可以有多个层级而不仅仅是单个层级。这也就是意味着一个术语可以有多个父亲。例如,假定你向你的编程语言词汇表中添加PHP。PHP可以使用过程化的方式编码,但是在最近的版本中,也引入了面向对象的编程能力。我们是把它放到面向对象的下面还是过程化的下面?在多层级关系中,你可以把它放在两者的下面,如图14-5所示
14-5 一个多层级的词汇表中,术语可以有多个父亲
 
       在网站建设的计划阶段,你值得花费大量的时间,用来认真的考虑一下分类的使用情况,以决定你需要使用哪类词汇表。
    因为多层级词汇表无法轻易的显示在用户界面,当你为一个术语选择多个父亲时,Drupal将警告你托放界面将被禁用。警告如图14-6所示。
14-6.为一个术语选择多个父亲将禁用托放界面
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 根据术语查看内容

 

通过访问一个术语的URL,你可以来查看与该术语相关的所有节点,除非模块覆写了这个视图。例如,在URLhttp://example.com/?q=taxonomy/term/5中, 5就是你想要查看的术语的术语ID。结果将是一列标题和摘要,其中的每个节点都使用了该术语作为标签。
 
在URL中使用AND和OR
    分别使用逗号“,”和加号“+”,就可以让构建的分类URL支持AND和OR操作。下面是一些例子。
    为了显示分配给术语ID为5和6的所有节点,可以使用下面的URL:
 
 
    使用下面的URL,来显示分配给术语ID为1或2,或3的所有节点:
 
 
    taxonomy.module对AND和OR的混合使用,目前还没有提供支持。
 
提示:使用路径模块,为你用的这些分类URL设置友好的URL别名,这样它们后面就不会带有那些枯燥的数字了。
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 为分层级的词汇表声明深度

 

在前面的例子中,我们使用了一个隐含的参数。例如,URL
 
    实际上就是
 
    在准备将要显示的结果集时,尾数0就是所要搜索的层级的层次数量;如果参数为all,这意味着将包括所有的层次。假定你有一个分层级的词汇表,如表14-3所示。
 
14-3.一个地理的分层级的词汇表(子术语位于它们父亲的下面,同时缩进)
术语 ID        名字
1           加拿大
2               不列颠哥伦比亚省
3                   温哥华
4               安大略省
5                   多伦多
 
层级的第一层次是国家,加拿大;它有两个孩子,不列颠哥伦比亚省和安大略省。每一个省都包含一个孩子,一个主要的加拿大城市,在那里Drupal开发异常活跃。修改URL中的深度参数,所带来的影响如下所示。
以温哥华为标签的所有节点共用下面的URL:
 
 
为了显示标签为“不列颠哥伦比亚省”(但是没有标签“温哥华”)的所有节点,可以使用下面的URL:
 
 
为了显示标签为“不列颠哥伦比亚省”(包含标签“温哥华”)的所有节点(注意我们这里将深度设为了1),使用下面的URL:
 
 
标签为“加拿大”或者标签为任意一个加拿大省份或者城市的所有节点,都可使用下面的URL来显示:
 
 
注意 结果集是作为一个普通的节点列表来显示的。如果你想将节点的标题和(或)摘要分层级的显示出来,那么你需要编写一个自定义的主题函数,或者使用views模块(http://drupal.org/project/views)。
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 自动的RSS种子

 

每个术语都有一个自动的RSS种子,用来显示标签该术语的最新节点。例如,术语ID 3的种子位于
 
 
    注意深度参数(这里为0)是必须的。和期望的一样,你可以使用AND或者OR来联合术语以创建一个联合的种子,下面是术语2或4的种子,包含了所有的亲儿子(不包括孙子):
 
 
    下面是包含所有子孙术语的种子:
 
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 存储分类

老葛的Drupal培训班 Think in Drupal

如果你不想局限于内置的分类能力,那么这将驱使着你去理解分类在数据库中是如何存储的。在一个典型的非Drupal数据库中,你可能通过向数据库表中简单的添加一列来创建一个单层分类。你已经看到了,Drupal使用普通的数据库表来添加分类。图14-7给出了表结构。
 
14-7 Drupal的分类数据库表:主键使用了粗体;索引字段使用了斜体。term_node表中的*vid,引用的是node_revisions表的版本ID,而不是词汇表ID。
 
     下列表组成了Drupal的分类存储系统:
 
• vocabulary:这个表存储了词汇表的相关信息,通过Drupal的分类界面可以对其进行修改。
 
• vocabulary_node_types: 这个表用来追踪词汇表与节点类型的对应关系。该类型是Drupal内部的节点类型名字(例如,blog),它对应于node表的type列。
 
• term_data: 这个表包含了术语的真实名字,它所在的词汇表,它的可选的描述,以及它的重量,后者用来决定它在术语的下拉选择框中的相对位置(例如,在节点提交表单上)。
 
• term_synonym: 这个表包含了给定术语ID的同义词。
 
• term_relation:当定义一个术语时,这个表用来追踪相关术语的术语ID。
 
• term_hierarchy:这个表包含了术语的术语ID和它父亲的术语ID。如果一个术语位于根部(也就是说,它没有父亲),那么它父亲的ID为0.
 
• term_node: 这个表是用来匹配术语与节点的,节点以该术语为标签。
 

Drupal版本:

Drupal专业开发指南 第14章 基于模块的词汇表

 

除了使用“管理➤内容管理➤分类”创建词汇表以外,模块也可以使用分类数据库表来存储它们自己的词汇表。例如,论坛模块使用分类数据库表来保存一个关于容器和论坛的词汇表。图片模块使用分类数据库表来管理相册。任何时候,当你发现自己需要实现分层级的术语时,你都需要考虑一下,如果使用分类模块和一个基于模块的词汇表,是否会更好一些?
vocabulary表中的module列用来标识哪个模块拥有这一词汇表。一般情况下,这一列将包含taxonomy(分类),这是因为分类模块管理着大多数词汇表。

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 创建一个基于模块的词汇表

 

让我们看一个基于模块的词汇表的例子。第3方的相册模块(包含在图片模块;参看http://drupal.org/project/image)使用分类来管理不同的相册。它通过代码创建了它的词汇表,如下面的例子所示,并且通过将$vocabulary数组的module键设为该模块的名字(不带.module)来锁定该词汇表的所有权。
 
/**
 * Returns (and possibly creates) a new vocabulary for Image galleries.
 */
function _image_gallery_get_vid() {
    $vid = variable_get('image_gallery_nav_vocabulary', '');
    if (empty($vid) || is_null(taxonomy_vocabulary_load($vid))) {
        // Check to see if an image gallery vocabulary exists.
        $vid = db_result(db_query("SELECT vid FROM {vocabulary} WHERE
            module='image_gallery'"));
        if (!$vid) {
            $vocabulary = array(
                'name' => t('Image Galleries'),
                'multiple' => '0',
                'required' => '0',
                'hierarchy' => '1',
                'relations' => '0',
                'module' => 'image_gallery',
                'nodes' => array(
                    'image' => 1
                )
            );
            taxonomy_save_vocabulary($vocabulary);
            $vid = $vocabulary['vid'];
        }
        variable_set('image_gallery_nav_vocabulary', $vid);
    }
 
    return $vid;
}
 老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 为术语提供自定义路径

老葛的Drupal培训班 Think in Drupal

如果你的模块负责维护一个词汇表,你可能想为该模块控制的术语提供自定义路径,来代替由taxonomy.module提供的默认路径taxonomy/term/[term id]。当为一个术语生成一个链接时,调用taxonomy.module中的taxonomy_term_path()函数(你应该调用这个函数,而不是自己为分类术语创建链接;不要假定分类模块维护了该分类)。注意,在下面的代码中,它是如何检查哪个模块拥有该词汇表的:
 
/**
 * For vocabularies not maintained by taxonomy.module, give the maintaining
 * module a chance to provide a path for terms in that vocabulary.
 *
 * @param $term
 * A term object.
 * @return
 * An internal Drupal path.
 */
function taxonomy_term_path($term) {
    $vocabulary = taxonomy_get_vocabulary($term->vid);
    if ($vocabulary->module != 'taxonomy' &&
        $path = module_invoke($vocabulary->module, 'term_path', $term)) {
            return $path;
    }
    return 'taxonomy/term/'. $term->tid;
}
 
    例如,image_gallery.module将路径重定向为了image/tid/[term id]:
 
function image_gallery_term_path($term) {
    return 'image/tid/'. $term->tid;
}

Drupal版本:

Drupal专业开发指南 第14章 使用hook_taxonomy()来获悉词汇表的变更

老葛的Drupal培训班 Think in Drupal

如果你为你自己的模块保留了一个词汇表,当使用标准的分类用户界面修改你的词汇表时,那么你将想收到词汇表的相关修改信息。对于由taxonomy.module维护的已有的一个词汇表,当它被修改时,你可能也想收到相关的修改信息。在任何一种情况下,通过实现hook_taxonomy(),当词汇表变更时你都会收到相应的通知。下面的模块实现了hook_taxonomy(),当词汇表变更时,你将会收到电子邮件通知。下面是taxonomymonitor.info文件:
 
; $Id$
name = Taxonomy Monitor
description = Sends email to notify of changes to taxonomy vocabularies.
package = Pro Drupal Development
dependencies[] = taxonomy
core = 6.x
 
    下面是taxonomymonitor.module:
 
<?php
// $Id$
 
/**
 * Implementation of hook_taxonomy().
 *
 * Sends email when changes to vocabularies or terms occur.
 */
function taxonomymonitor_taxonomy($op, $type, $array = array()) {
    $to = 'me@example.com';
    $name = check_plain($array['name']);
 
    // $type is either 'vocabulary' or 'term'.
    switch ($type) {
        case 'vocabulary':
            switch($op) {
                case 'insert':
                    $subject = t('Vocabulary @voc was added.', array('@voc' => $name));
                    break;
                case 'update':
                    $subject = t('Vocabulary @voc was changed.', array('@voc' => $name));
                    break;
                case 'delete':
                    $subject = t('Vocabulary @voc was deleted.', array('@voc' => $name));
                    break;
            }
            break;
        case 'term':
            switch($op) {
                case 'insert':
                    $subject = t('Term @term was added.', array('@term' => $name));
                    break;
                case 'update':
                    $subject = t('Term @term was changed.', array('@term' => $name));
                    break;
                case 'delete':
                    $subject = t('Term @term was deleted.', array('@term' => $name));
                    break;
            }
    }
 
    // Dump the vocabulary or term information out and send it along.
    $body = print_r($array, TRUE);
 
    // Send the email.
    watchdog('taxonomymonitor', 'Sending email for @type @op',
        array('@type' => $type, '@op' => $op));
    drupal_mail('taxonomymonitor-notify', $to, $subject, $body);
}
 
    对于一些额外的功能,比如将变更者的名字也包含进来,你可以修改这一模块来实现自己的需求。

Drupal版本:

Drupal专业开发指南 第14章 常见任务

老葛的Drupal培训班 Think in Drupal

下面是一些常见任务, 在你使用分类时可能会碰到。

 
在一个节点对象中查找分类术语
通过在taxonomy.module中实现hook_nodeapi(),在node_load()期间分类术语被加载到节点对象中。实际负责从数据库中取回术语的是taxonomy_node_get_terms()函数。这将生成一个包含术语对象的数组,它放在节点的taxonomy键中:
 
print_r($node->taxonomy);
 
Array (
[3] => stdClass Object (
[tid] => 3
[vid] => 1
[name] => Vancouver
[description] => By Land, Sea, and Air we Prosper.
[weight] => 0 )
)
 
构建你自己的分类查询
如果你需要生成一个某种类别的节点列表,你可能希望一切都简单一些;你可能希望Drupal将分类术语保存在node表中,那样你就可以使用下面的SQL了:
 
SELECT * FROM node WHERE vocabulary = 1 and term = 'cheeseburger'
 
灵活性是有代价的,Drupal的分类很灵活,但是Drupal开发者在使用时需要多做一些工作。在Drupal中你不能使用这么简单的查询,你必须学习使用JOIN来查询分类数据库表。
 
使用taxonomy_select_nodes()
 
在你开始编写一个查询以前,你需要考虑一下,使用一个已有的函数是否也能够得到你想要的。例如,如果你想得到标签为术语ID 5和6的节点的标题,你可以使用taxonomy_select_nodes():
 
$tids = array(5, 6);
$result = taxonomy_select_nodes($tids, 'and');
$titles = array();
while ($data = db_fetch_object($result)) {
    $titles[] = $data->title;
}

Drupal版本:

Drupal专业开发指南 第14章 分类函数

老葛的Drupal培训班 Think in Drupal

下面的部分将解释在你的模块可能用到的分类常用函数。
 
取回词汇表的相关信息
下面所列的内置函数用来取回词汇表的相关信息,返回的可以是词汇表数据对象或者是包含这样对象的数组。
 
taxonomy_ vocabulary_load($vid)
这个函数取回单个词汇表(参数$vid是该词汇表的ID),返回的是一个词汇表对象。它还在内部缓存了词汇表对象,这样多次调用同一个词汇表并不费事。这个加载函数在Drupal的菜单系统中也非常有用(详细可参看第4章)。
 
taxonomy_get_vocabularies($type)
taxonomy_get_vocabularies($type)函数取回所有的词汇表对象。参数$type将取回的词汇表限定在给定的节点类型上;比如,blog。这个函数返回一个词汇表对象数组。
 

Drupal版本:

Drupal专业开发指南 第14章 添加、修改、和删除词汇表

老葛的Drupal培训班 Think in Drupal

下面的函数用于创建、修改、和删除词汇表。它们返回一个状态代码,代码为Drupal常量SAVED_UPDATED、SAVED_NEW、或SAVED_DELETED中的一个。
 
taxonomy_save_vocabulary(&$vocabulary)
这个函数用来创建一个新的词汇表或者更新一个已有的词汇表。参数$vocabulary是一个关联数组(注意它不是一个词汇表对象!),包含以下键:
 
• name: 词汇表的名字。
 
• description: 词汇表的描述。
 
• help: 一个帮助文本,在节点创建表单中,它显示在这个词汇表字段的下面。
 
• nodes: 一个数组,包含了这个词汇表适用的所有节点类型。
 
• hierarchy: 0表示没有层级,1表示单个层级,2表示多个层级。
 
• relations: 0表示禁用相关术语, 1表示允许相关术语。
 
• tags: 0表示禁用自由标签化, 1表示启用自由标签化。
 
• multiple: 0表示禁用术语的多选,1表示启用多选。
 
• required: 0表示节点被提交前术语是可选的(这将引入一个默认的“没有选择任何选项”术语), 1表示节点提交前术语是必选的。
 
• weight: 词汇表的重量;它影响它在节点提交表单的词汇表字段集里面的位置。
 
• module: 负责这个词汇表的模块的名字。如果没有传递这个键,那么它的值默认为taxonomy
 
• vid: 词汇表ID。如果没有传递这个键,那么将创建一个新的词汇表。
 
taxonomy_save_vocabulary(&$vocabulary)函数返回SAVED_NEW 或者 SAVED_UPDATED。
 
taxonomy_del_vocabulary($vid)
这个函数的参数$vid是词汇表的ID。删除一个词汇表的同时,会删除词汇表中的所有术语,通过为每个术语调用taxonomy_del_term()来删除术语。taxonomy_del_vocabulary($vid)函数返回SAVED_DELETED。

Drupal版本:

Drupal专业开发指南 第14章 取回术语的相关信息

 

下面所列的内置函数用来取回术语的相关信息,返回的一般是对象或者是包含对象的数组。
 
taxonomy_get_term($tid)
这个函数取回一个术语(参数$tid是词语的ID),返回的是一个术语对象。它在内部缓存了术语对象,所以对同一术语的多次调用并不费事。术语对象的结构如下所示:
 
$term = taxonomy_get_term(5);
var_dump($term);
object(stdClass)#6 (5) {
    ["tid"] => string(1) "3"
    ["vid"] => string(1) "1"
    ["name"]=> string(9) "Vancouver"
    ["description"]=> string(32) "By Land, Sea, and Air we Prosper"
    ["weight"]=> string(1) "0"
}
 
taxonomy_get_term_by_name($text)
taxonomy_get_term_by_name($text)函数搜索匹配一个字符串(参数$text是一个字符串)的所有术语。$text中的空格将被除去,而匹配操作使用的查询为WHERE LOWER(t.name) = LOWER($text)。这个函数返回一个包含术语对象的数组。
 
taxonomy_node_get_terms($nid, $key)
这个函数查找与一个节点相关的所有术语。参数$nid是节点的ID,就是为该节点取回术语的;而参数$key默认为tid,它有点难以理解,它影响结果返回的方式。taxonomy_node_get_terms($nid, $key)返回一个数组的数组,以$key为键。因此,结果数组在默认情况下是以术语ID为键的,但是你也可以替换为term_data表(tid, vid, name, description, weight)中的任意一列。这个函数会为每个节点在内部缓存结果。
 
提示 对于传递进来的节点,这里只用到了它的属性$node->vid。如果你知道节点(为其取回术语)的版本ID,那么你可以使用一个伪造的带有$vid属性的节点对象,这样就避免调用费事的node_load()函数了,例如,$fake_node = new stdClass(); $fake_node->$vid = 12;
$terms = taxonomy_node_get_terms($fake_node);。
 
taxonomy_node_get_terms_by_vocabulary($nid, $vid, $key)
这个函数将在一个词汇表($vid)中查找与一个节点($nid)相关的所有术语。更多信息,可参看taxonomy_node_get_terms($nid, $key)中参数$key的描述。
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 添加,修改,和删除术语

老葛的Drupal培训班 Think in Drupal

下面的函数用于创建、修改、和删除术语。它们返回一个状态代码,代码为Drupal常量SAVED_UPDATED、SAVED_NEW、或SAVED_DELETED中的一个。
 
taxonomy_save_term(&$term)
    这个函数创建一个新的术语或者更新一个已有的术语。参数$term是一个关联数组(注意它不是一个术语对象!),包含以下键:
 
• name: 术语的名字。
 
• description: 术语的描述。Drupal的默认用户界面中用不到该值,但是可能在你的模块中或者其它的第3方模块中用到它。
 
• vid: 术语所在词汇表的ID。
 
• weight: 术语的重量。它影响术语下拉选择框中各个术语的相对位置。
 
• relations: 一个可选的数组,包含了相关术语的ID。
 
• parent: 既可以是一个字符串,用来代表父术语的术语ID;也可以是一个数组,其元素既可以是字符串,也可以是子数组,其中字符串为用来代表父术语的术语ID,子数组则是包含这样字符串的数组。
 
• synonyms: 一个可选的字符串,包含了以换行字符(\n)分隔的同义词。
 
• tid: 术语的ID。如果没有传递这个键,那么将创建一个新的术语。
 
    这个函数返回SAVED_NEW 或者 SAVED_UPDATED。
 
taxonomy_del_term($tid)
taxonomy_del_term($tid)函数用来删除一个术语;参数$tid是术语ID。如果一个术语是在一个分层级的词汇表中,并且具有子术语,那么子术语也将被删除,除非子术语拥有多个父术语。

Drupal版本:

Drupal专业开发指南 第14章 取回术语层级的相关信息

老葛的Drupal培训班 Think in Drupal

当使用分层级的词汇表时,下面的函数会非常有用。
 
taxonomy_get_parents($tid, $key)
这个函数查找一个术语的上一层父亲;参数$tid是术语ID。参数$key默认为tid,它是term_data表(tid, vid, name,description, weight)中的一列。taxonomy_get_parents($tid, $key)返回一个包含术语对象的关联数组,以$key为键。
 
taxonomy_get_parents_all($tid)
这个函数找出一个术语的所有祖先;参数$tid是术语ID。这个函数返回一个包含术语对象的数组。
 
taxonomy_get_children($tid, $vid, $key)
taxonomy_get_children($tid, $vid, $key)函数查找一个术语的所有孩子。参数$tid是术语ID。参数$vid是可选的;如果一个词汇表的ID传了进来,那么该术语的孩子将被限制在这个词汇表中(注意,只有当术语有多个父亲,而父术语又位于不同的词汇表中时,这才有用,但是这种情况很少见)。参数$key默认为tid,它是term_data表(tid, vid, name,description, weight)中的一列。这个函数返回一个包含术语对象的关联数组,其中以$key为键。
 
taxonomy_get_tree($vid, $parent, $depth, $max_depth)
这个函数生成一个词汇表的分层级的表示。参数$vid就是词汇表ID,就是为词汇表生成术语树的。如果你不想为一个词汇表生成一个完整的术语树,而只想生成一个以$parent术语ID为根的子树,那么你可以声明参数$parent。参数$depth是内部使用的参数,默认为-1。参数$max_depth是一个整数,用来指出返回的树的层次数,它默认为NULL,这意味着所有的层次。这个函数返回了一个包含术语对象的数组,这里向术语对象添加了depthparents键。depth键是一个整数,用来指示术语在树中所处的层次;而parents键是一个数组,包含了术语父亲的术语ID。让我们以表14-3所列的词汇表为例,它的词汇表ID为2,让我们获得它的结果:
 
$vid = 2;
print_r($taxonomy_get_tree($vid));
 
结果如下:
Array (
    [0] => stdClass Object (
        [tid] => 1
        [vid] => 2
        [name] => Canada
        [description] => A mari usque ad mare.
        [weight] => 0
        [depth] => 0
        [parents] => Array (
            [0] => 0 )
    )
    [1] => stdClass Object (
        [tid] => 4
        [vid] => 2
        [name] => Ontario
        [description] => Ut incepit fidelis sic permanet.
        [weight] => 0
        [depth] => 1
        [parents] => Array (
            [0] => 1 )
    )
    [2] => stdClass Object (
        [tid] => 5
        [vid] => 2
        [name] => Toronto
        [description] => Diversity Our Strength.
        [weight] => 0
        [depth] => 2
        [parents] => Array (
            [0] => 4 )
    )
    [3] => stdClass Object (
        [tid] => 2
        [vid] => 2
        [name] => British Columbia
        [description] => Splendor sine occasu.
        [weight] => 0
        [depth] => 1
        [parents] => Array (
            [0] => 1 )
    )
    [4] => stdClass Object (
        [tid] => 3
        [vid] => 2
        [name] => Vancouver
        [description] => By Land, Sea and Air We Prosper.
        [weight] => 0
        [depth] => 2
        [parents] => Array (
            [0] => 2 )
    )
)
 

Drupal版本:

Drupal专业开发指南 第14章 取回术语同义词的相关信息

 

如果你的模块需要实现对同义词的支持,那么下面的函数对你将会有所帮助。
 
taxonomy_get_synonyms($tid)
使用这个函数为一个给定的术语取回包含其同义词的数组。参数$tid是术语ID。函数返回一个字符串数组;每个字符串就是术语的一个同义词。
 
taxonomy_get_synonym_root($synonym)
给参数$synonym一个字符串,这个函数将执行一个针对term_synonym表的精确匹配查询。它返回单个术语对象,表示使用该同义词找到的第一个术语。
 

老葛的Drupal培训班 Think in Drupal

Drupal版本:

Drupal专业开发指南 第14章 查找带有特定术语的节点

老葛的Drupal培训班 Think in Drupal

有时,你想有一种简单的方式,来查询具有特定术语的节点,或者输出这样查询的结果。下面的函数可以帮你实现这一点。
 
taxonomy_select_nodes($tids, $operator, $depth, $pager, $order)
这个函数,将基于给定参数构建一个数据库查询,并执行该查询,来查找匹配特定条件的节点。它返回一个指向查询结果的资源标识符。参数$tids是一个包含术语ID的数组。参数$operator是“or”或者“and”,它用来声明如何解释$tids数组。参数$depth指示在分类树中要遍历的层次深度,默认为0,意味着“不要对$tids中术语的任何孩子进行查找”。将$depth设为1,意味着对$tids中的术语以及它们的第一代子术语进行查找。将$depth设为all,意味着对$tids中术语以及它们的所有子术语进行查找。参数$pager是一个布尔值,用来指示是否要对生成的节点列表使用分页器,它默认为TRUE。如果你要生成一个XML种子,那么你可以将$pager设置为FALSE。参数$order包含了字面上的order语句,用在查询的SQL中,默认为“n.sticky DESC, n.created DESC”。
如果你需要对许多术语进行搜索,那么这个函数是非常耗费数据库资源的。
 
taxonomy_render_nodes($result)
如果你使用taxonomy_select_nodes()来查询匹配特定分类条件的节点,那么我们在这里就可以把taxonomy_render_nodes()作为一个起点,来为你的查询创建一个简单的输出。
 

Drupal版本:

Drupal专业开发指南 第14章 额外资源

老葛的Drupal培训班 Think in Drupal

许多模块在许多地方都使用了分类,比如添加访问控制(http://drupal.org/project/taxonomy_access),动态类别浏览((http://drupal.org/project/taxonomy_browser),在一个区块中根据分类术语显示相关的节点(http://drupal.org/project/similarterms)。Drupal参考手册包含了关于分类的更多信息,http://drupal.org/handbook/modules/taxonomy。分类相关模块的列表,可参看http://drupal.org/project/Modules/category/71
 
    我们鼓励你使用views模块,特别是在主题化分类列表时(http://drupal.org/project/views
 

Drupal版本:

Drupal专业开发指南 第14章 总结

老葛的Drupal培训班 Think in Drupal

读完本章后,你应该能够
• 理解什么是分类
• 理解术语,词汇表,以及它们不同的选项
• 单层的,分层级的,和多层级的词汇表之间的区别
• 构建带有AND 和 OR 操作的URL,来对分类术语进行搜索
• 为分类术语和术语联合体的RSS种子构建URL
• 理解分类是如何存储的
• 知道如何在你自己的模块中使用词汇表
• 创建你的模块来接收分类变更的通知

Drupal版本:

Drupal专业开发指南 第14章 中英文对照

Taxonomy: 分类,分类系统, 分类法

Category: 类别
Categories: 不同的类别
Term:术语
Review:评估
Bad:劣
OK:合格
Excellent:优
Tag:标签
Tagging:标签化。
Level:【计算机科学】 层次
Poor:差
Synonym:同义词
contributed module3方模块
glossary:术语表
vocabulary:词汇表
Controlled Vocabularies:受控的词汇表
administer taxonomy:管理分类
“None selected”: “没有选择任何选项”
Multiple select:多重选择
Parents:上层,父亲
parent term:上一层术语
Related Terms:相关术语
Flat:单层
Hierarchical:分层级的

Hierarchy:层级

 

老葛的Drupal培训班 Think in Drupal

Drupal版本: