8eeb1f9b6a18d17dc5d34986d9d06971d6772476
[yaffs-website] / web / core / modules / taxonomy / src / Plugin / views / argument / IndexTidDepth.php
1 <?php
2
3 namespace Drupal\taxonomy\Plugin\views\argument;
4
5 use Drupal\Core\Database\Query\Condition;
6 use Drupal\Core\Entity\EntityStorageInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
9 use Drupal\views\Plugin\views\argument\ArgumentPluginBase;
10 use Symfony\Component\DependencyInjection\ContainerInterface;
11
12 /**
13  * Argument handler for taxonomy terms with depth.
14  *
15  * This handler is actually part of the node table and has some restrictions,
16  * because it uses a subquery to find nodes with.
17  *
18  * @ingroup views_argument_handlers
19  *
20  * @ViewsArgument("taxonomy_index_tid_depth")
21  */
22 class IndexTidDepth extends ArgumentPluginBase implements ContainerFactoryPluginInterface {
23
24   /**
25    * @var \Drupal\Core\Entity\EntityStorageInterface
26    */
27   protected $termStorage;
28
29   /**
30    * {@inheritdoc}
31    */
32   public function __construct(array $configuration, $plugin_id, $plugin_definition, EntityStorageInterface $termStorage) {
33     parent::__construct($configuration, $plugin_id, $plugin_definition);
34
35     $this->termStorage = $termStorage;
36   }
37
38   /**
39    * {@inheritdoc}
40    */
41   public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
42     return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity.manager')->getStorage('taxonomy_term'));
43   }
44
45   protected function defineOptions() {
46     $options = parent::defineOptions();
47
48     $options['depth'] = ['default' => 0];
49     $options['break_phrase'] = ['default' => FALSE];
50     $options['use_taxonomy_term_path'] = ['default' => FALSE];
51
52     return $options;
53   }
54
55   public function buildOptionsForm(&$form, FormStateInterface $form_state) {
56     $form['depth'] = [
57       '#type' => 'weight',
58       '#title' => $this->t('Depth'),
59       '#default_value' => $this->options['depth'],
60       '#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).'),
61     ];
62
63     $form['break_phrase'] = [
64       '#type' => 'checkbox',
65       '#title' => $this->t('Allow multiple values'),
66       '#description' => $this->t('If selected, users can enter multiple values in the form of 1+2+3. Due to the number of JOINs it would require, AND will be treated as OR with this filter.'),
67       '#default_value' => !empty($this->options['break_phrase']),
68     ];
69
70     parent::buildOptionsForm($form, $form_state);
71   }
72
73   /**
74    * Override defaultActions() to remove summary actions.
75    */
76   protected function defaultActions($which = NULL) {
77     if ($which) {
78       if (in_array($which, ['ignore', 'not found', 'empty', 'default'])) {
79         return parent::defaultActions($which);
80       }
81       return;
82     }
83     $actions = parent::defaultActions();
84     unset($actions['summary asc']);
85     unset($actions['summary desc']);
86     unset($actions['summary asc by count']);
87     unset($actions['summary desc by count']);
88     return $actions;
89   }
90
91   public function query($group_by = FALSE) {
92     $this->ensureMyTable();
93
94     if (!empty($this->options['break_phrase'])) {
95       $break = static::breakString($this->argument);
96       if ($break->value === [-1]) {
97         return FALSE;
98       }
99
100       $operator = (count($break->value) > 1) ? 'IN' : '=';
101       $tids = $break->value;
102     }
103     else {
104       $operator = "=";
105       $tids = $this->argument;
106     }
107     // Now build the subqueries.
108     $subquery = db_select('taxonomy_index', 'tn');
109     $subquery->addField('tn', 'nid');
110     $where = (new Condition('OR'))->condition('tn.tid', $tids, $operator);
111     $last = "tn";
112
113     if ($this->options['depth'] > 0) {
114       $subquery->leftJoin('taxonomy_term__parent', 'th', "th.entity_id = tn.tid");
115       $last = "th";
116       foreach (range(1, abs($this->options['depth'])) as $count) {
117         $subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.parent_target_id = th$count.entity_id");
118         $where->condition("th$count.entity_id", $tids, $operator);
119         $last = "th$count";
120       }
121     }
122     elseif ($this->options['depth'] < 0) {
123       foreach (range(1, abs($this->options['depth'])) as $count) {
124         $field = $count == 1 ? 'tid' : 'entity_id';
125         $subquery->leftJoin('taxonomy_term__parent', "th$count", "$last.$field = th$count.parent_target_id");
126         $where->condition("th$count.entity_id", $tids, $operator);
127         $last = "th$count";
128       }
129     }
130
131     $subquery->condition($where);
132     $this->query->addWhere(0, "$this->tableAlias.$this->realField", $subquery, 'IN');
133   }
134
135   public function title() {
136     $term = $this->termStorage->load($this->argument);
137     if (!empty($term)) {
138       return $term->getName();
139     }
140     // TODO review text
141     return $this->t('No name');
142   }
143
144 }