3 namespace Drupal\Tests\Core\Field;
5 use Drupal\Component\Plugin\Exception\PluginNotFoundException;
6 use Drupal\Core\Cache\CacheBackendInterface;
7 use Drupal\Core\Entity\DynamicallyFieldableEntityStorageInterface;
8 use Drupal\Core\Entity\EntityFieldManagerInterface;
9 use Drupal\Core\Entity\EntityInterface;
10 use Drupal\Core\Entity\EntityTypeInterface;
11 use Drupal\Core\Entity\EntityTypeManagerInterface;
12 use Drupal\Core\Field\FieldDefinitionInterface;
13 use Drupal\Core\Field\FieldDefinitionListener;
14 use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
15 use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
16 use Drupal\Tests\UnitTestCase;
17 use Prophecy\Argument;
20 * @coversDefaultClass \Drupal\Core\Field\FieldDefinitionListener
23 class FieldDefinitionListenerTest extends UnitTestCase {
26 * The key-value factory.
28 * @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface|\Prophecy\Prophecy\ProphecyInterface
30 protected $keyValueFactory;
33 * The entity type manager.
35 * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\Prophecy\Prophecy\ProphecyInterface
37 protected $entityTypeManager;
40 * The entity field manager.
42 * @var \Drupal\Core\Entity\EntityFieldManagerInterface|\Prophecy\Prophecy\ProphecyInterface
44 protected $entityFieldManager;
49 * @var \Drupal\Core\Cache\CacheBackendInterface|\Prophecy\Prophecy\ProphecyInterface
51 protected $cacheBackend;
54 * The field definition listener under test.
56 * @var \Drupal\Core\Field\FieldDefinitionListener
58 protected $fieldDefinitionListener;
63 protected function setUp() {
66 $this->keyValueFactory = $this->prophesize(KeyValueFactoryInterface::class);
67 $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
68 $this->entityFieldManager = $this->prophesize(EntityFieldManagerInterface::class);
69 $this->cacheBackend = $this->prophesize(CacheBackendInterface::class);
71 $this->fieldDefinitionListener = new FieldDefinitionListener($this->entityTypeManager->reveal(), $this->entityFieldManager->reveal(), $this->keyValueFactory->reveal(), $this->cacheBackend->reveal());
75 * Sets up the entity manager to be tested.
77 * @param \Drupal\Core\Entity\EntityTypeInterface[]|\Prophecy\Prophecy\ProphecyInterface[] $definitions
78 * (optional) An array of entity type definitions.
80 protected function setUpEntityManager($definitions = []) {
81 $class = $this->getMockClass(EntityInterface::class);
82 foreach ($definitions as $key => $entity_type) {
83 // \Drupal\Core\Entity\EntityTypeInterface::getLinkTemplates() is called
84 // by \Drupal\Core\Entity\EntityManager::processDefinition() so it must
86 $entity_type->getLinkTemplates()->willReturn([]);
88 // Give the entity type a legitimate class to return.
89 $entity_type->getClass()->willReturn($class);
91 $definitions[$key] = $entity_type->reveal();
94 $this->entityTypeManager->getDefinition(Argument::cetera())
95 ->will(function ($args) use ($definitions) {
96 $entity_type_id = $args[0];
97 $exception_on_invalid = $args[1];
98 if (isset($definitions[$entity_type_id])) {
99 return $definitions[$entity_type_id];
101 elseif (!$exception_on_invalid) {
105 throw new PluginNotFoundException($entity_type_id);
108 $this->entityTypeManager->getDefinitions()->willReturn($definitions);
112 * @covers ::onFieldDefinitionCreate
114 public function testOnFieldDefinitionCreateNewField() {
115 $field_definition = $this->prophesize(FieldDefinitionInterface::class);
116 $field_definition->getTargetEntityTypeId()->willReturn('test_entity_type');
117 $field_definition->getTargetBundle()->willReturn('test_bundle');
118 $field_definition->getName()->willReturn('test_field');
119 $field_definition->getType()->willReturn('test_type');
121 $storage = $this->prophesize(DynamicallyFieldableEntityStorageInterface::class);
122 $storage->onFieldDefinitionCreate($field_definition->reveal())->shouldBeCalledTimes(1);
123 $this->entityTypeManager->getStorage('test_entity_type')->willReturn($storage->reveal());
125 $entity = $this->prophesize(EntityTypeInterface::class);
126 $this->setUpEntityManager(['test_entity_type' => $entity]);
128 // Set up the stored bundle field map.
129 $key_value_store = $this->prophesize(KeyValueStoreInterface::class);
130 $this->keyValueFactory->get('entity.definitions.bundle_field_map')->willReturn($key_value_store->reveal());
131 $key_value_store->get('test_entity_type')->willReturn([]);
132 $key_value_store->set('test_entity_type', [
134 'type' => 'test_type',
135 'bundles' => ['test_bundle' => 'test_bundle'],
137 ])->shouldBeCalled();
139 $this->fieldDefinitionListener->onFieldDefinitionCreate($field_definition->reveal());
143 * @covers ::onFieldDefinitionCreate
145 public function testOnFieldDefinitionCreateExistingField() {
146 $field_definition = $this->prophesize(FieldDefinitionInterface::class);
147 $field_definition->getTargetEntityTypeId()->willReturn('test_entity_type');
148 $field_definition->getTargetBundle()->willReturn('test_bundle');
149 $field_definition->getName()->willReturn('test_field');
151 $storage = $this->prophesize(DynamicallyFieldableEntityStorageInterface::class);
152 $storage->onFieldDefinitionCreate($field_definition->reveal())->shouldBeCalledTimes(1);
153 $this->entityTypeManager->getStorage('test_entity_type')->willReturn($storage->reveal());
155 $entity = $this->prophesize(EntityTypeInterface::class);
156 $this->setUpEntityManager(['test_entity_type' => $entity]);
158 // Set up the stored bundle field map.
159 $key_value_store = $this->prophesize(KeyValueStoreInterface::class);
160 $this->keyValueFactory->get('entity.definitions.bundle_field_map')->willReturn($key_value_store->reveal());
161 $key_value_store->get('test_entity_type')->willReturn([
163 'type' => 'test_type',
164 'bundles' => ['existing_bundle' => 'existing_bundle'],
167 $key_value_store->set('test_entity_type', [
169 'type' => 'test_type',
170 'bundles' => ['existing_bundle' => 'existing_bundle', 'test_bundle' => 'test_bundle'],
175 $this->fieldDefinitionListener->onFieldDefinitionCreate($field_definition->reveal());
179 * @covers ::onFieldDefinitionUpdate
181 public function testOnFieldDefinitionUpdate() {
182 $field_definition = $this->prophesize(FieldDefinitionInterface::class);
183 $field_definition->getTargetEntityTypeId()->willReturn('test_entity_type');
185 $storage = $this->prophesize(DynamicallyFieldableEntityStorageInterface::class);
186 $storage->onFieldDefinitionUpdate($field_definition->reveal(), $field_definition->reveal())->shouldBeCalledTimes(1);
187 $this->entityTypeManager->getStorage('test_entity_type')->willReturn($storage->reveal());
189 $entity = $this->prophesize(EntityTypeInterface::class);
190 $this->setUpEntityManager(['test_entity_type' => $entity]);
192 $this->fieldDefinitionListener->onFieldDefinitionUpdate($field_definition->reveal(), $field_definition->reveal());
196 * @covers ::onFieldDefinitionDelete
198 public function testOnFieldDefinitionDeleteMultipleBundles() {
199 $field_definition = $this->prophesize(FieldDefinitionInterface::class);
200 $field_definition->getTargetEntityTypeId()->willReturn('test_entity_type');
201 $field_definition->getTargetBundle()->willReturn('test_bundle');
202 $field_definition->getName()->willReturn('test_field');
204 $storage = $this->prophesize(DynamicallyFieldableEntityStorageInterface::class);
205 $storage->onFieldDefinitionDelete($field_definition->reveal())->shouldBeCalledTimes(1);
206 $this->entityTypeManager->getStorage('test_entity_type')->willReturn($storage->reveal());
208 $entity = $this->prophesize(EntityTypeInterface::class);
209 $this->setUpEntityManager(['test_entity_type' => $entity]);
211 // Set up the stored bundle field map.
212 $key_value_store = $this->prophesize(KeyValueStoreInterface::class);
213 $this->keyValueFactory->get('entity.definitions.bundle_field_map')->willReturn($key_value_store->reveal());
214 $key_value_store->get('test_entity_type')->willReturn([
216 'type' => 'test_type',
217 'bundles' => ['test_bundle' => 'test_bundle'],
220 'type' => 'test_type',
221 'bundles' => ['test_bundle' => 'test_bundle'],
224 $key_value_store->set('test_entity_type', [
226 'type' => 'test_type',
227 'bundles' => ['test_bundle' => 'test_bundle'],
232 $this->fieldDefinitionListener->onFieldDefinitionDelete($field_definition->reveal());
237 * @covers ::onFieldDefinitionDelete
239 public function testOnFieldDefinitionDeleteSingleBundles() {
240 $field_definition = $this->prophesize(FieldDefinitionInterface::class);
241 $field_definition->getTargetEntityTypeId()->willReturn('test_entity_type');
242 $field_definition->getTargetBundle()->willReturn('test_bundle');
243 $field_definition->getName()->willReturn('test_field');
245 $storage = $this->prophesize(DynamicallyFieldableEntityStorageInterface::class);
246 $storage->onFieldDefinitionDelete($field_definition->reveal())->shouldBeCalledTimes(1);
247 $this->entityTypeManager->getStorage('test_entity_type')->willReturn($storage->reveal());
249 $entity = $this->prophesize(EntityTypeInterface::class);
250 $this->setUpEntityManager(['test_entity_type' => $entity]);
252 // Set up the stored bundle field map.
253 $key_value_store = $this->prophesize(KeyValueStoreInterface::class);
254 $this->keyValueFactory->get('entity.definitions.bundle_field_map')->willReturn($key_value_store->reveal());
255 $key_value_store->get('test_entity_type')->willReturn([
257 'type' => 'test_type',
258 'bundles' => ['test_bundle' => 'test_bundle', 'second_bundle' => 'second_bundle'],
261 $key_value_store->set('test_entity_type', [
263 'type' => 'test_type',
264 'bundles' => ['second_bundle' => 'second_bundle'],
269 $this->fieldDefinitionListener->onFieldDefinitionDelete($field_definition->reveal());