Mercurial > hg > isophonics-drupal-site
comparison core/modules/taxonomy/src/TermStorage.php @ 17:129ea1e6d783
Update, including to Drupal core 8.6.10
author | Chris Cannam |
---|---|
date | Thu, 28 Feb 2019 13:21:36 +0000 |
parents | 4c8ae668cc8c |
children | af1871eacc83 |
comparison
equal
deleted
inserted
replaced
16:c2387f117808 | 17:129ea1e6d783 |
---|---|
1 <?php | 1 <?php |
2 | 2 |
3 namespace Drupal\taxonomy; | 3 namespace Drupal\taxonomy; |
4 | 4 |
5 use Drupal\Core\Entity\EntityInterface; | |
5 use Drupal\Core\Entity\Sql\SqlContentEntityStorage; | 6 use Drupal\Core\Entity\Sql\SqlContentEntityStorage; |
6 use Drupal\Core\Entity\EntityInterface; | |
7 | 7 |
8 /** | 8 /** |
9 * Defines a Controller class for taxonomy terms. | 9 * Defines a Controller class for taxonomy terms. |
10 */ | 10 */ |
11 class TermStorage extends SqlContentEntityStorage implements TermStorageInterface { | 11 class TermStorage extends SqlContentEntityStorage implements TermStorageInterface { |
12 | 12 |
13 /** | 13 /** |
14 * Array of loaded parents keyed by child term ID. | 14 * Array of term parents keyed by vocabulary ID and child term ID. |
15 * | 15 * |
16 * @var array | 16 * @var array |
17 */ | 17 */ |
18 protected $parents = []; | 18 protected $treeParents = []; |
19 | 19 |
20 /** | 20 /** |
21 * Array of all loaded term ancestry keyed by ancestor term ID. | 21 * Array of term ancestors keyed by vocabulary ID and parent term ID. |
22 * | 22 * |
23 * @var array | 23 * @var array |
24 */ | 24 */ |
25 protected $parentsAll = []; | 25 protected $treeChildren = []; |
26 | 26 |
27 /** | 27 /** |
28 * Array of child terms keyed by parent term ID. | 28 * Array of terms in a tree keyed by vocabulary ID and term ID. |
29 * | 29 * |
30 * @var array | 30 * @var array |
31 */ | 31 */ |
32 protected $children = []; | 32 protected $treeTerms = []; |
33 | 33 |
34 /** | 34 /** |
35 * Array of term parents keyed by vocabulary ID and child term ID. | 35 * Array of loaded trees keyed by a cache id matching tree arguments. |
36 * | 36 * |
37 * @var array | 37 * @var array |
38 */ | 38 */ |
39 protected $treeParents = []; | |
40 | |
41 /** | |
42 * Array of term ancestors keyed by vocabulary ID and parent term ID. | |
43 * | |
44 * @var array | |
45 */ | |
46 protected $treeChildren = []; | |
47 | |
48 /** | |
49 * Array of terms in a tree keyed by vocabulary ID and term ID. | |
50 * | |
51 * @var array | |
52 */ | |
53 protected $treeTerms = []; | |
54 | |
55 /** | |
56 * Array of loaded trees keyed by a cache id matching tree arguments. | |
57 * | |
58 * @var array | |
59 */ | |
60 protected $trees = []; | 39 protected $trees = []; |
40 | |
41 /** | |
42 * Array of all loaded term ancestry keyed by ancestor term ID, keyed by term | |
43 * ID. | |
44 * | |
45 * @var \Drupal\taxonomy\TermInterface[][] | |
46 */ | |
47 protected $ancestors; | |
61 | 48 |
62 /** | 49 /** |
63 * {@inheritdoc} | 50 * {@inheritdoc} |
64 * | 51 * |
65 * @param array $values | 52 * @param array $values |
78 /** | 65 /** |
79 * {@inheritdoc} | 66 * {@inheritdoc} |
80 */ | 67 */ |
81 public function resetCache(array $ids = NULL) { | 68 public function resetCache(array $ids = NULL) { |
82 drupal_static_reset('taxonomy_term_count_nodes'); | 69 drupal_static_reset('taxonomy_term_count_nodes'); |
83 $this->parents = []; | 70 $this->ancestors = []; |
84 $this->parentsAll = []; | |
85 $this->children = []; | |
86 $this->treeChildren = []; | 71 $this->treeChildren = []; |
87 $this->treeParents = []; | 72 $this->treeParents = []; |
88 $this->treeTerms = []; | 73 $this->treeTerms = []; |
89 $this->trees = []; | 74 $this->trees = []; |
90 parent::resetCache($ids); | 75 parent::resetCache($ids); |
91 } | 76 } |
92 | 77 |
93 /** | 78 /** |
94 * {@inheritdoc} | 79 * {@inheritdoc} |
95 */ | 80 */ |
96 public function deleteTermHierarchy($tids) { | 81 public function deleteTermHierarchy($tids) {} |
97 $this->database->delete('taxonomy_term_hierarchy') | 82 |
98 ->condition('tid', $tids, 'IN') | 83 /** |
99 ->execute(); | 84 * {@inheritdoc} |
100 } | 85 */ |
101 | 86 public function updateTermHierarchy(EntityInterface $term) {} |
102 /** | |
103 * {@inheritdoc} | |
104 */ | |
105 public function updateTermHierarchy(EntityInterface $term) { | |
106 $query = $this->database->insert('taxonomy_term_hierarchy') | |
107 ->fields(['tid', 'parent']); | |
108 | |
109 foreach ($term->parent as $parent) { | |
110 $query->values([ | |
111 'tid' => $term->id(), | |
112 'parent' => (int) $parent->target_id, | |
113 ]); | |
114 } | |
115 $query->execute(); | |
116 } | |
117 | 87 |
118 /** | 88 /** |
119 * {@inheritdoc} | 89 * {@inheritdoc} |
120 */ | 90 */ |
121 public function loadParents($tid) { | 91 public function loadParents($tid) { |
122 if (!isset($this->parents[$tid])) { | 92 $terms = []; |
123 $parents = []; | 93 /** @var \Drupal\taxonomy\TermInterface $term */ |
124 $query = $this->database->select('taxonomy_term_field_data', 't'); | 94 if ($tid && $term = $this->load($tid)) { |
125 $query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid'); | 95 foreach ($this->getParents($term) as $id => $parent) { |
126 $query->addField('t', 'tid'); | 96 // This method currently doesn't return the <root> parent. |
127 $query->condition('h.tid', $tid); | 97 // @see https://www.drupal.org/node/2019905 |
128 $query->condition('t.default_langcode', 1); | 98 if (!empty($id)) { |
129 $query->addTag('taxonomy_term_access'); | 99 $terms[$id] = $parent; |
130 $query->orderBy('t.weight'); | 100 } |
131 $query->orderBy('t.name'); | 101 } |
132 if ($ids = $query->execute()->fetchCol()) { | 102 } |
133 $parents = $this->loadMultiple($ids); | 103 |
134 } | 104 return $terms; |
135 $this->parents[$tid] = $parents; | 105 } |
136 } | 106 |
137 return $this->parents[$tid]; | 107 /** |
108 * Returns a list of parents of this term. | |
109 * | |
110 * @return \Drupal\taxonomy\TermInterface[] | |
111 * The parent taxonomy term entities keyed by term ID. If this term has a | |
112 * <root> parent, that item is keyed with 0 and will have NULL as value. | |
113 * | |
114 * @internal | |
115 * @todo Refactor away when TreeInterface is introduced. | |
116 */ | |
117 protected function getParents(TermInterface $term) { | |
118 $parents = $ids = []; | |
119 // Cannot use $this->get('parent')->referencedEntities() here because that | |
120 // strips out the '0' reference. | |
121 foreach ($term->get('parent') as $item) { | |
122 if ($item->target_id == 0) { | |
123 // The <root> parent. | |
124 $parents[0] = NULL; | |
125 continue; | |
126 } | |
127 $ids[] = $item->target_id; | |
128 } | |
129 | |
130 // @todo Better way to do this? AND handle the NULL/0 parent? | |
131 // Querying the terms again so that the same access checks are run when | |
132 // getParents() is called as in Drupal version prior to 8.3. | |
133 $loaded_parents = []; | |
134 | |
135 if ($ids) { | |
136 $query = \Drupal::entityQuery('taxonomy_term') | |
137 ->condition('tid', $ids, 'IN'); | |
138 | |
139 $loaded_parents = static::loadMultiple($query->execute()); | |
140 } | |
141 | |
142 return $parents + $loaded_parents; | |
138 } | 143 } |
139 | 144 |
140 /** | 145 /** |
141 * {@inheritdoc} | 146 * {@inheritdoc} |
142 */ | 147 */ |
143 public function loadAllParents($tid) { | 148 public function loadAllParents($tid) { |
144 if (!isset($this->parentsAll[$tid])) { | 149 /** @var \Drupal\taxonomy\TermInterface $term */ |
145 $parents = []; | 150 return (!empty($tid) && $term = $this->load($tid)) ? $this->getAncestors($term) : []; |
146 if ($term = $this->load($tid)) { | 151 } |
147 $parents[$term->id()] = $term; | 152 |
148 $terms_to_search[] = $term->id(); | 153 /** |
149 | 154 * Returns all ancestors of this term. |
150 while ($tid = array_shift($terms_to_search)) { | 155 * |
151 if ($new_parents = $this->loadParents($tid)) { | 156 * @return \Drupal\taxonomy\TermInterface[] |
152 foreach ($new_parents as $new_parent) { | 157 * A list of ancestor taxonomy term entities keyed by term ID. |
153 if (!isset($parents[$new_parent->id()])) { | 158 * |
154 $parents[$new_parent->id()] = $new_parent; | 159 * @internal |
155 $terms_to_search[] = $new_parent->id(); | 160 * @todo Refactor away when TreeInterface is introduced. |
156 } | 161 */ |
157 } | 162 protected function getAncestors(TermInterface $term) { |
163 if (!isset($this->ancestors[$term->id()])) { | |
164 $this->ancestors[$term->id()] = [$term->id() => $term]; | |
165 $search[] = $term->id(); | |
166 | |
167 while ($tid = array_shift($search)) { | |
168 foreach ($this->getParents(static::load($tid)) as $id => $parent) { | |
169 if ($parent && !isset($this->ancestors[$term->id()][$id])) { | |
170 $this->ancestors[$term->id()][$id] = $parent; | |
171 $search[] = $id; | |
158 } | 172 } |
159 } | 173 } |
160 } | 174 } |
161 | 175 } |
162 $this->parentsAll[$tid] = $parents; | 176 return $this->ancestors[$term->id()]; |
163 } | |
164 return $this->parentsAll[$tid]; | |
165 } | 177 } |
166 | 178 |
167 /** | 179 /** |
168 * {@inheritdoc} | 180 * {@inheritdoc} |
169 */ | 181 */ |
170 public function loadChildren($tid, $vid = NULL) { | 182 public function loadChildren($tid, $vid = NULL) { |
171 if (!isset($this->children[$tid])) { | 183 /** @var \Drupal\taxonomy\TermInterface $term */ |
172 $children = []; | 184 return (!empty($tid) && $term = $this->load($tid)) ? $this->getChildren($term) : []; |
173 $query = $this->database->select('taxonomy_term_field_data', 't'); | 185 } |
174 $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid'); | 186 |
175 $query->addField('t', 'tid'); | 187 /** |
176 $query->condition('h.parent', $tid); | 188 * Returns all children terms of this term. |
177 if ($vid) { | 189 * |
178 $query->condition('t.vid', $vid); | 190 * @return \Drupal\taxonomy\TermInterface[] |
179 } | 191 * A list of children taxonomy term entities keyed by term ID. |
180 $query->condition('t.default_langcode', 1); | 192 * |
181 $query->addTag('taxonomy_term_access'); | 193 * @internal |
182 $query->orderBy('t.weight'); | 194 * @todo Refactor away when TreeInterface is introduced. |
183 $query->orderBy('t.name'); | 195 */ |
184 if ($ids = $query->execute()->fetchCol()) { | 196 public function getChildren(TermInterface $term) { |
185 $children = $this->loadMultiple($ids); | 197 $query = \Drupal::entityQuery('taxonomy_term') |
186 } | 198 ->condition('parent', $term->id()); |
187 $this->children[$tid] = $children; | 199 return static::loadMultiple($query->execute()); |
188 } | |
189 return $this->children[$tid]; | |
190 } | 200 } |
191 | 201 |
192 /** | 202 /** |
193 * {@inheritdoc} | 203 * {@inheritdoc} |
194 */ | 204 */ |
199 // children, too. | 209 // children, too. |
200 if (!isset($this->treeChildren[$vid])) { | 210 if (!isset($this->treeChildren[$vid])) { |
201 $this->treeChildren[$vid] = []; | 211 $this->treeChildren[$vid] = []; |
202 $this->treeParents[$vid] = []; | 212 $this->treeParents[$vid] = []; |
203 $this->treeTerms[$vid] = []; | 213 $this->treeTerms[$vid] = []; |
204 $query = $this->database->select('taxonomy_term_field_data', 't'); | 214 $query = $this->database->select($this->getDataTable(), 't'); |
205 $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid'); | 215 $query->join('taxonomy_term__parent', 'p', 't.tid = p.entity_id'); |
216 $query->addExpression('parent_target_id', 'parent'); | |
206 $result = $query | 217 $result = $query |
207 ->addTag('taxonomy_term_access') | 218 ->addTag('taxonomy_term_access') |
208 ->fields('t') | 219 ->fields('t') |
209 ->fields('h', ['parent']) | |
210 ->condition('t.vid', $vid) | 220 ->condition('t.vid', $vid) |
211 ->condition('t.default_langcode', 1) | 221 ->condition('t.default_langcode', 1) |
212 ->orderBy('t.weight') | 222 ->orderBy('t.weight') |
213 ->orderBy('t.name') | 223 ->orderBy('t.name') |
214 ->execute(); | 224 ->execute(); |
252 // Clone the term so that the depth attribute remains correct | 262 // Clone the term so that the depth attribute remains correct |
253 // in the event of multiple parents. | 263 // in the event of multiple parents. |
254 $term = clone $term; | 264 $term = clone $term; |
255 } | 265 } |
256 $term->depth = $depth; | 266 $term->depth = $depth; |
257 unset($term->parent); | 267 if (!$load_entities) { |
268 unset($term->parent); | |
269 } | |
258 $tid = $load_entities ? $term->id() : $term->tid; | 270 $tid = $load_entities ? $term->id() : $term->tid; |
259 $term->parents = $this->treeParents[$vid][$tid]; | 271 $term->parents = $this->treeParents[$vid][$tid]; |
260 $tree[] = $term; | 272 $tree[] = $term; |
261 if (!empty($this->treeChildren[$vid][$tid])) { | 273 if (!empty($this->treeChildren[$vid][$tid])) { |
262 $has_children = TRUE; | 274 $has_children = TRUE; |
291 * {@inheritdoc} | 303 * {@inheritdoc} |
292 */ | 304 */ |
293 public function nodeCount($vid) { | 305 public function nodeCount($vid) { |
294 $query = $this->database->select('taxonomy_index', 'ti'); | 306 $query = $this->database->select('taxonomy_index', 'ti'); |
295 $query->addExpression('COUNT(DISTINCT ti.nid)'); | 307 $query->addExpression('COUNT(DISTINCT ti.nid)'); |
296 $query->leftJoin('taxonomy_term_data', 'td', 'ti.tid = td.tid'); | 308 $query->leftJoin($this->getBaseTable(), 'td', 'ti.tid = td.tid'); |
297 $query->condition('td.vid', $vid); | 309 $query->condition('td.vid', $vid); |
298 $query->addTag('vocabulary_node_count'); | 310 $query->addTag('vocabulary_node_count'); |
299 return $query->execute()->fetchField(); | 311 return $query->execute()->fetchField(); |
300 } | 312 } |
301 | 313 |
302 /** | 314 /** |
303 * {@inheritdoc} | 315 * {@inheritdoc} |
304 */ | 316 */ |
305 public function resetWeights($vid) { | 317 public function resetWeights($vid) { |
306 $this->database->update('taxonomy_term_field_data') | 318 $this->database->update($this->getDataTable()) |
307 ->fields(['weight' => 0]) | 319 ->fields(['weight' => 0]) |
308 ->condition('vid', $vid) | 320 ->condition('vid', $vid) |
309 ->execute(); | 321 ->execute(); |
310 } | 322 } |
311 | 323 |
312 /** | 324 /** |
313 * {@inheritdoc} | 325 * {@inheritdoc} |
314 */ | 326 */ |
315 public function getNodeTerms(array $nids, array $vocabs = [], $langcode = NULL) { | 327 public function getNodeTerms(array $nids, array $vocabs = [], $langcode = NULL) { |
316 $query = db_select('taxonomy_term_field_data', 'td'); | 328 $query = db_select($this->getDataTable(), 'td'); |
317 $query->innerJoin('taxonomy_index', 'tn', 'td.tid = tn.tid'); | 329 $query->innerJoin('taxonomy_index', 'tn', 'td.tid = tn.tid'); |
318 $query->fields('td', ['tid']); | 330 $query->fields('td', ['tid']); |
319 $query->addField('tn', 'nid', 'node_nid'); | 331 $query->addField('tn', 'nid', 'node_nid'); |
320 $query->orderby('td.weight'); | 332 $query->orderby('td.weight'); |
321 $query->orderby('td.name'); | 333 $query->orderby('td.name'); |
349 * {@inheritdoc} | 361 * {@inheritdoc} |
350 */ | 362 */ |
351 public function __sleep() { | 363 public function __sleep() { |
352 $vars = parent::__sleep(); | 364 $vars = parent::__sleep(); |
353 // Do not serialize static cache. | 365 // Do not serialize static cache. |
354 unset($vars['parents'], $vars['parentsAll'], $vars['children'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']); | 366 unset($vars['ancestors'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']); |
355 return $vars; | 367 return $vars; |
356 } | 368 } |
357 | 369 |
358 /** | 370 /** |
359 * {@inheritdoc} | 371 * {@inheritdoc} |
360 */ | 372 */ |
361 public function __wakeup() { | 373 public function __wakeup() { |
362 parent::__wakeup(); | 374 parent::__wakeup(); |
363 // Initialize static caches. | 375 // Initialize static caches. |
364 $this->parents = []; | 376 $this->ancestors = []; |
365 $this->parentsAll = []; | |
366 $this->children = []; | |
367 $this->treeChildren = []; | 377 $this->treeChildren = []; |
368 $this->treeParents = []; | 378 $this->treeParents = []; |
369 $this->treeTerms = []; | 379 $this->treeTerms = []; |
370 $this->trees = []; | 380 $this->trees = []; |
371 } | 381 } |