From 459213431851551a5e17ed34cfd735a4b2421deb Mon Sep 17 00:00:00 2001 From: catch <catch@35733.no-reply.drupal.org> Date: Mon, 28 Nov 2022 16:06:45 +0000 Subject: [PATCH] Issue #2898903 by tetranz, alexpott, smustgrave, immaculatexavier, prasanth_kp, timmillwood, catch, vinaymahale, rajandro: Terms lose <root> as the parent when editing --- core/modules/taxonomy/src/TermForm.php | 8 +- .../tests/src/Functional/TermTest.php | 89 ++++++++++++++++--- 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/core/modules/taxonomy/src/TermForm.php b/core/modules/taxonomy/src/TermForm.php index c077b5147df5..af287ba88131 100644 --- a/core/modules/taxonomy/src/TermForm.php +++ b/core/modules/taxonomy/src/TermForm.php @@ -23,7 +23,12 @@ public function form(array $form, FormStateInterface $form_state) { $taxonomy_storage = $this->entityTypeManager->getStorage('taxonomy_term'); $vocabulary = $vocab_storage->load($term->bundle()); - $parent = array_keys($taxonomy_storage->loadParents($term->id())); + $parent = []; + // Get the parent directly from the term as + // \Drupal\taxonomy\TermStorageInterface::loadParents() excludes the root. + foreach ($term->get('parent') as $item) { + $parent[] = (int) $item->target_id; + } $form_state->set(['taxonomy', 'parent'], $parent); $form_state->set(['taxonomy', 'vocabulary'], $vocabulary); @@ -42,7 +47,6 @@ public function form(array $form, FormStateInterface $form_state) { if (!$this->config('taxonomy.settings')->get('override_selector')) { $exclude = []; if (!$term->isNew()) { - $parent = array_keys($taxonomy_storage->loadParents($term->id())); $children = $taxonomy_storage->loadTree($vocabulary->id(), $term->id()); // A term can't be the child of itself, nor of its children. diff --git a/core/modules/taxonomy/tests/src/Functional/TermTest.php b/core/modules/taxonomy/tests/src/Functional/TermTest.php index 61985d5b0032..a1e13c16b26e 100644 --- a/core/modules/taxonomy/tests/src/Functional/TermTest.php +++ b/core/modules/taxonomy/tests/src/Functional/TermTest.php @@ -6,6 +6,7 @@ use Drupal\Core\Field\FieldStorageDefinitionInterface; use Drupal\field\Entity\FieldConfig; use Drupal\taxonomy\Entity\Term; +use Drupal\taxonomy\TermInterface; use Drupal\Tests\system\Functional\Menu\AssertBreadcrumbTrait; /** @@ -535,32 +536,96 @@ public function testTermReorder() { * Tests saving a term with multiple parents through the UI. */ public function testTermMultipleParentsInterface() { - // Add a new term to the vocabulary so that we can have multiple parents. - $parent = $this->createTerm($this->vocabulary); + // Add two new terms to the vocabulary so that we can have multiple parents. + // These will be terms with tids of 1 and 2 respectively. + $this->createTerm($this->vocabulary); + $this->createTerm($this->vocabulary); // Add a new term with multiple parents. $edit = [ 'name[0][value]' => $this->randomMachineName(12), 'description[0][value]' => $this->randomMachineName(100), - 'parent[]' => [0, $parent->id()], + 'parent[]' => [0, 1], ]; // Save the new term. $this->drupalGet('admin/structure/taxonomy/manage/' . $this->vocabulary->id() . '/add'); $this->submitForm($edit, 'Save'); // Check that the term was successfully created. - $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties([ - 'name' => $edit['name[0][value]'], - ]); - $term = reset($terms); + $term = $this->reloadTermByName($edit['name[0][value]']); $this->assertNotNull($term, 'Term found in database.'); $this->assertEquals($edit['name[0][value]'], $term->getName(), 'Term name was successfully saved.'); $this->assertEquals($edit['description[0][value]'], $term->getDescription(), 'Term description was successfully saved.'); - // Check that the parent tid is still there. The other parent (<root>) is - // not added by \Drupal\taxonomy\TermStorageInterface::loadParents(). - $parents = $this->container->get('entity_type.manager')->getStorage('taxonomy_term')->loadParents($term->id()); - $parent = reset($parents); - $this->assertEquals($edit['parent[]'][1], $parent->id(), 'Term parents were successfully saved.'); + + // Check that we have the expected parents. + $this->assertEquals([0, 1], $this->getParentTids($term), 'Term parents (root plus one) were successfully saved.'); + + // Load the edit form and save again to ensure parent are preserved. + // Generate a new name, so we know that the term really is saved. + $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); + $edit = [ + 'name[0][value]' => $this->randomMachineName(12), + ]; + $this->submitForm($edit, 'Save'); + $this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]']); + $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); + $this->submitForm([], 'Save'); + $this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]']); + + // Check that we still have the expected parents. + $term = $this->reloadTermByName($edit['name[0][value]']); + $this->assertEquals([0, 1], $this->getParentTids($term), 'Term parents (root plus one) were successfully saved again.'); + + // Save with two real parents. i.e., not including <root>. + $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); + $edit = [ + 'name[0][value]' => $this->randomMachineName(12), + 'parent[]' => [1, 2], + ]; + $this->submitForm($edit, 'Save'); + $this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]']); + $this->drupalGet('taxonomy/term/' . $term->id() . '/edit'); + $this->submitForm([], 'Save'); + $this->assertSession()->pageTextContains('Updated term ' . $edit['name[0][value]']); + + // Check that we have the expected parents. + $term = $this->reloadTermByName($edit['name[0][value]']); + $this->assertEquals([1, 2], $this->getParentTids($term), 'Term parents (two real) were successfully saved.'); + } + + /** + * Reloads a term by name. + * + * @param string $name + * The name of the term. + * + * @return \Drupal\taxonomy\TermInterface + * The reloaded term. + */ + private function reloadTermByName(string $name): TermInterface { + \Drupal::entityTypeManager()->getStorage('taxonomy_term')->resetCache(); + /** @var \Drupal\taxonomy\TermInterface[] $terms */ + $terms = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadByProperties(['name' => $name]); + return reset($terms); + } + + /** + * Get the parent tids for a term including root. + * + * @param \Drupal\taxonomy\TermInterface $term + * The term. + * + * @return array + * A sorted array of tids and 0 if the root is a parent. + */ + private function getParentTids($term) { + $parent_tids = []; + foreach ($term->get('parent') as $item) { + $parent_tids[] = (int) $item->target_id; + } + sort($parent_tids); + + return $parent_tids; } /** -- GitLab