diff --git a/core/modules/taxonomy/lib/Drupal/taxonomy/Taxonomy.php b/core/modules/taxonomy/lib/Drupal/taxonomy/Taxonomy.php new file mode 100644 index 0000000..5b1a7c9 --- /dev/null +++ b/core/modules/taxonomy/lib/Drupal/taxonomy/Taxonomy.php @@ -0,0 +1,223 @@ +entityManager = $entity_manager; + $this->database = $connection; + } + + /** + * Create a hierarchical representation of a vocabulary. + * + * @param int $vid + * The vocabulary ID to generate the tree for. + * @param int $parent + * The term ID under which to generate the tree. If 0, generate the tree + * for the entire vocabulary. + * @param int $max_depth + * The number of levels of the tree to return. Leave NULL to return all levels. + * @param bool $load_entities + * If TRUE, a full entity load will occur on the term objects. Otherwise they + * are partial objects queried directly from the {taxonomy_term_data} table to + * save execution time and memory consumption when listing large numbers of + * terms. Defaults to FALSE. + * + * @return array + * An array of all term objects in the tree. Each term object is extended + * to have "depth" and "parents" attributes in addition to its normal ones. + * Results are statically cached. Term objects will be partial or complete + * depending on the $load_entities parameter. + */ + public function getTree($vid, $parent = 0, $max_depth = NULL, $load_entities = FALSE) { + // We cache trees, so it's not CPU-intensive to call taxonomy_get_tree() on a + // term and its children, too. + if (!isset($this->tree[$vid])) { + $this->tree[$vid] = array(); + $this->parents[$vid] = array(); + $this->terms[$vid] = array(); + + $query = $this->database->select('taxonomy_term_data', 't'); + $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid'); + $result = $query + ->addTag('term_access') + ->fields('t') + ->fields('h', array('parent')) + ->condition('t.vid', $vid) + ->orderBy('t.weight') + ->orderBy('t.name') + ->execute(); + + foreach ($result as $term) { + $this->tree[$vid][$term->parent][] = $term->tid; + $this->parents[$vid][$term->tid][] = $term->parent; + $this->terms[$vid][$term->tid] = $term; + } + } + + // Load full entities, if necessary. The entity controller statically + // caches the results. + if ($load_entities) { + $term_entities = $this->entityManager->getStorageController('taxonomy_term')->load(array_keys($this->terms[$vid])); + } + + $max_depth = (!isset($max_depth)) ? count($this->tree[$vid]) : $max_depth; + $tree = array(); + + // Keeps track of the parents we have to process, the last entry is used + // for the next processing step. + $process_parents = array(); + $process_parents[] = $parent; + + // Loops over the parent terms and adds its children to the tree array. + // Uses a loop instead of a recursion, because it's more efficient. + while (count($process_parents)) { + $parent = array_pop($process_parents); + // The number of parents determines the current depth. + $depth = count($process_parents); + if ($max_depth > $depth && !empty($this->tree[$vid][$parent])) { + $has_children = FALSE; + $child = current($this->tree[$vid][$parent]); + do { + if (empty($child)) { + break; + } + $term = $load_entities ? $term_entities[$child] : $this->terms[$vid][$child]; + if (isset($this->parents[$vid][$term->tid])) { + // Clone the term so that the depth attribute remains correct + // in the event of multiple parents. + $term = clone $term; + } + $term->depth = $depth; + unset($term->parent); + $term->parents = $this->parents[$vid][$term->tid]; + $tree[] = $term; + if (!empty($this->tree[$vid][$term->tid])) { + $has_children = TRUE; + + // We have to continue with this parent later. + $process_parents[] = $parent; + // Use the current term as parent for the next iteration. + $process_parents[] = $term->tid; + + // Reset pointers for child lists because we step in there more often + // with multi parents. + reset($this->tree[$vid][$term->tid]); + // Move pointer so that we get the correct term the next time. + next($this->tree[$vid][$parent]); + break; + } + } while ($child = next($this->tree[$vid][$parent])); + + if (!$has_children) { + // We processed all terms in this hierarchy-level, reset pointer + // so that this function works the next time it gets called. + reset($this->tree[$vid][$parent]); + } + } + } + + return $tree; + } + + /** + * Finds all children of a term ID. + * + * @param int $tid + * A taxonomy term ID. + * @param int $vid + * An optional vocabulary ID to restrict the child search. + * + * @return array + * An array of term objects that are the children of the term $tid, or an + * empty array when no children exist. + */ + public function loadChildren($tid, $vid = NULL) { + if ($tid && !isset($this->children[$tid])) { + $query = $this->database->select('taxonomy_term_data', 't'); + $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid'); + $query->addField('t', 'tid'); + $query->condition('h.parent', $tid); + if ($vid) { + $query->condition('t.vid', $vid); + } + $query->addTag('term_access'); + $query->orderBy('t.weight'); + $query->orderBy('t.name'); + $tids = $query->execute()->fetchCol(); + $this->children[$tid] = $this->entityManager->getStorageController('taxonomy_term')->load($tids); + } + + return isset($this->children[$tid]) ? $this->children[$tid] : array(); + } + + /** + * Flushes the static cache. + */ + public function clearCache() { + $this->tree = array(); + $this->parents = array(); + $this->children = array(); + $this->terms = array(); + } +} diff --git a/core/modules/taxonomy/taxonomy.module b/core/modules/taxonomy/taxonomy.module index 89f334b..59945d6 100644 --- a/core/modules/taxonomy/taxonomy.module +++ b/core/modules/taxonomy/taxonomy.module @@ -681,26 +681,11 @@ function taxonomy_term_load_parents_all($tid) { * @return * An array of term objects that are the children of the term $tid, or an * empty array when no children exist. + * + * @deprecated Use Drupal::service('taxonomy')->loadChildren() instead. */ function taxonomy_term_load_children($tid, $vid = NULL) { - $children = &drupal_static(__FUNCTION__, array()); - - if ($tid && !isset($children[$tid])) { - $query = db_select('taxonomy_term_data', 't'); - $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid'); - $query->addField('t', 'tid'); - $query->condition('h.parent', $tid); - if ($vid) { - $query->condition('t.vid', $vid); - } - $query->addTag('term_access'); - $query->orderBy('t.weight'); - $query->orderBy('t.name'); - $tids = $query->execute()->fetchCol(); - $children[$tid] = taxonomy_term_load_multiple($tids); - } - - return isset($children[$tid]) ? $children[$tid] : array(); + return Drupal::service('taxonomy')->loadChildren($tid, $vid); } /** @@ -724,100 +709,11 @@ function taxonomy_term_load_children($tid, $vid = NULL) { * to have "depth" and "parents" attributes in addition to its normal ones. * Results are statically cached. Term objects will be partial or complete * depending on the $load_entities parameter. + * + * @deprecated Use Drupal::service('taxonomy')->getTree() instead. */ function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities = FALSE) { - $children = &drupal_static(__FUNCTION__, array()); - $parents = &drupal_static(__FUNCTION__ . ':parents', array()); - $terms = &drupal_static(__FUNCTION__ . ':terms', array()); - - // We cache trees, so it's not CPU-intensive to call taxonomy_get_tree() on a - // term and its children, too. - if (!isset($children[$vid])) { - $children[$vid] = array(); - $parents[$vid] = array(); - $terms[$vid] = array(); - - $query = db_select('taxonomy_term_data', 't'); - $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid'); - $result = $query - ->addTag('term_access') - ->fields('t') - ->fields('h', array('parent')) - ->condition('t.vid', $vid) - ->orderBy('t.weight') - ->orderBy('t.name') - ->execute(); - - foreach ($result as $term) { - $children[$vid][$term->parent][] = $term->tid; - $parents[$vid][$term->tid][] = $term->parent; - $terms[$vid][$term->tid] = $term; - } - } - - // Load full entities, if necessary. The entity controller statically - // caches the results. - if ($load_entities) { - $term_entities = taxonomy_term_load_multiple(array_keys($terms[$vid])); - } - - $max_depth = (!isset($max_depth)) ? count($children[$vid]) : $max_depth; - $tree = array(); - - // Keeps track of the parents we have to process, the last entry is used - // for the next processing step. - $process_parents = array(); - $process_parents[] = $parent; - - // Loops over the parent terms and adds its children to the tree array. - // Uses a loop instead of a recursion, because it's more efficient. - while (count($process_parents)) { - $parent = array_pop($process_parents); - // The number of parents determines the current depth. - $depth = count($process_parents); - if ($max_depth > $depth && !empty($children[$vid][$parent])) { - $has_children = FALSE; - $child = current($children[$vid][$parent]); - do { - if (empty($child)) { - break; - } - $term = $load_entities ? $term_entities[$child] : $terms[$vid][$child]; - if (isset($parents[$vid][$term->tid])) { - // Clone the term so that the depth attribute remains correct - // in the event of multiple parents. - $term = clone $term; - } - $term->depth = $depth; - unset($term->parent); - $term->parents = $parents[$vid][$term->tid]; - $tree[] = $term; - if (!empty($children[$vid][$term->tid])) { - $has_children = TRUE; - - // We have to continue with this parent later. - $process_parents[] = $parent; - // Use the current term as parent for the next iteration. - $process_parents[] = $term->tid; - - // Reset pointers for child lists because we step in there more often - // with multi parents. - reset($children[$vid][$term->tid]); - // Move pointer so that we get the correct term the next time. - next($children[$vid][$parent]); - break; - } - } while ($child = next($children[$vid][$parent])); - - if (!$has_children) { - // We processed all terms in this hierarchy-level, reset pointer - // so that this function works the next time it gets called. - reset($children[$vid][$parent]); - } - } - } - - return $tree; + return Drupal::service('taxonomy')->getTree($vid, $parent, $max_depth, $load_entities); } /** diff --git a/core/modules/taxonomy/taxonomy.services.yml b/core/modules/taxonomy/taxonomy.services.yml new file mode 100644 index 0000000..b725d7c --- /dev/null +++ b/core/modules/taxonomy/taxonomy.services.yml @@ -0,0 +1,4 @@ +services: + taxonomy: + class: Drupal\taxonomy\Taxonomy + arguments: ['@plugin.manager.entity', '@database']