1<?php
2
3namespace Drupal\Tests\taxonomy\Kernel;
4
5use Drupal\taxonomy\Entity\Term;
6use Drupal\KernelTests\KernelTestBase;
7use Drupal\Tests\taxonomy\Traits\TaxonomyTestTrait;
8
9/**
10 * Kernel tests for taxonomy term functions.
11 *
12 * @group taxonomy
13 */
14class TermKernelTest extends KernelTestBase {
15
16  use TaxonomyTestTrait;
17
18  /**
19   * {@inheritdoc}
20   */
21  public static $modules = ['filter', 'taxonomy', 'text', 'user'];
22
23  /**
24   * {@inheritdoc}
25   */
26  protected function setUp() {
27    parent::setUp();
28    $this->installConfig(['filter']);
29    $this->installEntitySchema('taxonomy_term');
30  }
31
32  /**
33   * Tests that a deleted term is no longer in the vocabulary.
34   */
35  public function testTermDelete() {
36    $vocabulary = $this->createVocabulary();
37    $valid_term = $this->createTerm($vocabulary);
38    // Delete a valid term.
39    $valid_term->delete();
40    $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['vid' => $vocabulary->id()]);
41    $this->assertTrue(empty($terms), 'Vocabulary is empty after deletion');
42  }
43
44  /**
45   * Deleting a parent of a term with multiple parents does not delete the term.
46   */
47  public function testMultipleParentDelete() {
48    $vocabulary = $this->createVocabulary();
49    $parent_term1 = $this->createTerm($vocabulary);
50    $parent_term2 = $this->createTerm($vocabulary);
51    $child_term = $this->createTerm($vocabulary);
52    $child_term->parent = [$parent_term1->id(), $parent_term2->id()];
53    $child_term->save();
54    $child_term_id = $child_term->id();
55
56    $parent_term1->delete();
57    $term_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
58    $term_storage->resetCache([$child_term_id]);
59    $child_term = Term::load($child_term_id);
60    $this->assertTrue(!empty($child_term), 'Child term is not deleted if only one of its parents is removed.');
61
62    $parent_term2->delete();
63    $term_storage->resetCache([$child_term_id]);
64    $child_term = Term::load($child_term_id);
65    $this->assertTrue(empty($child_term), 'Child term is deleted if all of its parents are removed.');
66  }
67
68  /**
69   * Test a taxonomy with terms that have multiple parents of different depths.
70   */
71  public function testTaxonomyVocabularyTree() {
72    // Create a new vocabulary with 6 terms.
73    $vocabulary = $this->createVocabulary();
74    $term = [];
75    for ($i = 0; $i < 6; $i++) {
76      $term[$i] = $this->createTerm($vocabulary);
77    }
78
79    // Get the taxonomy storage.
80    $taxonomy_storage = $this->container->get('entity_type.manager')->getStorage('taxonomy_term');
81
82    // Set the weight on $term[1] so it appears before $term[5] when fetching
83    // the parents for $term[2], in order to test for a regression on
84    // \Drupal\taxonomy\TermStorageInterface::loadAllParents().
85    $term[1]->weight = -1;
86    $term[1]->save();
87
88    // $term[2] is a child of 1 and 5.
89    $term[2]->parent = [$term[1]->id(), $term[5]->id()];
90    $term[2]->save();
91    // $term[3] is a child of 2.
92    $term[3]->parent = [$term[2]->id()];
93    $term[3]->save();
94    // $term[5] is a child of 4.
95    $term[5]->parent = [$term[4]->id()];
96    $term[5]->save();
97
98    /**
99     * Expected tree:
100     * term[0] | depth: 0
101     * term[1] | depth: 0
102     * -- term[2] | depth: 1
103     * ---- term[3] | depth: 2
104     * term[4] | depth: 0
105     * -- term[5] | depth: 1
106     * ---- term[2] | depth: 2
107     * ------ term[3] | depth: 3
108     */
109    // Count $term[1] parents with $max_depth = 1.
110    $tree = $taxonomy_storage->loadTree($vocabulary->id(), $term[1]->id(), 1);
111    $this->assertCount(1, $tree, 'We have one parent with depth 1.');
112
113    // Count all vocabulary tree elements.
114    $tree = $taxonomy_storage->loadTree($vocabulary->id());
115    $this->assertCount(8, $tree, 'We have all vocabulary tree elements.');
116
117    // Count elements in every tree depth.
118    foreach ($tree as $element) {
119      if (!isset($depth_count[$element->depth])) {
120        $depth_count[$element->depth] = 0;
121      }
122      $depth_count[$element->depth]++;
123    }
124    $this->assertEqual(3, $depth_count[0], 'Three elements in taxonomy tree depth 0.');
125    $this->assertEqual(2, $depth_count[1], 'Two elements in taxonomy tree depth 1.');
126    $this->assertEqual(2, $depth_count[2], 'Two elements in taxonomy tree depth 2.');
127    $this->assertEqual(1, $depth_count[3], 'One element in taxonomy tree depth 3.');
128
129    /** @var \Drupal\taxonomy\TermStorageInterface $storage */
130    $storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term');
131    // Count parents of $term[2].
132    $parents = $storage->loadParents($term[2]->id());
133    $this->assertCount(2, $parents, 'The term has two parents.');
134
135    // Count parents of $term[3].
136    $parents = $storage->loadParents($term[3]->id());
137    $this->assertCount(1, $parents, 'The term has one parent.');
138
139    // Identify all ancestors of $term[2].
140    $ancestors = $storage->loadAllParents($term[2]->id());
141    $this->assertCount(4, $ancestors, 'The term has four ancestors including the term itself.');
142
143    // Identify all ancestors of $term[3].
144    $ancestors = $storage->loadAllParents($term[3]->id());
145    $this->assertCount(5, $ancestors, 'The term has five ancestors including the term itself.');
146  }
147
148  /**
149   * Tests that a Term is renderable when unsaved (preview).
150   */
151  public function testTermPreview() {
152    $entity_manager = \Drupal::entityTypeManager();
153    $vocabulary = $this->createVocabulary();
154
155    // Create a unsaved term.
156    $term = $entity_manager->getStorage('taxonomy_term')->create([
157      'vid' => $vocabulary->id(),
158      'name' => 'Inator',
159    ]);
160
161    // Confirm we can get the view of unsaved term.
162    $render_array = $entity_manager->getViewBuilder('taxonomy_term')
163      ->view($term);
164    $this->assertTrue(!empty($render_array), 'Term view builder is built.');
165
166    // Confirm we can render said view.
167    $rendered = \Drupal::service('renderer')->renderPlain($render_array);
168    $this->assertTrue(!empty(trim($rendered)), 'Term is able to be rendered.');
169  }
170
171}
172