在 Drupal 6 中使用暴露的表单元素创建自定义视图过滤器
Views是一个了不起的模块,但有时您可能会遇到某些限制,使生活变得困难。例如,我创建了一个视图,根据不同的分类术语拉入一堆节点。问题是我在不同的词汇表中使用了多个分类术语来过滤结果,这基本上导致term_data表中的相同字段用于两个分类过滤器。因此,无论我如何更改参数,我始终没有收到任何结果。我确实尝试将第二项添加为参数,但不可能使用视图参数进行LIKE匹配。
经过一番摸索,我决定需要为第二个元素创建一个自定义视图过滤器。这将在节点和term_data表之间创建第二个连接,并允许我使用LIKE匹配对其进行过滤。使用这种方法是有意义的,因为我还希望公开元素,以便用户可以输入搜索词来限制查看结果。接下来是如何使用视图API设置自定义视图过滤器以及关联的公开表单元素。
我们需要的第一件事是实现,HOOK_views_api()以便视图知道模块启用了视图。这些函数挂钩需要添加到模块中,以便您可以使用现有模块或创建新模块。
/** * Implentation of HOO_views_api() * * @return array An associative array of views options. */ function mymodule_views_api() { return array( 'api' => 2.0 ); }
在我们可以指向我们的视图过滤器处理程序之前,我们必须首先通过包含一个HOOK_views_handlers()钩子让视图知道它们在哪里。在这里,我们定义了一个处理程序类,它将对我们的查询对象进行所需的更改并添加到表单元素中。请注意,路径设置为当前模块中名为views的目录。
/** * * Register the views handlers with the view. * * @return array An associative array of options. */ function mymodule_views_handlers() { return array( 'info' => array( 'path' => drupal_get_path('module', 'mymodule') . '/views', ), 'handlers' => array( 'mymodule_special_data_filter_view' => array( 'parent' => 'views_handler_filter', ), ), ); }
接下来我们需要的是的实现HOOK_views_data(),它将告诉Views各种事情,但在这种情况下,我们将告诉Views关于我们的过滤器。该函数应该返回一个项目的关联数组,每个项目都是我们想要实现的过滤器。该数组可能非常大且复杂,带有表和字段定义,但为了简单起见,我通过使用$data数组的“节点”元素将此过滤器绑定到节点表。因此,当我们继续创建节点视图类型时,将出现此过滤器,并将出现在节点过滤器列表中。
这里重要的一点是过滤器元素(它告诉视图定义过滤器)和过滤器处理程序(它将处理我们的过滤器所做的事情)。handler元素包含我们之前创建的一个类的名称,该类将向查询添加额外的连接和where子句。
/** * Implementation of HOOK_views_data * * Tells views about the filters we need to add. * * @return array An associative array of options. */ function mymodule_views_data() { $data = array(); $data['node']['mymodule_special_data'] = array( 'title' => t('Custom Taxonomy Lookup'), 'help' => t('Added to create a second link between the node and taxonomy tables.'), 'filter' => array( 'handler' => 'mymodule_special_data_filter_view', ), ); return $data; }
在您的模块目录中的views子文件夹中创建一个名为mymodule_special_data_filter_view.inc的文件,并定义一个名为mymodule_special_data_filter_view的类。这个类扩展了views_handler_filter并定义了两个方法。该value_form()方法用于为公开的表单小部件创建元素。该query()方法用于在视图中添加(或删除)部分查询。
ensure_my_table(); //其余查询信息在此处 } }
本质上,我们试图添加到查询中的是以下子句。
term_node和节点表之间的左连接,对term_node表使用别名term_node2。
LEFTJOINterm_nodeterm_node2ONnode.vid=term_node2.vid
term_data和term_data表之间的左连接,对term_data表使用别名term_data2。
LEFTJOINterm_dataterm_data2ONterm_node2.tid=term_data2.tid
添加到WHERE子句以限制包含的数据。
AND(UPPER(term_data2.name)LIKEUPPER('%TermName%'))
虽然我花了一些时间来实际跟踪这些信息,但最简单的部分是为公开的过滤器创建表单元素。您需要做的就是添加一个被调用的方法value_form(),然后定义您希望在公开表单中拥有的表单元素。下面将创建一个文本字段,我们可以用它来提取我们的数据。
class mymodule_special_data_filter_view extends views_handler_filter { /** * Shortcut to display the exposed options form. */ function value_form(&$form, &$form_state) { //$options=menu_parent_options(menu_get_menus(FALSE),1); $form['value'] = array( '#type' => 'textfield', '#title' => t('Term Name'), '#default_value' => NULL, ); return $form; } ... SNIP
最后一部分是将代码添加到query()方法中以更改输出的SQL。我在代码中包含了很多注释来清楚地解释发生了什么。本质上,如果用户输入了公开的表单,则此代码会选取该值并添加所需的连接。我还发现我必须添加对$this->query->的调用才能add_table()为term_node表创建别名。如果忽略这一点,则在term_data2和term_node之间完成第二个连接,这使我们回到第一个。
function query() { //确保已设置表别名 $table_alias = $this->ensure_my_table(); //获取期限值 $term_value = check_plain($this->view->exposed_input['mymodule_special_data_filter_view']); //确保设置了术语值。 if ($term_value != '') { /* Query parts to add: 1. LEFT JOIN term_node term_node2 ONnode.vid= term_node2.vid 2. LEFT JOIN term_data term_data2 ON term_node2.tid = term_data2.tid 3. AND (UPPER(term_data2.name) LIKE UPPER('%Term Name%')) */ //添加具有term_node2别名的term_node表,以确保 $this->query->add_table('term_node', NULL, NULL, 'term_node2'); //在term_node和节点表之间添加连接 //这对term_node表使用别名term_node2 $join = new views_join(); $join->construct('term_node', $this->table_alias, 'vid', 'vid', array(), 'LEFT'); $this->query->ensure_table('term_node2', $this->relationship, $join); //在term_data和term_node表之间添加连接 //这对term_data表使用别名term_data2 $join = new views_join(); $join->construct('term_data', 'term_node2', 'tid', 'tid', array(), 'LEFT'); $return = $this->query->ensure_table('term_data2', $this->relationship, $join); //向查询添加where子句 $this->query->add_where($this->options['group'], "(UPPER(term_data2.name) LIKE UPPER('%%%s%%')) ", $term_value); } }
我在这里添加了一个检查,以确保暴露的过滤器中存在一个值供我使用,如果是,那么我进行查询更改,否则代码不会运行。这可能与您的实现不同,因此您需要检查这一行周围发生了什么:
$term_value=check_plain($this->view->exposed_input['mymodule_special_data_filter_view']);
我应该注意,这段代码是专门为我的需要而创建的,我将它包含在这里,因为我花了一段时间才找到所有需要的组件。您的Drupal项目几乎肯定会与我的不同,因此此代码可能无法满足您的要求。