Chris@18: installEntitySchema('taxonomy_term'); Chris@18: } Chris@18: Chris@18: /** Chris@18: * Tests the term hierarchy validation with re-parenting in pending revisions. Chris@18: */ Chris@18: public function testTermHierarchyValidation() { Chris@18: $vocabulary_id = mb_strtolower($this->randomMachineName()); Chris@18: $vocabulary = Vocabulary::create([ Chris@18: 'name' => $vocabulary_id, Chris@18: 'vid' => $vocabulary_id, Chris@18: ]); Chris@18: $vocabulary->save(); Chris@18: Chris@18: // Create a simple hierarchy in the vocabulary, a root term and three parent Chris@18: // terms. Chris@18: /** @var \Drupal\Core\Entity\RevisionableStorageInterface $term_storage */ Chris@18: $term_storage = \Drupal::entityTypeManager()->getStorage('taxonomy_term'); Chris@18: $root = $term_storage->create([ Chris@18: 'name' => $this->randomMachineName(), Chris@18: 'vid' => $vocabulary_id, Chris@18: ]); Chris@18: $root->save(); Chris@18: $parent1 = $term_storage->create([ Chris@18: 'name' => $this->randomMachineName(), Chris@18: 'vid' => $vocabulary_id, Chris@18: 'parent' => $root->id(), Chris@18: ]); Chris@18: $parent1->save(); Chris@18: $parent2 = $term_storage->create([ Chris@18: 'name' => $this->randomMachineName(), Chris@18: 'vid' => $vocabulary_id, Chris@18: 'parent' => $root->id(), Chris@18: ]); Chris@18: $parent2->save(); Chris@18: $parent3 = $term_storage->create([ Chris@18: 'name' => $this->randomMachineName(), Chris@18: 'vid' => $vocabulary_id, Chris@18: 'parent' => $root->id(), Chris@18: ]); Chris@18: $parent3->save(); Chris@18: Chris@18: // Create a child term and assign one of the parents above. Chris@18: $child1 = $term_storage->create([ Chris@18: 'name' => $this->randomMachineName(), Chris@18: 'vid' => $vocabulary_id, Chris@18: 'parent' => $parent1->id(), Chris@18: ]); Chris@18: $violations = $child1->validate(); Chris@18: $this->assertEmpty($violations); Chris@18: $child1->save(); Chris@18: Chris@18: $validation_message = 'You can only change the hierarchy for the published version of this term.'; Chris@18: Chris@18: // Add a pending revision without changing the term parent. Chris@18: $pending_name = $this->randomMachineName(); Chris@18: $child_pending = $term_storage->createRevision($child1, FALSE); Chris@18: $child_pending->name = $pending_name; Chris@18: $violations = $child_pending->validate(); Chris@18: $this->assertEmpty($violations); Chris@18: Chris@18: // Add a pending revision and change the parent. Chris@18: $child_pending = $term_storage->createRevision($child1, FALSE); Chris@18: $child_pending->parent = $parent2; Chris@18: $violations = $child_pending->validate(); Chris@18: $this->assertCount(1, $violations); Chris@18: $this->assertEquals($validation_message, $violations[0]->getMessage()); Chris@18: $this->assertEquals('parent', $violations[0]->getPropertyPath()); Chris@18: Chris@18: // Add a pending revision and add a new parent. Chris@18: $child_pending = $term_storage->createRevision($child1, FALSE); Chris@18: $child_pending->parent[0] = $parent1; Chris@18: $child_pending->parent[1] = $parent3; Chris@18: $violations = $child_pending->validate(); Chris@18: $this->assertCount(1, $violations); Chris@18: $this->assertEquals($validation_message, $violations[0]->getMessage()); Chris@18: $this->assertEquals('parent', $violations[0]->getPropertyPath()); Chris@18: Chris@18: // Add a pending revision and use the root term as a parent. Chris@18: $child_pending = $term_storage->createRevision($child1, FALSE); Chris@18: $child_pending->parent[0] = $root; Chris@18: $violations = $child_pending->validate(); Chris@18: $this->assertCount(1, $violations); Chris@18: $this->assertEquals($validation_message, $violations[0]->getMessage()); Chris@18: $this->assertEquals('parent', $violations[0]->getPropertyPath()); Chris@18: Chris@18: // Add a pending revision and remove the parent. Chris@18: $child_pending = $term_storage->createRevision($child1, FALSE); Chris@18: $child_pending->parent[0] = NULL; Chris@18: $violations = $child_pending->validate(); Chris@18: $this->assertCount(1, $violations); Chris@18: $this->assertEquals($validation_message, $violations[0]->getMessage()); Chris@18: $this->assertEquals('parent', $violations[0]->getPropertyPath()); Chris@18: Chris@18: // Add a pending revision and change the weight. Chris@18: $child_pending = $term_storage->createRevision($child1, FALSE); Chris@18: $child_pending->weight = 10; Chris@18: $violations = $child_pending->validate(); Chris@18: $this->assertCount(1, $violations); Chris@18: $this->assertEquals($validation_message, $violations[0]->getMessage()); Chris@18: $this->assertEquals('weight', $violations[0]->getPropertyPath()); Chris@18: Chris@18: // Add a pending revision and change both the parent and the weight. Chris@18: $child_pending = $term_storage->createRevision($child1, FALSE); Chris@18: $child_pending->parent = $parent2; Chris@18: $child_pending->weight = 10; Chris@18: $violations = $child_pending->validate(); Chris@18: $this->assertCount(2, $violations); Chris@18: $this->assertEquals($validation_message, $violations[0]->getMessage()); Chris@18: $this->assertEquals($validation_message, $violations[1]->getMessage()); Chris@18: $this->assertEquals('parent', $violations[0]->getPropertyPath()); Chris@18: $this->assertEquals('weight', $violations[1]->getPropertyPath()); Chris@18: Chris@18: // Add a published revision and change the parent. Chris@18: $child_pending = $term_storage->createRevision($child1, TRUE); Chris@18: $child_pending->parent[0] = $parent2; Chris@18: $violations = $child_pending->validate(); Chris@18: $this->assertEmpty($violations); Chris@18: Chris@18: // Add a new term as a third-level child. Chris@18: // The taxonomy tree structure ends up as follows: Chris@18: // root Chris@18: // - parent1 Chris@18: // - parent2 Chris@18: // -- child1 <- this will be a term with a pending revision Chris@18: // --- child2 Chris@18: // - parent3 Chris@18: $child2 = $term_storage->create([ Chris@18: 'name' => $this->randomMachineName(), Chris@18: 'vid' => $vocabulary_id, Chris@18: 'parent' => $child1->id(), Chris@18: ]); Chris@18: $child2->save(); Chris@18: Chris@18: // Change 'child1' to be a pending revision. Chris@18: $child1 = $term_storage->createRevision($child1, FALSE); Chris@18: $child1->save(); Chris@18: Chris@18: // Check that a child of a pending term can not be re-parented. Chris@18: $child2_pending = $term_storage->createRevision($child2, FALSE); Chris@18: $child2_pending->parent = $parent3; Chris@18: $violations = $child2_pending->validate(); Chris@18: $this->assertCount(1, $violations); Chris@18: $this->assertEquals($validation_message, $violations[0]->getMessage()); Chris@18: $this->assertEquals('parent', $violations[0]->getPropertyPath()); Chris@18: Chris@18: // Check that another term which has a pending revision can not moved under Chris@18: // another term which has pending revision. Chris@18: $parent3_pending = $term_storage->createRevision($parent3, FALSE); Chris@18: $parent3_pending->parent = $child1; Chris@18: $violations = $parent3_pending->validate(); Chris@18: $this->assertCount(1, $violations); Chris@18: $this->assertEquals($validation_message, $violations[0]->getMessage()); Chris@18: $this->assertEquals('parent', $violations[0]->getPropertyPath()); Chris@18: Chris@18: // Check that a new term can be created under a term that has a pending Chris@18: // revision. Chris@18: $child3 = $term_storage->create([ Chris@18: 'name' => $this->randomMachineName(), Chris@18: 'vid' => $vocabulary_id, Chris@18: 'parent' => $child1->id(), Chris@18: ]); Chris@18: $violations = $child3->validate(); Chris@18: $this->assertEmpty($violations); Chris@18: } Chris@18: Chris@18: }