You are here

8自定义动作:获取节点上面的第一个分类术语

admin 的头像
Submitted by admin on 星期四, 2015-09-17 07:45

作者:老葛,北京亚艾元软件有限责任公司,http://www.yaiyuan.com

我们前面实现了一个动作,通过追加面包屑链接,我们可以构建完整的面包屑对象了。做到这里,就基本上可以满足大部分实际需要了,只不过配置的过程比较麻烦一些,可能需要为每个内容类型分别配置面包屑。而我们的目标是建立基于分类的面包屑,而且构建起来,通用一些,这样模块的易用性就更高一些。所以我们这里借鉴一下Custom breadcrumbs里面的部分代码,从一个节点上面智能的获取第一个分类术语,然后以它为基础,构建面包屑。

首先,向breadcrumb2_rules_action_info追加一下代码:

/**

 * Implements hook_rules_action_info().

 */

function breadcrumb2_rules_action_info() {

  $items = array();

…..

  $items['breadcrumb2_fetch_lightest_term_from_node'] = array(

    'label' => t('Fetch lightest term from node'),

    'group' => t('Breadcrumb2'),

    'parameter' => array(

      'node' => array(

        'type' => 'node',

        'label' => t('Node'),

        'wrapped' => TRUE,

        'save' => FALSE,

      ),

    ),

    'base' => 'breadcrumb2_rules_fetch_lightest_term_from_node',

    'access callback' => 'breadcrumb2_rules_integration_access',

    'provides' => array(

      'lightest_term' => array(

    'type' => 'taxonomy_term',

    'label' => t('First term'),

      ),

    ),

  );

  

  return $items;

}

这里,我们定义了一个新的动作,从节点上面获取第一个分类术语,参数只有一个node,动作的逻辑处理函数为breadcrumb2_rules_fetch_lightest_term_from_node;访问控制回调函数还是原来定义的。注意,这里面,我们使用了'provides',用来向rules提供一个新的可用的变量,这个变量的名字为lightest_term,数据类型为taxonomy_term,标签为'First term'(第一个分类术语)。如果动作需要返回一个变量的话,就需要用到这里的'provides',我这是第一次用这个参数。

接下来,我们看一下breadcrumb2_rules_fetch_lightest_term_from_node

/**

 * Action: Fetch lightest term from node.

 */

function breadcrumb2_rules_fetch_lightest_term_from_node(EntityDrupalWrapper $node) {

  $term = breadcrumb2_node_get_lightest_term($node->value());

  if(!empty($term)){

    $term = taxonomy_term_load($term->tid);

  }

  return array('lightest_term' => $term);

}

这个动作里面的逻辑也非常简单,当然我们这里面,把重活都交给了帮助函数breadcrumb2_node_get_lightest_term。这个函数怎么来的呢?是从custom_breadcrumbs模块中复制过来的,我们只是把函数名的前缀,改成了我们自己的而已。

 

/********************Helper Function *************************************/  

 

/**

 * Returns the lightest term for a given node.

 * Copy from custom_breadcrumbs_taxonomy module.

 *

 * If the term has parents, then the lightest parent's weight is used for the

 * term weight. And if the parent has multiple child terms at different depths,

 * the deepest child term will be returned. If the child terms have the same

 * depth, then the lightest child term is returned.

 *

 * @param $node

 *   The node object.

 *

 * @return

 *   The taxonomy term object.

 */

function breadcrumb2_node_get_lightest_term($node) {

  $terms = breadcrumb2_node_get_terms($node);

  if (!empty($terms)) {

    if (count($terms) > 1) {

      foreach ($terms as $term) {

        // Only consider terms in the lightest vocabulary.

        if (!isset($vid)) {

          $vid = $term->vid;

        }

        elseif ($term->vid != $vid) {

          continue;

        }

        // If the term has parents, the weight of the term is the weight of the lightest parent.

        $parents = taxonomy_get_parents_all($term->tid);

        $depth = count($parents);

        if ($depth > 0) {

          $parent = array_pop($parents);

          $weight = $parent->weight;

        }

        else {

          $weight = $term->weight;

        }

        if ((isset($lweight) && ($weight < $lweight)) || !isset($lweight)) {

          $lterm = $term;

          $lweight = $weight;

          $ldepth = $depth;

        }

        elseif (isset($lweight) && ($weight == $lweight)) {

          // If the node has multiple child terms with the same parent, choose the child with the greatest depth.

          if ($depth > $ldepth) {

            $lterm = $term;

            $ldepth = $depth;

          }

          elseif ($depth == $ldepth) {

            // If the terms have the same depth, pick the term with the lightest weight.

            $lterm = ($lterm->weight < $term->weight) ? $lterm : $term;

          }

        }

      }

      return $lterm;

    }

    else {

      return array_pop($terms);

    }

  }

}

 

/**

 * Copy from custom_breadcrumbs_taxonomy module.

 * Finds all terms associated with a node.

 * This is a D7 Replacement for Drupal 6 taxonomy_node_get_terms.

 */

function breadcrumb2_node_get_terms($node, $key = 'tid') {

  static $terms;

  if (isset($node->nid) && isset($node->vid)) {

    if (!isset($terms[$node->vid][$key])) {

      $query = db_select('taxonomy_index', 'r');

      $t_alias = $query->join('taxonomy_term_data', 't', 'r.tid = t.tid');

      $v_alias = $query->join('taxonomy_vocabulary', 'v', 't.vid = v.vid');

      $query->fields( $t_alias );

      $query->condition("r.nid", $node->nid);

      $query->orderBy('v.weight');

      $query->orderBy('t.weight');

      $query->orderBy('t.name');

      $result = $query->execute();

      $terms[$node->vid][$key] = array();

      foreach ($result as $term) {

        $terms[$node->vid][$key][$term->$key] = $term;

      }

    }

    return $terms[$node->vid][$key];

  }

  return array();

}

breadcrumb2_node_get_terms负责获取一个节点上面的所有分类术语,breadcrumb2_node_get_lightest_term从这些分类术语当中,按照特定的规则,找出第一个分类术语。在Drupal6里面,有个函数taxonomy_node_get_terms,可以用来获取节点上面的所有术语,但是这个函数在Drupal7里面没有了。另外需要注意的是,我们是从表taxonomy_index中获取数据的,在这个数据库表中,维护了节点分类术语之间的对应关系。我以前使用custom breadcrumbs模块的时候,修改过它们这里的代码,所以就把它们偷过来了。用孔乙己的话说,对程序员来说,这叫借,不叫偷。

好了,现在清除缓存,添加动作,就可以看到这个动作了。选中这个动作,进入配置页面,系统智能的为我们的参数选择了node

图片1.png 

其它都不用修改,注意这里提供的变量,与前面代码的对应关系。保存这里的设置,我们现在就可以使用变量“First term (lightest_term)”了。现在,我们就可以再追加一个面包屑链接了。这是追加的链接:

图片2.png 

现在,我们创建一个词汇表(product_category),并添加以下分类术语:

图片3.png 

接着创建一个内容类型product,并为其添加一个分类字段,引用的词汇表就是刚刚创建的。接着,我们创建一个产品,分类术语选择A11,这个时候系统会总动的帮助我们创建一个面包屑对象。面包屑的显示效果:

图片4.png 

如果这里,能够把A11 的父术语AA1也都显示出来,效果就完美了。注意,现在面包屑链接中的路径,还没有在内部定义,根据实际需要可以调整。


Drupal版本: