Commit 7e655f95 authored by catch's avatar catch
Browse files

Issue #2898903 by tetranz, alexpott, smustgrave, immaculatexavier,...

Issue #2898903 by tetranz, alexpott, smustgrave, immaculatexavier, prasanth_kp, timmillwood, vinaymahale, rajandro: Terms lose <root> as the parent when editing

(cherry picked from commit 4b675406)
parent 6a6dc60c
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -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.
+71 −12
Original line number Diff line number Diff line
@@ -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;

/**
@@ -529,32 +530,90 @@ 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->submitForm([], 'Save');

    // 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->submitForm([], 'Save');

    // 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;
  }

  /**