Version 1
[yaffs-website] / web / core / modules / taxonomy / src / Plugin / views / filter / TaxonomyIndexTidDepth.php
1 <?php
2
3 namespace Drupal\taxonomy\Plugin\views\filter;
4
5 use Drupal\Core\Form\FormStateInterface;
6
7 /**
8  * Filter handler for taxonomy terms with depth.
9  *
10  * This handler is actually part of the node table and has some restrictions,
11  * because it uses a subquery to find nodes with.
12  *
13  * @ingroup views_filter_handlers
14  *
15  * @ViewsFilter("taxonomy_index_tid_depth")
16  */
17 class TaxonomyIndexTidDepth extends TaxonomyIndexTid {
18
19   public function operatorOptions($which = 'title') {
20     return [
21       'or' => $this->t('Is one of'),
22     ];
23   }
24
25   protected function defineOptions() {
26     $options = parent::defineOptions();
27
28     $options['depth'] = ['default' => 0];
29
30     return $options;
31   }
32
33   public function buildExtraOptionsForm(&$form, FormStateInterface $form_state) {
34     parent::buildExtraOptionsForm($form, $form_state);
35
36     $form['depth'] = [
37       '#type' => 'weight',
38       '#title' => $this->t('Depth'),
39       '#default_value' => $this->options['depth'],
40       '#description' => $this->t('The depth will match nodes tagged with terms in the hierarchy. For example, if you have the term "fruit" and a child term "apple", with a depth of 1 (or higher) then filtering for the term "fruit" will get nodes that are tagged with "apple" as well as "fruit". If negative, the reverse is true; searching for "apple" will also pick up nodes tagged with "fruit" if depth is -1 (or lower).'),
41     ];
42   }
43
44   public function query() {
45     // If no filter values are present, then do nothing.
46     if (count($this->value) == 0) {
47       return;
48     }
49     elseif (count($this->value) == 1) {
50       // Sometimes $this->value is an array with a single element so convert it.
51       if (is_array($this->value)) {
52         $this->value = current($this->value);
53       }
54       $operator = '=';
55     }
56     else {
57       $operator = 'IN';# " IN (" . implode(', ', array_fill(0, sizeof($this->value), '%d')) . ")";
58     }
59
60     // The normal use of ensureMyTable() here breaks Views.
61     // So instead we trick the filter into using the alias of the base table.
62     //   See https://www.drupal.org/node/271833.
63     // If a relationship is set, we must use the alias it provides.
64     if (!empty($this->relationship)) {
65       $this->tableAlias = $this->relationship;
66     }
67     // If no relationship, then use the alias of the base table.
68     else {
69       $this->tableAlias = $this->query->ensureTable($this->view->storage->get('base_table'));
70     }
71
72     // Now build the subqueries.
73     $subquery = db_select('taxonomy_index', 'tn');
74     $subquery->addField('tn', 'nid');
75     $where = db_or()->condition('tn.tid', $this->value, $operator);
76     $last = "tn";
77
78     if ($this->options['depth'] > 0) {
79       $subquery->leftJoin('taxonomy_term_hierarchy', 'th', "th.tid = tn.tid");
80       $last = "th";
81       foreach (range(1, abs($this->options['depth'])) as $count) {
82         $subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.parent = th$count.tid");
83         $where->condition("th$count.tid", $this->value, $operator);
84         $last = "th$count";
85       }
86     }
87     elseif ($this->options['depth'] < 0) {
88       foreach (range(1, abs($this->options['depth'])) as $count) {
89         $subquery->leftJoin('taxonomy_term_hierarchy', "th$count", "$last.tid = th$count.parent");
90         $where->condition("th$count.tid", $this->value, $operator);
91         $last = "th$count";
92       }
93     }
94
95     $subquery->condition($where);
96     $this->query->addWhere($this->options['group'], "$this->tableAlias.$this->realField", $subquery, 'IN');
97   }
98
99 }