PageRenderTime 58ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/core/modules/taxonomy/src/TermStorage.php

https://gitlab.com/reasonat/test8
PHP | 373 lines | 235 code | 36 blank | 102 comment | 24 complexity | 3aee2748a052c539a3c8f2659ab7f021 MD5 | raw file
  1. <?php
  2. namespace Drupal\taxonomy;
  3. use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
  4. use Drupal\Core\Entity\EntityInterface;
  5. /**
  6. * Defines a Controller class for taxonomy terms.
  7. */
  8. class TermStorage extends SqlContentEntityStorage implements TermStorageInterface {
  9. /**
  10. * Array of loaded parents keyed by child term ID.
  11. *
  12. * @var array
  13. */
  14. protected $parents = array();
  15. /**
  16. * Array of all loaded term ancestry keyed by ancestor term ID.
  17. *
  18. * @var array
  19. */
  20. protected $parentsAll = array();
  21. /**
  22. * Array of child terms keyed by parent term ID.
  23. *
  24. * @var array
  25. */
  26. protected $children = array();
  27. /**
  28. * Array of term parents keyed by vocabulary ID and child term ID.
  29. *
  30. * @var array
  31. */
  32. protected $treeParents = array();
  33. /**
  34. * Array of term ancestors keyed by vocabulary ID and parent term ID.
  35. *
  36. * @var array
  37. */
  38. protected $treeChildren = array();
  39. /**
  40. * Array of terms in a tree keyed by vocabulary ID and term ID.
  41. *
  42. * @var array
  43. */
  44. protected $treeTerms = array();
  45. /**
  46. * Array of loaded trees keyed by a cache id matching tree arguments.
  47. *
  48. * @var array
  49. */
  50. protected $trees = array();
  51. /**
  52. * {@inheritdoc}
  53. *
  54. * @param array $values
  55. * An array of values to set, keyed by property name. A value for the
  56. * vocabulary ID ('vid') is required.
  57. */
  58. public function create(array $values = array()) {
  59. // Save new terms with no parents by default.
  60. if (empty($values['parent'])) {
  61. $values['parent'] = array(0);
  62. }
  63. $entity = parent::create($values);
  64. return $entity;
  65. }
  66. /**
  67. * {@inheritdoc}
  68. */
  69. public function resetCache(array $ids = NULL) {
  70. drupal_static_reset('taxonomy_term_count_nodes');
  71. $this->parents = array();
  72. $this->parentsAll = array();
  73. $this->children = array();
  74. $this->treeChildren = array();
  75. $this->treeParents = array();
  76. $this->treeTerms = array();
  77. $this->trees = array();
  78. parent::resetCache($ids);
  79. }
  80. /**
  81. * {@inheritdoc}
  82. */
  83. public function deleteTermHierarchy($tids) {
  84. $this->database->delete('taxonomy_term_hierarchy')
  85. ->condition('tid', $tids, 'IN')
  86. ->execute();
  87. }
  88. /**
  89. * {@inheritdoc}
  90. */
  91. public function updateTermHierarchy(EntityInterface $term) {
  92. $query = $this->database->insert('taxonomy_term_hierarchy')
  93. ->fields(array('tid', 'parent'));
  94. foreach ($term->parent as $parent) {
  95. $query->values(array(
  96. 'tid' => $term->id(),
  97. 'parent' => (int) $parent->target_id,
  98. ));
  99. }
  100. $query->execute();
  101. }
  102. /**
  103. * {@inheritdoc}
  104. */
  105. public function loadParents($tid) {
  106. if (!isset($this->parents[$tid])) {
  107. $parents = array();
  108. $query = $this->database->select('taxonomy_term_field_data', 't');
  109. $query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid');
  110. $query->addField('t', 'tid');
  111. $query->condition('h.tid', $tid);
  112. $query->condition('t.default_langcode', 1);
  113. $query->addTag('term_access');
  114. $query->orderBy('t.weight');
  115. $query->orderBy('t.name');
  116. if ($ids = $query->execute()->fetchCol()) {
  117. $parents = $this->loadMultiple($ids);
  118. }
  119. $this->parents[$tid] = $parents;
  120. }
  121. return $this->parents[$tid];
  122. }
  123. /**
  124. * {@inheritdoc}
  125. */
  126. public function loadAllParents($tid) {
  127. if (!isset($this->parentsAll[$tid])) {
  128. $parents = array();
  129. if ($term = $this->load($tid)) {
  130. $parents[$term->id()] = $term;
  131. $terms_to_search[] = $term->id();
  132. while ($tid = array_shift($terms_to_search)) {
  133. if ($new_parents = $this->loadParents($tid)) {
  134. foreach ($new_parents as $new_parent) {
  135. if (!isset($parents[$new_parent->id()])) {
  136. $parents[$new_parent->id()] = $new_parent;
  137. $terms_to_search[] = $new_parent->id();
  138. }
  139. }
  140. }
  141. }
  142. }
  143. $this->parentsAll[$tid] = $parents;
  144. }
  145. return $this->parentsAll[$tid];
  146. }
  147. /**
  148. * {@inheritdoc}
  149. */
  150. public function loadChildren($tid, $vid = NULL) {
  151. if (!isset($this->children[$tid])) {
  152. $children = array();
  153. $query = $this->database->select('taxonomy_term_field_data', 't');
  154. $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
  155. $query->addField('t', 'tid');
  156. $query->condition('h.parent', $tid);
  157. if ($vid) {
  158. $query->condition('t.vid', $vid);
  159. }
  160. $query->condition('t.default_langcode', 1);
  161. $query->addTag('term_access');
  162. $query->orderBy('t.weight');
  163. $query->orderBy('t.name');
  164. if ($ids = $query->execute()->fetchCol()) {
  165. $children = $this->loadMultiple($ids);
  166. }
  167. $this->children[$tid] = $children;
  168. }
  169. return $this->children[$tid];
  170. }
  171. /**
  172. * {@inheritdoc}
  173. */
  174. public function loadTree($vid, $parent = 0, $max_depth = NULL, $load_entities = FALSE) {
  175. $cache_key = implode(':', func_get_args());
  176. if (!isset($this->trees[$cache_key])) {
  177. // We cache trees, so it's not CPU-intensive to call on a term and its
  178. // children, too.
  179. if (!isset($this->treeChildren[$vid])) {
  180. $this->treeChildren[$vid] = array();
  181. $this->treeParents[$vid] = array();
  182. $this->treeTerms[$vid] = array();
  183. $query = $this->database->select('taxonomy_term_field_data', 't');
  184. $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
  185. $result = $query
  186. ->addTag('term_access')
  187. ->fields('t')
  188. ->fields('h', array('parent'))
  189. ->condition('t.vid', $vid)
  190. ->condition('t.default_langcode', 1)
  191. ->orderBy('t.weight')
  192. ->orderBy('t.name')
  193. ->execute();
  194. foreach ($result as $term) {
  195. $this->treeChildren[$vid][$term->parent][] = $term->tid;
  196. $this->treeParents[$vid][$term->tid][] = $term->parent;
  197. $this->treeTerms[$vid][$term->tid] = $term;
  198. }
  199. }
  200. // Load full entities, if necessary. The entity controller statically
  201. // caches the results.
  202. $term_entities = array();
  203. if ($load_entities) {
  204. $term_entities = $this->loadMultiple(array_keys($this->treeTerms[$vid]));
  205. }
  206. $max_depth = (!isset($max_depth)) ? count($this->treeChildren[$vid]) : $max_depth;
  207. $tree = array();
  208. // Keeps track of the parents we have to process, the last entry is used
  209. // for the next processing step.
  210. $process_parents = array();
  211. $process_parents[] = $parent;
  212. // Loops over the parent terms and adds its children to the tree array.
  213. // Uses a loop instead of a recursion, because it's more efficient.
  214. while (count($process_parents)) {
  215. $parent = array_pop($process_parents);
  216. // The number of parents determines the current depth.
  217. $depth = count($process_parents);
  218. if ($max_depth > $depth && !empty($this->treeChildren[$vid][$parent])) {
  219. $has_children = FALSE;
  220. $child = current($this->treeChildren[$vid][$parent]);
  221. do {
  222. if (empty($child)) {
  223. break;
  224. }
  225. $term = $load_entities ? $term_entities[$child] : $this->treeTerms[$vid][$child];
  226. if (isset($this->treeParents[$vid][$load_entities ? $term->id() : $term->tid])) {
  227. // Clone the term so that the depth attribute remains correct
  228. // in the event of multiple parents.
  229. $term = clone $term;
  230. }
  231. $term->depth = $depth;
  232. unset($term->parent);
  233. $tid = $load_entities ? $term->id() : $term->tid;
  234. $term->parents = $this->treeParents[$vid][$tid];
  235. $tree[] = $term;
  236. if (!empty($this->treeChildren[$vid][$tid])) {
  237. $has_children = TRUE;
  238. // We have to continue with this parent later.
  239. $process_parents[] = $parent;
  240. // Use the current term as parent for the next iteration.
  241. $process_parents[] = $tid;
  242. // Reset pointers for child lists because we step in there more
  243. // often with multi parents.
  244. reset($this->treeChildren[$vid][$tid]);
  245. // Move pointer so that we get the correct term the next time.
  246. next($this->treeChildren[$vid][$parent]);
  247. break;
  248. }
  249. } while ($child = next($this->treeChildren[$vid][$parent]));
  250. if (!$has_children) {
  251. // We processed all terms in this hierarchy-level, reset pointer
  252. // so that this function works the next time it gets called.
  253. reset($this->treeChildren[$vid][$parent]);
  254. }
  255. }
  256. }
  257. $this->trees[$cache_key] = $tree;
  258. }
  259. return $this->trees[$cache_key];
  260. }
  261. /**
  262. * {@inheritdoc}
  263. */
  264. public function nodeCount($vid) {
  265. $query = $this->database->select('taxonomy_index', 'ti');
  266. $query->addExpression('COUNT(DISTINCT ti.nid)');
  267. $query->leftJoin('taxonomy_term_data', 'td', 'ti.tid = td.tid');
  268. $query->condition('td.vid', $vid);
  269. $query->addTag('vocabulary_node_count');
  270. return $query->execute()->fetchField();
  271. }
  272. /**
  273. * {@inheritdoc}
  274. */
  275. public function resetWeights($vid) {
  276. $this->database->update('taxonomy_term_field_data')
  277. ->fields(array('weight' => 0))
  278. ->condition('vid', $vid)
  279. ->execute();
  280. }
  281. /**
  282. * {@inheritdoc}
  283. */
  284. public function getNodeTerms(array $nids, array $vocabs = array(), $langcode = NULL) {
  285. $query = db_select('taxonomy_term_field_data', 'td');
  286. $query->innerJoin('taxonomy_index', 'tn', 'td.tid = tn.tid');
  287. $query->fields('td', array('tid'));
  288. $query->addField('tn', 'nid', 'node_nid');
  289. $query->orderby('td.weight');
  290. $query->orderby('td.name');
  291. $query->condition('tn.nid', $nids, 'IN');
  292. $query->addTag('term_access');
  293. if (!empty($vocabs)) {
  294. $query->condition('td.vid', $vocabs, 'IN');
  295. }
  296. if (!empty($langcode)) {
  297. $query->condition('td.langcode', $langcode);
  298. }
  299. $results = array();
  300. $all_tids = array();
  301. foreach ($query->execute() as $term_record) {
  302. $results[$term_record->node_nid][] = $term_record->tid;
  303. $all_tids[] = $term_record->tid;
  304. }
  305. $all_terms = $this->loadMultiple($all_tids);
  306. $terms = array();
  307. foreach ($results as $nid => $tids) {
  308. foreach ($tids as $tid) {
  309. $terms[$nid][$tid] = $all_terms[$tid];
  310. }
  311. }
  312. return $terms;
  313. }
  314. /**
  315. * {@inheritdoc}
  316. */
  317. public function __sleep() {
  318. $vars = parent::__sleep();
  319. // Do not serialize static cache.
  320. unset($vars['parents'], $vars['parentsAll'], $vars['children'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']);
  321. return $vars;
  322. }
  323. /**
  324. * {@inheritdoc}
  325. */
  326. public function __wakeup() {
  327. parent::__wakeup();
  328. // Initialize static caches.
  329. $this->parents = array();
  330. $this->parentsAll = array();
  331. $this->children = array();
  332. $this->treeChildren = array();
  333. $this->treeParents = array();
  334. $this->treeTerms = array();
  335. $this->trees = array();
  336. }
  337. }