Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / modules / taxonomy / src / TermStorage.php
index 0a00c13de5652eb1e81b268c2aa74039570caad7..2d47722faeae5350efbd3118b9a99ce7d681f942 100644 (file)
@@ -2,35 +2,14 @@
 
 namespace Drupal\taxonomy;
 
-use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Sql\SqlContentEntityStorage;
 
 /**
  * Defines a Controller class for taxonomy terms.
  */
 class TermStorage extends SqlContentEntityStorage implements TermStorageInterface {
 
-  /**
-   * Array of loaded parents keyed by child term ID.
-   *
-   * @var array
-   */
-  protected $parents = [];
-
-  /**
-   * Array of all loaded term ancestry keyed by ancestor term ID.
-   *
-   * @var array
-   */
-  protected $parentsAll = [];
-
-  /**
-   * Array of child terms keyed by parent term ID.
-   *
-   * @var array
-   */
-  protected $children = [];
-
   /**
    * Array of term parents keyed by vocabulary ID and child term ID.
    *
@@ -59,6 +38,14 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
    */
   protected $trees = [];
 
+  /**
+   * Array of all loaded term ancestry keyed by ancestor term ID, keyed by term
+   * ID.
+   *
+   * @var \Drupal\taxonomy\TermInterface[][]
+   */
+  protected $ancestors;
+
   /**
    * {@inheritdoc}
    *
@@ -80,9 +67,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
    */
   public function resetCache(array $ids = NULL) {
     drupal_static_reset('taxonomy_term_count_nodes');
-    $this->parents = [];
-    $this->parentsAll = [];
-    $this->children = [];
+    $this->ancestors = [];
     $this->treeChildren = [];
     $this->treeParents = [];
     $this->treeTerms = [];
@@ -93,100 +78,125 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
   /**
    * {@inheritdoc}
    */
-  public function deleteTermHierarchy($tids) {
-    $this->database->delete('taxonomy_term_hierarchy')
-      ->condition('tid', $tids, 'IN')
-      ->execute();
-  }
+  public function deleteTermHierarchy($tids) {}
 
   /**
    * {@inheritdoc}
    */
-  public function updateTermHierarchy(EntityInterface $term) {
-    $query = $this->database->insert('taxonomy_term_hierarchy')
-      ->fields(['tid', 'parent']);
-
-    foreach ($term->parent as $parent) {
-      $query->values([
-        'tid' => $term->id(),
-        'parent' => (int) $parent->target_id,
-      ]);
-    }
-    $query->execute();
-  }
+  public function updateTermHierarchy(EntityInterface $term) {}
 
   /**
    * {@inheritdoc}
    */
   public function loadParents($tid) {
-    if (!isset($this->parents[$tid])) {
-      $parents = [];
-      $query = $this->database->select('taxonomy_term_field_data', 't');
-      $query->join('taxonomy_term_hierarchy', 'h', 'h.parent = t.tid');
-      $query->addField('t', 'tid');
-      $query->condition('h.tid', $tid);
-      $query->condition('t.default_langcode', 1);
-      $query->addTag('taxonomy_term_access');
-      $query->orderBy('t.weight');
-      $query->orderBy('t.name');
-      if ($ids = $query->execute()->fetchCol()) {
-        $parents = $this->loadMultiple($ids);
+    $terms = [];
+    /** @var \Drupal\taxonomy\TermInterface $term */
+    if ($tid && $term = $this->load($tid)) {
+      foreach ($this->getParents($term) as $id => $parent) {
+        // This method currently doesn't return the <root> parent.
+        // @see https://www.drupal.org/node/2019905
+        if (!empty($id)) {
+          $terms[$id] = $parent;
+        }
+      }
+    }
+
+    return $terms;
+  }
+
+  /**
+   * Returns a list of parents of this term.
+   *
+   * @return \Drupal\taxonomy\TermInterface[]
+   *   The parent taxonomy term entities keyed by term ID. If this term has a
+   *   <root> parent, that item is keyed with 0 and will have NULL as value.
+   *
+   * @internal
+   * @todo Refactor away when TreeInterface is introduced.
+   */
+  protected function getParents(TermInterface $term) {
+    $parents = $ids = [];
+    // Cannot use $this->get('parent')->referencedEntities() here because that
+    // strips out the '0' reference.
+    foreach ($term->get('parent') as $item) {
+      if ($item->target_id == 0) {
+        // The <root> parent.
+        $parents[0] = NULL;
+        continue;
       }
-      $this->parents[$tid] = $parents;
+      $ids[] = $item->target_id;
     }
-    return $this->parents[$tid];
+
+    // @todo Better way to do this? AND handle the NULL/0 parent?
+    // Querying the terms again so that the same access checks are run when
+    // getParents() is called as in Drupal version prior to 8.3.
+    $loaded_parents = [];
+
+    if ($ids) {
+      $query = \Drupal::entityQuery('taxonomy_term')
+        ->condition('tid', $ids, 'IN');
+
+      $loaded_parents = static::loadMultiple($query->execute());
+    }
+
+    return $parents + $loaded_parents;
   }
 
   /**
    * {@inheritdoc}
    */
   public function loadAllParents($tid) {
-    if (!isset($this->parentsAll[$tid])) {
-      $parents = [];
-      if ($term = $this->load($tid)) {
-        $parents[$term->id()] = $term;
-        $terms_to_search[] = $term->id();
-
-        while ($tid = array_shift($terms_to_search)) {
-          if ($new_parents = $this->loadParents($tid)) {
-            foreach ($new_parents as $new_parent) {
-              if (!isset($parents[$new_parent->id()])) {
-                $parents[$new_parent->id()] = $new_parent;
-                $terms_to_search[] = $new_parent->id();
-              }
-            }
+    /** @var \Drupal\taxonomy\TermInterface $term */
+    return (!empty($tid) && $term = $this->load($tid)) ? $this->getAncestors($term) : [];
+  }
+
+  /**
+   * Returns all ancestors of this term.
+   *
+   * @return \Drupal\taxonomy\TermInterface[]
+   *   A list of ancestor taxonomy term entities keyed by term ID.
+   *
+   * @internal
+   * @todo Refactor away when TreeInterface is introduced.
+   */
+  protected function getAncestors(TermInterface $term) {
+    if (!isset($this->ancestors[$term->id()])) {
+      $this->ancestors[$term->id()] = [$term->id() => $term];
+      $search[] = $term->id();
+
+      while ($tid = array_shift($search)) {
+        foreach ($this->getParents(static::load($tid)) as $id => $parent) {
+          if ($parent && !isset($this->ancestors[$term->id()][$id])) {
+            $this->ancestors[$term->id()][$id] = $parent;
+            $search[] = $id;
           }
         }
       }
-
-      $this->parentsAll[$tid] = $parents;
     }
-    return $this->parentsAll[$tid];
+    return $this->ancestors[$term->id()];
   }
 
   /**
    * {@inheritdoc}
    */
   public function loadChildren($tid, $vid = NULL) {
-    if (!isset($this->children[$tid])) {
-      $children = [];
-      $query = $this->database->select('taxonomy_term_field_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->condition('t.default_langcode', 1);
-      $query->addTag('taxonomy_term_access');
-      $query->orderBy('t.weight');
-      $query->orderBy('t.name');
-      if ($ids = $query->execute()->fetchCol()) {
-        $children = $this->loadMultiple($ids);
-      }
-      $this->children[$tid] = $children;
-    }
-    return $this->children[$tid];
+    /** @var \Drupal\taxonomy\TermInterface $term */
+    return (!empty($tid) && $term = $this->load($tid)) ? $this->getChildren($term) : [];
+  }
+
+  /**
+   * Returns all children terms of this term.
+   *
+   * @return \Drupal\taxonomy\TermInterface[]
+   *   A list of children taxonomy term entities keyed by term ID.
+   *
+   * @internal
+   * @todo Refactor away when TreeInterface is introduced.
+   */
+  public function getChildren(TermInterface $term) {
+    $query = \Drupal::entityQuery('taxonomy_term')
+      ->condition('parent', $term->id());
+    return static::loadMultiple($query->execute());
   }
 
   /**
@@ -201,12 +211,12 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
         $this->treeChildren[$vid] = [];
         $this->treeParents[$vid] = [];
         $this->treeTerms[$vid] = [];
-        $query = $this->database->select('taxonomy_term_field_data', 't');
-        $query->join('taxonomy_term_hierarchy', 'h', 'h.tid = t.tid');
+        $query = $this->database->select($this->getDataTable(), 't');
+        $query->join('taxonomy_term__parent', 'p', 't.tid = p.entity_id');
+        $query->addExpression('parent_target_id', 'parent');
         $result = $query
           ->addTag('taxonomy_term_access')
           ->fields('t')
-          ->fields('h', ['parent'])
           ->condition('t.vid', $vid)
           ->condition('t.default_langcode', 1)
           ->orderBy('t.weight')
@@ -254,7 +264,9 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
               $term = clone $term;
             }
             $term->depth = $depth;
-            unset($term->parent);
+            if (!$load_entities) {
+              unset($term->parent);
+            }
             $tid = $load_entities ? $term->id() : $term->tid;
             $term->parents = $this->treeParents[$vid][$tid];
             $tree[] = $term;
@@ -293,7 +305,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
   public function nodeCount($vid) {
     $query = $this->database->select('taxonomy_index', 'ti');
     $query->addExpression('COUNT(DISTINCT ti.nid)');
-    $query->leftJoin('taxonomy_term_data', 'td', 'ti.tid = td.tid');
+    $query->leftJoin($this->getBaseTable(), 'td', 'ti.tid = td.tid');
     $query->condition('td.vid', $vid);
     $query->addTag('vocabulary_node_count');
     return $query->execute()->fetchField();
@@ -303,7 +315,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
    * {@inheritdoc}
    */
   public function resetWeights($vid) {
-    $this->database->update('taxonomy_term_field_data')
+    $this->database->update($this->getDataTable())
       ->fields(['weight' => 0])
       ->condition('vid', $vid)
       ->execute();
@@ -313,7 +325,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
    * {@inheritdoc}
    */
   public function getNodeTerms(array $nids, array $vocabs = [], $langcode = NULL) {
-    $query = db_select('taxonomy_term_field_data', 'td');
+    $query = db_select($this->getDataTable(), 'td');
     $query->innerJoin('taxonomy_index', 'tn', 'td.tid = tn.tid');
     $query->fields('td', ['tid']);
     $query->addField('tn', 'nid', 'node_nid');
@@ -351,7 +363,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
   public function __sleep() {
     $vars = parent::__sleep();
     // Do not serialize static cache.
-    unset($vars['parents'], $vars['parentsAll'], $vars['children'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']);
+    unset($vars['ancestors'], $vars['treeChildren'], $vars['treeParents'], $vars['treeTerms'], $vars['trees']);
     return $vars;
   }
 
@@ -361,9 +373,7 @@ class TermStorage extends SqlContentEntityStorage implements TermStorageInterfac
   public function __wakeup() {
     parent::__wakeup();
     // Initialize static caches.
-    $this->parents = [];
-    $this->parentsAll = [];
-    $this->children = [];
+    $this->ancestors = [];
     $this->treeChildren = [];
     $this->treeParents = [];
     $this->treeTerms = [];