ValidReferenceConstraintValidatorTest.php 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. namespace Drupal\KernelTests\Core\Entity;
  3. use Drupal\Core\Field\BaseFieldDefinition;
  4. use Drupal\Core\Field\FieldStorageDefinitionInterface;
  5. use Drupal\entity_test\Entity\EntityTest;
  6. use Drupal\field\Entity\FieldConfig;
  7. use Drupal\field\Tests\EntityReference\EntityReferenceTestTrait;
  8. use Drupal\node\Entity\Node;
  9. use Drupal\node\NodeInterface;
  10. use Drupal\Tests\node\Traits\ContentTypeCreationTrait;
  11. use Drupal\user\Entity\Role;
  12. use Drupal\user\Entity\User;
  13. /**
  14. * Tests validation constraints for ValidReferenceConstraintValidator.
  15. *
  16. * @group Validation
  17. */
  18. class ValidReferenceConstraintValidatorTest extends EntityKernelTestBase {
  19. use EntityReferenceTestTrait;
  20. use ContentTypeCreationTrait;
  21. /**
  22. * The typed data manager to use.
  23. *
  24. * @var \Drupal\Core\TypedData\TypedDataManager
  25. */
  26. protected $typedData;
  27. /**
  28. * {@inheritdoc}
  29. */
  30. public static $modules = ['field', 'node', 'user'];
  31. /**
  32. * {@inheritdoc}
  33. */
  34. protected function setUp() {
  35. parent::setUp();
  36. $this->installSchema('user', ['users_data']);
  37. $this->installSchema('node', ['node_access']);
  38. $this->installConfig('node');
  39. $this->typedData = $this->container->get('typed_data_manager');
  40. $this->createContentType(['type' => 'article', 'name' => 'Article']);
  41. $this->createContentType(['type' => 'page', 'name' => 'Basic page']);
  42. }
  43. /**
  44. * Tests the ValidReferenceConstraintValidator.
  45. */
  46. public function testValidation() {
  47. // Create a test entity to be referenced.
  48. $entity = $this->createUser();
  49. // By default entity references already have the ValidReference constraint.
  50. $definition = BaseFieldDefinition::create('entity_reference')
  51. ->setSettings(['target_type' => 'user']);
  52. $typed_data = $this->typedData->create($definition, ['target_id' => $entity->id()]);
  53. $violations = $typed_data->validate();
  54. $this->assertFalse($violations->count(), 'Validation passed for correct value.');
  55. // NULL is also considered a valid reference.
  56. $typed_data = $this->typedData->create($definition, ['target_id' => NULL]);
  57. $violations = $typed_data->validate();
  58. $this->assertFalse($violations->count(), 'Validation passed for correct value.');
  59. $typed_data = $this->typedData->create($definition, ['target_id' => $entity->id()]);
  60. // Delete the referenced entity.
  61. $entity->delete();
  62. $violations = $typed_data->validate();
  63. $this->assertTrue($violations->count(), 'Validation failed for incorrect value.');
  64. // Make sure the information provided by a violation is correct.
  65. $violation = $violations[0];
  66. $this->assertEqual($violation->getMessage(), t('The referenced entity (%type: %id) does not exist.', [
  67. '%type' => 'user',
  68. '%id' => $entity->id(),
  69. ]), 'The message for invalid value is correct.');
  70. $this->assertEqual($violation->getRoot(), $typed_data, 'Violation root is correct.');
  71. }
  72. /**
  73. * Tests the validation of pre-existing items in an entity reference field.
  74. */
  75. public function testPreExistingItemsValidation() {
  76. // Create two types of users, with and without access to bypass content
  77. // access.
  78. /** @var \Drupal\user\RoleInterface $role_with_access */
  79. $role_with_access = Role::create(['id' => 'role_with_access']);
  80. $role_with_access->grantPermission('access content');
  81. $role_with_access->grantPermission('bypass node access');
  82. $role_with_access->save();
  83. /** @var \Drupal\user\RoleInterface $role_without_access */
  84. $role_without_access = Role::create(['id' => 'role_without_access']);
  85. $role_without_access->grantPermission('access content');
  86. $role_without_access->save();
  87. $user_with_access = User::create(['roles' => ['role_with_access']]);
  88. $user_without_access = User::create(['roles' => ['role_without_access']]);
  89. // Add an entity reference field.
  90. $this->createEntityReferenceField(
  91. 'entity_test',
  92. 'entity_test',
  93. 'field_test',
  94. 'Field test',
  95. 'node',
  96. 'default',
  97. ['target_bundles' => ['article', 'page']],
  98. FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
  99. );
  100. // Create four test nodes.
  101. $published_node = Node::create([
  102. 'title' => 'Test published node',
  103. 'type' => 'article',
  104. 'status' => NodeInterface::PUBLISHED,
  105. ]);
  106. $published_node->save();
  107. $unpublished_node = Node::create([
  108. 'title' => 'Test unpublished node',
  109. 'type' => 'article',
  110. 'status' => NodeInterface::NOT_PUBLISHED,
  111. ]);
  112. $unpublished_node->save();
  113. $different_bundle_node = Node::create([
  114. 'title' => 'Test page node',
  115. 'type' => 'page',
  116. 'status' => NodeInterface::PUBLISHED,
  117. ]);
  118. $different_bundle_node->save();
  119. $deleted_node = Node::create([
  120. 'title' => 'Test deleted node',
  121. 'type' => 'article',
  122. 'status' => NodeInterface::PUBLISHED,
  123. ]);
  124. $deleted_node->save();
  125. $referencing_entity = EntityTest::create([
  126. 'field_test' => [
  127. ['entity' => $published_node],
  128. ['entity' => $unpublished_node],
  129. ['entity' => $different_bundle_node],
  130. ['entity' => $deleted_node],
  131. ]
  132. ]);
  133. // Check that users with access are able pass the validation for fields
  134. // without pre-existing content.
  135. $this->container->get('account_switcher')->switchTo($user_with_access);
  136. $violations = $referencing_entity->field_test->validate();
  137. $this->assertCount(0, $violations);
  138. // Check that users without access are not able pass the validation for
  139. // fields without pre-existing content.
  140. $this->container->get('account_switcher')->switchTo($user_without_access);
  141. $violations = $referencing_entity->field_test->validate();
  142. $this->assertCount(1, $violations);
  143. $this->assertEquals(t('This entity (%type: %id) cannot be referenced.', [
  144. '%type' => 'node',
  145. '%id' => $unpublished_node->id(),
  146. ]), $violations[0]->getMessage());
  147. // Now save the referencing entity which will create a pre-existing state
  148. // for it and repeat the checks. This time, the user without access should
  149. // be able to pass the validation as well because it's not changing the
  150. // pre-existing state.
  151. $referencing_entity->save();
  152. $this->container->get('account_switcher')->switchTo($user_with_access);
  153. $violations = $referencing_entity->field_test->validate();
  154. $this->assertCount(0, $violations);
  155. // Check that users without access are able pass the validation for fields
  156. // with pre-existing content.
  157. $this->container->get('account_switcher')->switchTo($user_without_access);
  158. $violations = $referencing_entity->field_test->validate();
  159. $this->assertCount(0, $violations);
  160. // Re-save the referencing entity and check that the referenced entity is
  161. // not affected.
  162. $referencing_entity->name->value = $this->randomString();
  163. $referencing_entity->save();
  164. $this->assertEquals($published_node->id(), $referencing_entity->field_test[0]->target_id);
  165. $this->assertEquals($unpublished_node->id(), $referencing_entity->field_test[1]->target_id);
  166. $this->assertEquals($different_bundle_node->id(), $referencing_entity->field_test[2]->target_id);
  167. $this->assertEquals($deleted_node->id(), $referencing_entity->field_test[3]->target_id);
  168. $violations = $referencing_entity->field_test->validate();
  169. $this->assertCount(0, $violations);
  170. // Remove one of the referencable bundles and check that a pre-existing node
  171. // of that bundle can not be referenced anymore.
  172. $field = FieldConfig::loadByName('entity_test', 'entity_test', 'field_test');
  173. $field->setSetting('handler_settings', ['target_bundles' => ['article']]);
  174. $field->save();
  175. $referencing_entity = $this->reloadEntity($referencing_entity);
  176. $violations = $referencing_entity->field_test->validate();
  177. $this->assertCount(1, $violations);
  178. $this->assertEquals(t('This entity (%type: %id) cannot be referenced.', [
  179. '%type' => 'node',
  180. '%id' => $different_bundle_node->id(),
  181. ]), $violations[0]->getMessage());
  182. // Delete the last node and check that the pre-existing reference is not
  183. // valid anymore.
  184. $deleted_node->delete();
  185. $violations = $referencing_entity->field_test->validate();
  186. $this->assertCount(2, $violations);
  187. $this->assertEquals(t('This entity (%type: %id) cannot be referenced.', [
  188. '%type' => 'node',
  189. '%id' => $different_bundle_node->id(),
  190. ]), $violations[0]->getMessage());
  191. $this->assertEquals(t('The referenced entity (%type: %id) does not exist.', [
  192. '%type' => 'node',
  193. '%id' => $deleted_node->id(),
  194. ]), $violations[1]->getMessage());
  195. }
  196. }