Updated to Drupal 8.6.4, which is PHP 7.3 friendly. Also updated HTMLaw library....
[yaffs-website] / web / core / tests / Drupal / KernelTests / Core / Entity / EntityFieldTest.php
1 <?php
2
3 namespace Drupal\KernelTests\Core\Entity;
4
5 use Drupal\Core\Entity\EntityInterface;
6 use Drupal\Core\Entity\RevisionLogInterface;
7 use Drupal\Core\Entity\TypedData\EntityDataDefinition;
8 use Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface;
9 use Drupal\Core\Field\BaseFieldDefinition;
10 use Drupal\Core\Field\FieldDefinitionInterface;
11 use Drupal\Core\Field\FieldItemInterface;
12 use Drupal\Core\Field\FieldItemListInterface;
13 use Drupal\Core\TypedData\ComplexDataDefinitionInterface;
14 use Drupal\Core\TypedData\ComplexDataInterface;
15 use Drupal\Core\TypedData\DataDefinitionInterface;
16 use Drupal\Core\TypedData\ListInterface;
17 use Drupal\Core\TypedData\Type\StringInterface;
18 use Drupal\Core\TypedData\TypedDataInterface;
19 use Drupal\entity_test\Entity\EntityTest;
20 use Drupal\entity_test\Entity\EntityTestComputedField;
21 use Drupal\node\Entity\Node;
22 use Drupal\node\Entity\NodeType;
23
24 /**
25  * Tests the Entity Field API.
26  *
27  * @group Entity
28  */
29 class EntityFieldTest extends EntityKernelTestBase {
30
31   /**
32    * Modules to enable.
33    *
34    * @var array
35    */
36   public static $modules = ['filter', 'text', 'node', 'user', 'field_test'];
37
38   /**
39    * @var string
40    */
41   protected $entityName;
42
43   /**
44    * @var \Drupal\user\Entity\User
45    */
46   protected $entityUser;
47
48   /**
49    * @var string
50    */
51   protected $entityFieldText;
52
53   protected function setUp() {
54     parent::setUp();
55
56     foreach (entity_test_entity_types() as $entity_type_id) {
57       // The entity_test schema is installed by the parent.
58       if ($entity_type_id != 'entity_test') {
59         $this->installEntitySchema($entity_type_id);
60       }
61     }
62
63     // Create the test field.
64     module_load_install('entity_test');
65     entity_test_install();
66
67     // Install required default configuration for filter module.
68     $this->installConfig(['system', 'filter']);
69   }
70
71   /**
72    * Creates a test entity.
73    *
74    * @return \Drupal\Core\Entity\EntityInterface
75    */
76   protected function createTestEntity($entity_type) {
77     $this->entityName = $this->randomMachineName();
78     $this->entityUser = $this->createUser();
79     $this->entityFieldText = $this->randomMachineName();
80
81     // Pass in the value of the name field when creating. With the user
82     // field we test setting a field after creation.
83     $entity = $this->container->get('entity_type.manager')
84       ->getStorage($entity_type)
85       ->create();
86     $entity->user_id->target_id = $this->entityUser->id();
87     $entity->name->value = $this->entityName;
88
89     // Set a value for the test field.
90     $entity->field_test_text->value = $this->entityFieldText;
91
92     return $entity;
93   }
94
95   /**
96    * Tests reading and writing properties and field items.
97    */
98   public function testReadWrite() {
99     // All entity variations have to have the same results.
100     foreach (entity_test_entity_types() as $entity_type) {
101       $this->doTestReadWrite($entity_type);
102     }
103   }
104
105   /**
106    * Executes the read write test set for a defined entity type.
107    *
108    * @param string $entity_type
109    *   The entity type to run the tests with.
110    */
111   protected function doTestReadWrite($entity_type) {
112     $entity = $this->createTestEntity($entity_type);
113
114     $langcode = 'en';
115
116     // Access the name field.
117     $this->assertTrue($entity->name instanceof FieldItemListInterface, format_string('%entity_type: Field implements interface', ['%entity_type' => $entity_type]));
118     $this->assertTrue($entity->name[0] instanceof FieldItemInterface, format_string('%entity_type: Field item implements interface', ['%entity_type' => $entity_type]));
119
120     $this->assertEqual($this->entityName, $entity->name->value, format_string('%entity_type: Name value can be read.', ['%entity_type' => $entity_type]));
121     $this->assertEqual($this->entityName, $entity->name[0]->value, format_string('%entity_type: Name value can be read through list access.', ['%entity_type' => $entity_type]));
122     $this->assertEqual($entity->name->getValue(), [0 => ['value' => $this->entityName]], format_string('%entity_type: Plain field value returned.', ['%entity_type' => $entity_type]));
123
124     // Change the name.
125     $new_name = $this->randomMachineName();
126     $entity->name->value = $new_name;
127     $this->assertEqual($new_name, $entity->name->value, format_string('%entity_type: Name can be updated and read.', ['%entity_type' => $entity_type]));
128     $this->assertEqual($entity->name->getValue(), [0 => ['value' => $new_name]], format_string('%entity_type: Plain field value reflects the update.', ['%entity_type' => $entity_type]));
129
130     $new_name = $this->randomMachineName();
131     $entity->name[0]->value = $new_name;
132     $this->assertEqual($new_name, $entity->name->value, format_string('%entity_type: Name can be updated and read through list access.', ['%entity_type' => $entity_type]));
133
134     // Access the user field.
135     $this->assertTrue($entity->user_id instanceof FieldItemListInterface, format_string('%entity_type: Field implements interface', ['%entity_type' => $entity_type]));
136     $this->assertTrue($entity->user_id[0] instanceof FieldItemInterface, format_string('%entity_type: Field item implements interface', ['%entity_type' => $entity_type]));
137
138     $this->assertEqual($this->entityUser->id(), $entity->user_id->target_id, format_string('%entity_type: User id can be read.', ['%entity_type' => $entity_type]));
139     $this->assertEqual($this->entityUser->getUsername(), $entity->user_id->entity->name->value, format_string('%entity_type: User name can be read.', ['%entity_type' => $entity_type]));
140
141     // Change the assigned user by entity.
142     $new_user1 = $this->createUser();
143     $entity->user_id->entity = $new_user1;
144     $this->assertEqual($new_user1->id(), $entity->user_id->target_id, format_string('%entity_type: Updated user id can be read.', ['%entity_type' => $entity_type]));
145     $this->assertEqual($new_user1->getUsername(), $entity->user_id->entity->name->value, format_string('%entity_type: Updated username value can be read.', ['%entity_type' => $entity_type]));
146
147     // Change the assigned user by id.
148     $new_user2 = $this->createUser();
149     $entity->user_id->target_id = $new_user2->id();
150     $this->assertEqual($new_user2->id(), $entity->user_id->target_id, format_string('%entity_type: Updated user id can be read.', ['%entity_type' => $entity_type]));
151     $this->assertEqual($new_user2->getUsername(), $entity->user_id->entity->name->value, format_string('%entity_type: Updated username value can be read.', ['%entity_type' => $entity_type]));
152
153     // Try unsetting a field property.
154     $entity->name->value = NULL;
155     $entity->user_id->target_id = NULL;
156     $this->assertNull($entity->name->value, format_string('%entity_type: Name field is not set.', ['%entity_type' => $entity_type]));
157     $this->assertNull($entity->user_id->target_id, format_string('%entity_type: User ID field is not set.', ['%entity_type' => $entity_type]));
158     $this->assertNull($entity->user_id->entity, format_string('%entity_type: User entity field is not set.', ['%entity_type' => $entity_type]));
159
160     // Test setting the values via the typed data API works as well.
161     // Change the assigned user by entity.
162     $entity->user_id->first()->get('entity')->setValue($new_user2);
163     $this->assertEqual($new_user2->id(), $entity->user_id->target_id, format_string('%entity_type: Updated user id can be read.', ['%entity_type' => $entity_type]));
164     $this->assertEqual($new_user2->getUsername(), $entity->user_id->entity->name->value, format_string('%entity_type: Updated user name value can be read.', ['%entity_type' => $entity_type]));
165
166     // Change the assigned user by id.
167     $entity->user_id->first()->get('target_id')->setValue($new_user2->id());
168     $this->assertEqual($new_user2->id(), $entity->user_id->target_id, format_string('%entity_type: Updated user id can be read.', ['%entity_type' => $entity_type]));
169     $this->assertEqual($new_user2->getUsername(), $entity->user_id->entity->name->value, format_string('%entity_type: Updated user name value can be read.', ['%entity_type' => $entity_type]));
170
171     // Try unsetting a field.
172     $entity->name->first()->get('value')->setValue(NULL);
173     $entity->user_id->first()->get('target_id')->setValue(NULL);
174     $this->assertNull($entity->name->value, format_string('%entity_type: Name field is not set.', ['%entity_type' => $entity_type]));
175     $this->assertNull($entity->user_id->target_id, format_string('%entity_type: User ID field is not set.', ['%entity_type' => $entity_type]));
176     $this->assertNull($entity->user_id->entity, format_string('%entity_type: User entity field is not set.', ['%entity_type' => $entity_type]));
177
178     // Create a fresh entity so target_id does not get its property object
179     // instantiated, then verify setting a new value via typed data API works.
180     $entity2 = $this->container->get('entity_type.manager')
181       ->getStorage($entity_type)
182       ->create([
183         'user_id' => ['target_id' => $new_user1->id()],
184       ]);
185     // Access the property object, and set a value.
186     $entity2->user_id->first()->get('target_id')->setValue($new_user2->id());
187     $this->assertEqual($new_user2->id(), $entity2->user_id->target_id, format_string('%entity_type: Updated user id can be read.', ['%entity_type' => $entity_type]));
188     $this->assertEqual($new_user2->name->value, $entity2->user_id->entity->name->value, format_string('%entity_type: Updated user name value can be read.', ['%entity_type' => $entity_type]));
189
190     // Test using isset(), empty() and unset().
191     $entity->name->value = 'test unset';
192     unset($entity->name->value);
193     $this->assertFalse(isset($entity->name->value), format_string('%entity_type: Name is not set.', ['%entity_type' => $entity_type]));
194     $this->assertFalse(isset($entity->name[0]->value), format_string('%entity_type: Name is not set.', ['%entity_type' => $entity_type]));
195     $this->assertTrue(empty($entity->name->value), format_string('%entity_type: Name is empty.', ['%entity_type' => $entity_type]));
196     $this->assertTrue(empty($entity->name[0]->value), format_string('%entity_type: Name is empty.', ['%entity_type' => $entity_type]));
197
198     $entity->name->value = 'a value';
199     $this->assertTrue(isset($entity->name->value), format_string('%entity_type: Name is set.', ['%entity_type' => $entity_type]));
200     $this->assertTrue(isset($entity->name[0]->value), format_string('%entity_type: Name is set.', ['%entity_type' => $entity_type]));
201     $this->assertFalse(empty($entity->name->value), format_string('%entity_type: Name is not empty.', ['%entity_type' => $entity_type]));
202     $this->assertFalse(empty($entity->name[0]->value), format_string('%entity_type: Name is not empty.', ['%entity_type' => $entity_type]));
203     $this->assertTrue(isset($entity->name[0]), format_string('%entity_type: Name string item is set.', ['%entity_type' => $entity_type]));
204     $this->assertFalse(isset($entity->name[1]), format_string('%entity_type: Second name string item is not set as it does not exist', ['%entity_type' => $entity_type]));
205     $this->assertTrue(isset($entity->name), format_string('%entity_type: Name field is set.', ['%entity_type' => $entity_type]));
206     $this->assertFalse(isset($entity->nameInvalid), format_string('%entity_type: Not existing field is not set.', ['%entity_type' => $entity_type]));
207
208     unset($entity->name[0]);
209     $this->assertFalse(isset($entity->name[0]), format_string('%entity_type: Name field item is not set.', ['%entity_type' => $entity_type]));
210     $this->assertFalse(isset($entity->name[0]->value), format_string('%entity_type: Name is not set.', ['%entity_type' => $entity_type]));
211     $this->assertFalse(isset($entity->name->value), format_string('%entity_type: Name is not set.', ['%entity_type' => $entity_type]));
212
213     // Test emptying a field by assigning an empty value. NULL and array()
214     // behave the same.
215     foreach ([NULL, [], 'unset'] as $empty) {
216       // Make sure a value is present
217       $entity->name->value = 'a value';
218       $this->assertTrue(isset($entity->name->value), format_string('%entity_type: Name is set.', ['%entity_type' => $entity_type]));
219       // Now, empty the field.
220       if ($empty === 'unset') {
221         unset($entity->name);
222       }
223       else {
224         $entity->name = $empty;
225       }
226       $this->assertTrue(isset($entity->name), format_string('%entity_type: Name field is set.', ['%entity_type' => $entity_type]));
227       $this->assertTrue($entity->name->isEmpty(), format_string('%entity_type: Name field is set.', ['%entity_type' => $entity_type]));
228       $this->assertIdentical(count($entity->name), 0, format_string('%entity_type: Name field contains no items.', ['%entity_type' => $entity_type]));
229       $this->assertIdentical($entity->name->getValue(), [], format_string('%entity_type: Name field value is an empty array.', ['%entity_type' => $entity_type]));
230       $this->assertFalse(isset($entity->name[0]), format_string('%entity_type: Name field item is not set.', ['%entity_type' => $entity_type]));
231       $this->assertFalse(isset($entity->name[0]->value), format_string('%entity_type: First name item value is not set.', ['%entity_type' => $entity_type]));
232       $this->assertFalse(isset($entity->name->value), format_string('%entity_type: Name value is not set.', ['%entity_type' => $entity_type]));
233     }
234
235     // Access the language field.
236     $langcode_key = $this->entityManager->getDefinition($entity_type)->getKey('langcode');
237     $this->assertEqual($langcode, $entity->{$langcode_key}->value, format_string('%entity_type: Language code can be read.', ['%entity_type' => $entity_type]));
238     $this->assertEqual(\Drupal::languageManager()->getLanguage($langcode), $entity->{$langcode_key}->language, format_string('%entity_type: Language object can be read.', ['%entity_type' => $entity_type]));
239
240     // Change the language by code.
241     $entity->{$langcode_key}->value = \Drupal::languageManager()->getDefaultLanguage()->getId();
242     $this->assertEqual(\Drupal::languageManager()->getDefaultLanguage()->getId(), $entity->{$langcode_key}->value, format_string('%entity_type: Language code can be read.', ['%entity_type' => $entity_type]));
243     $this->assertEqual(\Drupal::languageManager()->getDefaultLanguage(), $entity->{$langcode_key}->language, format_string('%entity_type: Language object can be read.', ['%entity_type' => $entity_type]));
244
245     // Revert language by code then try setting it by language object.
246     $entity->{$langcode_key}->value = $langcode;
247     $entity->{$langcode_key}->language = \Drupal::languageManager()->getDefaultLanguage();
248     $this->assertEqual(\Drupal::languageManager()->getDefaultLanguage()->getId(), $entity->{$langcode_key}->value, format_string('%entity_type: Language code can be read.', ['%entity_type' => $entity_type]));
249     $this->assertEqual(\Drupal::languageManager()->getDefaultLanguage(), $entity->{$langcode_key}->language, format_string('%entity_type: Language object can be read.', ['%entity_type' => $entity_type]));
250
251     // Access the text field and test updating.
252     $this->assertEqual($entity->field_test_text->value, $this->entityFieldText, format_string('%entity_type: Text field can be read.', ['%entity_type' => $entity_type]));
253     $new_text = $this->randomMachineName();
254     $entity->field_test_text->value = $new_text;
255     $this->assertEqual($entity->field_test_text->value, $new_text, format_string('%entity_type: Updated text field can be read.', ['%entity_type' => $entity_type]));
256
257     // Test creating the entity by passing in plain values.
258     $this->entityName = $this->randomMachineName();
259     $name_item[0]['value'] = $this->entityName;
260     $this->entityUser = $this->createUser();
261     $user_item[0]['target_id'] = $this->entityUser->id();
262     $this->entityFieldText = $this->randomMachineName();
263     $text_item[0]['value'] = $this->entityFieldText;
264
265     $entity = $this->container->get('entity_type.manager')
266       ->getStorage($entity_type)
267       ->create([
268         'name' => $name_item,
269         'user_id' => $user_item,
270         'field_test_text' => $text_item,
271       ]);
272     $this->assertEqual($this->entityName, $entity->name->value, format_string('%entity_type: Name value can be read.', ['%entity_type' => $entity_type]));
273     $this->assertEqual($this->entityUser->id(), $entity->user_id->target_id, format_string('%entity_type: User id can be read.', ['%entity_type' => $entity_type]));
274     $this->assertEqual($this->entityUser->getUsername(), $entity->user_id->entity->name->value, format_string('%entity_type: User name can be read.', ['%entity_type' => $entity_type]));
275     $this->assertEqual($this->entityFieldText, $entity->field_test_text->value, format_string('%entity_type: Text field can be read.', ['%entity_type' => $entity_type]));
276
277     // Tests copying field values by assigning the TypedData objects.
278     $entity2 = $this->createTestEntity($entity_type);
279     $entity2->name = $entity->name;
280     $entity2->user_id = $entity->user_id;
281     $entity2->field_test_text = $entity->field_test_text;
282     $this->assertFalse($entity->name === $entity2->name, format_string('%entity_type: Copying properties results in a different field object.', ['%entity_type' => $entity_type]));
283     $this->assertEqual($entity->name->value, $entity2->name->value, format_string('%entity_type: Name field copied.', ['%entity_type' => $entity_type]));
284     $this->assertEqual($entity->user_id->target_id, $entity2->user_id->target_id, format_string('%entity_type: User id field copied.', ['%entity_type' => $entity_type]));
285     $this->assertEqual($entity->field_test_text->value, $entity2->field_test_text->value, format_string('%entity_type: Text field copied.', ['%entity_type' => $entity_type]));
286
287     // Tests that assigning TypedData objects to non-field properties keeps the
288     // assigned value as is.
289     $entity2 = $this->createTestEntity($entity_type);
290     $entity2->_not_a_field = $entity->name;
291     $this->assertTrue($entity2->_not_a_field === $entity->name, format_string('%entity_type: Typed data objects can be copied to non-field properties as is.', ['%entity_type' => $entity_type]));
292
293     // Tests adding a value to a field item list.
294     $entity->name[] = 'Another name';
295     $this->assertEqual($entity->name[1]->value, 'Another name', format_string('%entity_type: List item added via [] and the first property.', ['%entity_type' => $entity_type]));
296     $entity->name[] = ['value' => 'Third name'];
297     $this->assertEqual($entity->name[2]->value, 'Third name', format_string('%entity_type: List item added via [] and an array of properties.', ['%entity_type' => $entity_type]));
298     $entity->name[3] = ['value' => 'Fourth name'];
299     $this->assertEqual($entity->name[3]->value, 'Fourth name', format_string('%entity_type: List item added via offset and an array of properties.', ['%entity_type' => $entity_type]));
300     unset($entity->name[3]);
301
302     // Test removing and empty-ing list items.
303     $this->assertEqual(count($entity->name), 3, format_string('%entity_type: List has 3 items.', ['%entity_type' => $entity_type]));
304     unset($entity->name[1]);
305     $this->assertEqual(count($entity->name), 2, format_string('%entity_type: Second list item has been removed.', ['%entity_type' => $entity_type]));
306     $this->assertEqual($entity->name[1]->value, 'Third name', format_string('%entity_type: The subsequent items have been shifted up.', ['%entity_type' => $entity_type]));
307     $this->assertEqual($entity->name[1]->getName(), 1, format_string('%entity_type: The items names have been updated to their new delta.', ['%entity_type' => $entity_type]));
308     $entity->name[1] = NULL;
309     $this->assertEqual(count($entity->name), 2, format_string('%entity_type: Assigning NULL does not reduce array count.', ['%entity_type' => $entity_type]));
310     $this->assertTrue($entity->name[1]->isEmpty(), format_string('%entity_type: Assigning NULL empties the item.', ['%entity_type' => $entity_type]));
311
312     // Test using isEmpty().
313     unset($entity->name[1]);
314     $this->assertFalse($entity->name[0]->isEmpty(), format_string('%entity_type: Name item is not empty.', ['%entity_type' => $entity_type]));
315     $entity->name->value = NULL;
316     $this->assertTrue($entity->name[0]->isEmpty(), format_string('%entity_type: Name item is empty.', ['%entity_type' => $entity_type]));
317     $this->assertTrue($entity->name->isEmpty(), format_string('%entity_type: Name field is empty.', ['%entity_type' => $entity_type]));
318     $this->assertEqual(count($entity->name), 1, format_string('%entity_type: Empty item is considered when counting.', ['%entity_type' => $entity_type]));
319     $this->assertEqual(count(iterator_to_array($entity->name->getIterator())), count($entity->name), format_string('%entity_type: Count matches iterator count.', ['%entity_type' => $entity_type]));
320     $this->assertTrue($entity->name->getValue() === [0 => ['value' => NULL]], format_string('%entity_type: Name field value contains a NULL value.', ['%entity_type' => $entity_type]));
321
322     // Test using filterEmptyItems().
323     $entity->name = [NULL, 'foo'];
324     $this->assertEqual(count($entity->name), 2, format_string('%entity_type: List has 2 items.', ['%entity_type' => $entity_type]));
325     $entity->name->filterEmptyItems();
326     $this->assertEqual(count($entity->name), 1, format_string('%entity_type: The empty item was removed.', ['%entity_type' => $entity_type]));
327     $this->assertEqual($entity->name[0]->value, 'foo', format_string('%entity_type: The items were renumbered.', ['%entity_type' => $entity_type]));
328     $this->assertEqual($entity->name[0]->getName(), 0, format_string('%entity_type: The deltas were updated in the items.', ['%entity_type' => $entity_type]));
329
330     // Test get and set field values.
331     $entity->name = 'foo';
332     $this->assertEqual($entity->name[0]->toArray(), ['value' => 'foo'], format_string('%entity_type: Field value has been retrieved via toArray()', ['%entity_type' => $entity_type]));
333
334     $values = $entity->toArray();
335     $this->assertEqual($values['name'], [0 => ['value' => 'foo']], format_string('%entity_type: Field value has been retrieved via toArray() from an entity.', ['%entity_type' => $entity_type]));
336
337     // Make sure the user id can be set to zero.
338     $user_item[0]['target_id'] = 0;
339     $entity = $this->container->get('entity_type.manager')
340       ->getStorage($entity_type)
341       ->create([
342         'name' => $name_item,
343         'user_id' => $user_item,
344         'field_test_text' => $text_item,
345       ]);
346     $this->assertNotNull($entity->user_id->target_id, format_string('%entity_type: User id is not NULL', ['%entity_type' => $entity_type]));
347     $this->assertIdentical($entity->user_id->target_id, 0, format_string('%entity_type: User id has been set to 0', ['%entity_type' => $entity_type]));
348
349     // Test setting the ID with the value only.
350     $entity = $this->container->get('entity_type.manager')
351       ->getStorage($entity_type)
352       ->create([
353         'name' => $name_item,
354         'user_id' => 0,
355         'field_test_text' => $text_item,
356       ]);
357     $this->assertNotNull($entity->user_id->target_id, format_string('%entity_type: User id is not NULL', ['%entity_type' => $entity_type]));
358     $this->assertIdentical($entity->user_id->target_id, 0, format_string('%entity_type: User id has been set to 0', ['%entity_type' => $entity_type]));
359   }
360
361   /**
362    * Tries to save and load an entity again.
363    */
364   public function testSave() {
365     // All entity variations have to have the same results.
366     foreach (entity_test_entity_types() as $entity_type) {
367       $this->doTestSave($entity_type);
368     }
369   }
370
371   /**
372    * Executes the save tests for the given entity type.
373    *
374    * @param string $entity_type
375    *   The entity type to run the tests with.
376    */
377   protected function doTestSave($entity_type) {
378     $langcode_key = $this->entityManager->getDefinition($entity_type)->getKey('langcode');
379     $entity = $this->createTestEntity($entity_type);
380     $entity->save();
381     $this->assertTrue((bool) $entity->id(), format_string('%entity_type: Entity has received an id.', ['%entity_type' => $entity_type]));
382
383     $entity = $this->container->get('entity_type.manager')
384       ->getStorage($entity_type)
385       ->load($entity->id());
386     $this->assertTrue((bool) $entity->id(), format_string('%entity_type: Entity loaded.', ['%entity_type' => $entity_type]));
387
388     // Access the name field.
389     $this->assertEqual(1, $entity->id->value, format_string('%entity_type: ID value can be read.', ['%entity_type' => $entity_type]));
390     $this->assertTrue(is_string($entity->uuid->value), format_string('%entity_type: UUID value can be read.', ['%entity_type' => $entity_type]));
391     $this->assertEqual('en', $entity->{$langcode_key}->value, format_string('%entity_type: Language code can be read.', ['%entity_type' => $entity_type]));
392     $this->assertEqual(\Drupal::languageManager()->getLanguage('en'), $entity->{$langcode_key}->language, format_string('%entity_type: Language object can be read.', ['%entity_type' => $entity_type]));
393     $this->assertEqual($this->entityUser->id(), $entity->user_id->target_id, format_string('%entity_type: User id can be read.', ['%entity_type' => $entity_type]));
394     $this->assertEqual($this->entityUser->getUsername(), $entity->user_id->entity->name->value, format_string('%entity_type: User name can be read.', ['%entity_type' => $entity_type]));
395     $this->assertEqual($this->entityFieldText, $entity->field_test_text->value, format_string('%entity_type: Text field can be read.', ['%entity_type' => $entity_type]));
396   }
397
398   /**
399    * Tests introspection and getting metadata upfront.
400    */
401   public function testIntrospection() {
402     // All entity variations have to have the same results.
403     foreach (entity_test_entity_types() as $entity_type) {
404       $this->doTestIntrospection($entity_type);
405     }
406   }
407
408   /**
409    * Executes the introspection tests for the given entity type.
410    *
411    * @param string $entity_type
412    *   The entity type to run the tests with.
413    */
414   protected function doTestIntrospection($entity_type) {
415     // Test getting metadata upfront. The entity types used for this test have
416     // a default bundle that is the same as the entity type.
417     $definitions = \Drupal::entityManager()->getFieldDefinitions($entity_type, $entity_type);
418     $this->assertEqual($definitions['name']->getType(), 'string', $entity_type . ': Name field found.');
419     $this->assertEqual($definitions['user_id']->getType(), 'entity_reference', $entity_type . ': User field found.');
420     $this->assertEqual($definitions['field_test_text']->getType(), 'text', $entity_type . ': Test-text-field field found.');
421
422     // Test deriving further metadata.
423     $this->assertTrue($definitions['name'] instanceof FieldDefinitionInterface);
424     $field_item_definition = $definitions['name']->getItemDefinition();
425     $this->assertTrue($field_item_definition instanceof ComplexDataDefinitionInterface);
426     $this->assertEqual($field_item_definition->getDataType(), 'field_item:string');
427     $value_definition = $field_item_definition->getPropertyDefinition('value');
428     $this->assertTrue($value_definition instanceof DataDefinitionInterface);
429     $this->assertEqual($value_definition->getDataType(), 'string');
430
431     // Test deriving metadata from references.
432     $entity_definition = EntityDataDefinition::create($entity_type);
433     $langcode_key = $this->entityManager->getDefinition($entity_type)->getKey('langcode');
434     $reference_definition = $entity_definition->getPropertyDefinition($langcode_key)
435       ->getPropertyDefinition('language')
436       ->getTargetDefinition();
437     $this->assertEqual($reference_definition->getDataType(), 'language');
438
439     $reference_definition = $entity_definition->getPropertyDefinition('user_id')
440       ->getPropertyDefinition('entity')
441       ->getTargetDefinition();
442
443     $this->assertTrue($reference_definition instanceof EntityDataDefinitionInterface, 'Definition of the referenced user retrieved.');
444     $this->assertEqual($reference_definition->getEntityTypeId(), 'user', 'Referenced entity is of type "user".');
445
446     // Test propagating down.
447     $name_definition = $reference_definition->getPropertyDefinition('name');
448     $this->assertTrue($name_definition instanceof FieldDefinitionInterface);
449     $this->assertEqual($name_definition->getPropertyDefinition('value')->getDataType(), 'string');
450
451     // Test introspecting an entity object.
452     // @todo: Add bundles and test bundles as well.
453     $entity = $this->container->get('entity_type.manager')
454       ->getStorage($entity_type)
455       ->create();
456
457     $definitions = $entity->getFieldDefinitions();
458     $this->assertEqual($definitions['name']->getType(), 'string', $entity_type . ': Name field found.');
459     $this->assertEqual($definitions['user_id']->getType(), 'entity_reference', $entity_type . ': User field found.');
460     $this->assertEqual($definitions['field_test_text']->getType(), 'text', $entity_type . ': Test-text-field field found.');
461
462     $name_properties = $entity->name->getFieldDefinition()->getPropertyDefinitions();
463     $this->assertEqual($name_properties['value']->getDataType(), 'string', $entity_type . ': String value property of the name found.');
464
465     $userref_properties = $entity->user_id->getFieldDefinition()->getPropertyDefinitions();
466     $this->assertEqual($userref_properties['target_id']->getDataType(), 'integer', $entity_type . ': Entity id property of the user found.');
467     $this->assertEqual($userref_properties['entity']->getDataType(), 'entity_reference', $entity_type . ': Entity reference property of the user found.');
468
469     $textfield_properties = $entity->field_test_text->getFieldDefinition()->getFieldStorageDefinition()->getPropertyDefinitions();
470     $this->assertEqual($textfield_properties['value']->getDataType(), 'string', $entity_type . ': String value property of the test-text field found.');
471     $this->assertEqual($textfield_properties['format']->getDataType(), 'filter_format', $entity_type . ': String format field of the test-text field found.');
472     $this->assertEqual($textfield_properties['processed']->getDataType(), 'string', $entity_type . ': String processed property of the test-text field found.');
473
474     // Make sure provided contextual information is right.
475     $entity_adapter = $entity->getTypedData();
476     $this->assertSame($entity_adapter->getRoot(), $entity_adapter, 'Entity is root object.');
477     $this->assertEqual($entity_adapter->getPropertyPath(), '');
478     $this->assertEqual($entity_adapter->getName(), '');
479     $this->assertEqual($entity_adapter->getParent(), NULL);
480
481     $field = $entity->user_id;
482     $this->assertSame($field->getRoot()->getValue(), $entity, 'Entity is root object.');
483     $this->assertSame($field->getEntity(), $entity, 'getEntity() returns the entity.');
484     $this->assertEqual($field->getPropertyPath(), 'user_id');
485     $this->assertEqual($field->getName(), 'user_id');
486     $this->assertSame($field->getParent()->getValue(), $entity, 'Parent object matches.');
487
488     $field_item = $field[0];
489     $this->assertSame($field_item->getRoot()->getValue(), $entity, 'Entity is root object.');
490     $this->assertSame($field_item->getEntity(), $entity, 'getEntity() returns the entity.');
491     $this->assertEqual($field_item->getPropertyPath(), 'user_id.0');
492     $this->assertEqual($field_item->getName(), '0');
493     $this->assertSame($field_item->getParent(), $field, 'Parent object matches.');
494
495     $item_value = $field_item->get('entity');
496     $this->assertSame($item_value->getRoot()->getValue(), $entity, 'Entity is root object.');
497     $this->assertEqual($item_value->getPropertyPath(), 'user_id.0.entity');
498     $this->assertEqual($item_value->getName(), 'entity');
499     $this->assertSame($item_value->getParent(), $field_item, 'Parent object matches.');
500   }
501
502   /**
503    * Tests iterating over properties.
504    */
505   public function testIterator() {
506     // All entity variations have to have the same results.
507     foreach (entity_test_entity_types() as $entity_type) {
508       $this->doTestIterator($entity_type);
509     }
510   }
511
512   /**
513    * Executes the iterator tests for the given entity type.
514    *
515    * @param string $entity_type
516    *   The entity type to run the tests with.
517    */
518   protected function doTestIterator($entity_type) {
519     $entity = $this->createTestEntity($entity_type);
520
521     foreach ($entity as $name => $field) {
522       $this->assertTrue($field instanceof FieldItemListInterface, $entity_type . ": Field $name implements interface.");
523
524       foreach ($field as $delta => $item) {
525         $this->assertTrue($field[0] instanceof FieldItemInterface, $entity_type . ": Item $delta of field $name implements interface.");
526
527         foreach ($item as $value_name => $value_property) {
528           $this->assertTrue($value_property instanceof TypedDataInterface, $entity_type . ": Value $value_name of item $delta of field $name implements interface.");
529
530           $value = $value_property->getValue();
531           $this->assertTrue(!isset($value) || is_scalar($value) || $value instanceof EntityInterface, $entity_type . ": Value $value_name of item $delta of field $name is a primitive or an entity.");
532         }
533       }
534     }
535
536     $fields = $entity->getFields();
537     $this->assertEqual(array_keys($fields), array_keys($entity->getTypedData()->getDataDefinition()->getPropertyDefinitions()), format_string('%entity_type: All fields returned.', ['%entity_type' => $entity_type]));
538     $this->assertEqual($fields, iterator_to_array($entity->getIterator()), format_string('%entity_type: Entity iterator iterates over all fields.', ['%entity_type' => $entity_type]));
539   }
540
541   /**
542    * Tests working with the entity based upon the TypedData API.
543    */
544   public function testDataStructureInterfaces() {
545     // All entity variations have to have the same results.
546     foreach (entity_test_entity_types() as $entity_type) {
547       $this->doTestDataStructureInterfaces($entity_type);
548     }
549   }
550
551   /**
552    * Executes the data structure interfaces tests for the given entity type.
553    *
554    * @param string $entity_type
555    *   The entity type to run the tests with.
556    */
557   protected function doTestDataStructureInterfaces($entity_type) {
558     $entity = $this->createTestEntity($entity_type);
559
560     // Test using the whole tree of typed data by navigating through the tree of
561     // contained properties and getting all contained strings, limited by a
562     // certain depth.
563     $strings = [];
564     $this->getContainedStrings($entity->getTypedData(), 0, $strings);
565
566     // @todo: Once the user entity has defined properties this should contain
567     // the user name and other user entity strings as well.
568     $target_strings = [
569       $entity->uuid->value,
570       'en',
571       $this->entityName,
572       // Bundle name.
573       $entity->bundle(),
574       $this->entityFieldText,
575       // Field format.
576       NULL,
577     ];
578
579     if ($entity instanceof RevisionLogInterface) {
580       // Adding empty string for revision message.
581       $target_strings[] = '';
582     }
583
584     asort($strings);
585     asort($target_strings);
586     $this->assertEqual(array_values($strings), array_values($target_strings), format_string('%entity_type: All contained strings found.', ['%entity_type' => $entity_type]));
587   }
588
589   /**
590    * Recursive helper for getting all contained strings,
591    * i.e. properties of type string.
592    */
593   public function getContainedStrings(TypedDataInterface $wrapper, $depth, array &$strings) {
594
595     if ($wrapper instanceof StringInterface) {
596       $strings[] = $wrapper->getValue();
597     }
598
599     // Recurse until a certain depth is reached if possible.
600     if ($depth < 7) {
601       if ($wrapper instanceof ListInterface) {
602         foreach ($wrapper as $item) {
603           $this->getContainedStrings($item, $depth + 1, $strings);
604         }
605       }
606       elseif ($wrapper instanceof ComplexDataInterface) {
607         foreach ($wrapper as $property) {
608           $this->getContainedStrings($property, $depth + 1, $strings);
609         }
610       }
611     }
612   }
613
614   /**
615    * Makes sure data types are correctly derived for all entity types.
616    */
617   public function testDataTypes() {
618     $types = \Drupal::typedDataManager()->getDefinitions();
619     foreach (entity_test_entity_types() as $entity_type) {
620       $this->assertTrue($types['entity:' . $entity_type]['class'], 'Entity data type registered.');
621     }
622     // Check bundle types are provided as well.
623     entity_test_create_bundle('bundle');
624     $types = \Drupal::typedDataManager()->getDefinitions();
625     $this->assertTrue($types['entity:entity_test:bundle']['class'], 'Entity bundle data type registered.');
626   }
627
628   /**
629    * Tests a base field override on a non-existing base field.
630    *
631    * @see entity_test_entity_base_field_info_alter()
632    */
633   public function testBaseFieldNonExistingBaseField() {
634     $this->entityManager->getStorage('node_type')->create([
635       'type' => 'page',
636       'name' => 'page',
637     ])->save();
638     $this->entityManager->clearCachedFieldDefinitions();
639     $fields = $this->entityManager->getFieldDefinitions('node', 'page');
640     $override = $fields['status']->getConfig('page');
641     $override->setLabel($this->randomString())->save();
642     \Drupal::state()->set('entity_test.node_remove_status_field', TRUE);
643     $this->entityManager->clearCachedFieldDefinitions();
644     $fields = $this->entityManager->getFieldDefinitions('node', 'page');
645     // A base field override on a non-existing base field should not cause a
646     // field definition to come into existence.
647     $this->assertFalse(isset($fields['status']), 'Node\'s status base field does not exist.');
648   }
649
650   /**
651    * Tests creating a field override config for a bundle field.
652    *
653    * @see entity_test_entity_base_field_info_alter()
654    */
655   public function testFieldOverrideBundleField() {
656     // First make sure the bundle field override in code, which is provided by
657     // the test entity works.
658     entity_test_create_bundle('some_test_bundle', 'Some test bundle', 'entity_test_field_override');
659     $field_definitions = $this->entityManager->getFieldDefinitions('entity_test_field_override', 'entity_test_field_override');
660     $this->assertEqual($field_definitions['name']->getDescription(), 'The default description.');
661     $this->assertNull($field_definitions['name']->getTargetBundle());
662
663     $field_definitions = $this->entityManager->getFieldDefinitions('entity_test_field_override', 'some_test_bundle');
664     $this->assertEqual($field_definitions['name']->getDescription(), 'Custom description.');
665     $this->assertEqual($field_definitions['name']->getTargetBundle(), 'some_test_bundle');
666
667     // Now create a config override of the bundle field.
668     $field_config = $field_definitions['name']->getConfig('some_test_bundle');
669     $field_config->setTranslatable(FALSE);
670     $field_config->save();
671
672     // Make sure both overrides are present.
673     $this->entityManager->clearCachedFieldDefinitions();
674     $field_definitions = $this->entityManager->getFieldDefinitions('entity_test_field_override', 'some_test_bundle');
675     $this->assertEqual($field_definitions['name']->getDescription(), 'Custom description.');
676     $this->assertEqual($field_definitions['name']->getTargetBundle(), 'some_test_bundle');
677     $this->assertFalse($field_definitions['name']->isTranslatable());
678   }
679
680   /**
681    * Tests validation constraints provided by the Entity API.
682    */
683   public function testEntityConstraintValidation() {
684     $entity = $this->createTestEntity('entity_test');
685     $entity->save();
686     // Create a reference field item and let it reference the entity.
687     $definition = BaseFieldDefinition::create('entity_reference')
688       ->setLabel('Test entity')
689       ->setSetting('target_type', 'entity_test');
690     $reference_field = \Drupal::typedDataManager()->create($definition);
691     $reference = $reference_field->appendItem(['entity' => $entity])->get('entity');
692
693     // Test validation the typed data object.
694     $violations = $reference->validate();
695     $this->assertEqual($violations->count(), 0);
696
697     // Test validating an entity of the wrong type.
698     $user = $this->createUser();
699     $user->save();
700     $node = $node = Node::create([
701       'type' => 'page',
702       'uid' => $user->id(),
703       'title' => $this->randomString(),
704     ]);
705     $reference->setValue($node);
706     $violations = $reference->validate();
707     $this->assertEqual($violations->count(), 1);
708
709     // Test bundle validation.
710     NodeType::create(['type' => 'article'])
711       ->save();
712     $definition = BaseFieldDefinition::create('entity_reference')
713       ->setLabel('Test entity')
714       ->setSetting('target_type', 'node')
715       ->setSetting('handler_settings', ['target_bundles' => ['article' => 'article']]);
716     $reference_field = \Drupal::TypedDataManager()->create($definition);
717     $reference_field->appendItem(['entity' => $node]);
718     $violations = $reference_field->validate();
719     $this->assertEqual($violations->count(), 1);
720
721     $node = Node::create([
722       'type' => 'article',
723       'uid' => $user->id(),
724       'title' => $this->randomString(),
725     ]);
726     $node->save();
727     $reference_field->entity = $node;
728     $violations = $reference_field->validate();
729     $this->assertEqual($violations->count(), 0);
730   }
731
732   /**
733    * Tests getting processed property values via a computed property.
734    */
735   public function testComputedProperties() {
736     // All entity variations have to have the same results.
737     foreach (entity_test_entity_types() as $entity_type) {
738       $this->doTestComputedProperties($entity_type);
739     }
740   }
741
742   /**
743    * Tests all the interaction points of a computed field.
744    */
745   public function testComputedFields() {
746     $this->installEntitySchema('entity_test_computed_field');
747
748     \Drupal::state()->set('entity_test_computed_field_item_list_value', ['foo computed']);
749
750     // Check that the values are not computed unnecessarily during the lifecycle
751     // of an entity when the field is not interacted with directly.
752     \Drupal::state()->set('computed_test_field_execution', 0);
753     $entity = EntityTestComputedField::create([]);
754     $this->assertSame(0, \Drupal::state()->get('computed_test_field_execution', 0));
755
756     $entity->name->value = $this->randomString();
757     $this->assertSame(0, \Drupal::state()->get('computed_test_field_execution', 0));
758
759     $entity->save();
760     $this->assertSame(0, \Drupal::state()->get('computed_test_field_execution', 0));
761
762     // Test \Drupal\Core\TypedData\ComputedItemListTrait::getValue().
763     \Drupal::state()->set('computed_test_field_execution', 0);
764     $entity = EntityTestComputedField::create([]);
765     $this->assertSame([['value' => 'foo computed']], $entity->computed_string_field->getValue());
766
767     // Check that the values are only computed once.
768     $this->assertSame(1, \Drupal::state()->get('computed_test_field_execution', 0));
769
770     // Test \Drupal\Core\TypedData\ComputedItemListTrait::setValue(). This also
771     // checks that a subsequent getter does not try to re-compute the value.
772     \Drupal::state()->set('computed_test_field_execution', 0);
773     $entity = EntityTestComputedField::create([]);
774     $entity->computed_string_field->setValue([
775       ['value' => 'foo computed 1'],
776       ['value' => 'foo computed 2'],
777     ]);
778     $this->assertSame([['value' => 'foo computed 1'], ['value' => 'foo computed 2']], $entity->computed_string_field->getValue());
779
780     // Check that the values have not been computed when they were explicitly
781     // set.
782     $this->assertSame(0, \Drupal::state()->get('computed_test_field_execution', 0));
783
784     // Test \Drupal\Core\TypedData\ComputedItemListTrait::getString().
785     $entity = EntityTestComputedField::create([]);
786     $this->assertSame('foo computed', $entity->computed_string_field->getString());
787
788     // Test \Drupal\Core\TypedData\ComputedItemListTrait::get().
789     $entity = EntityTestComputedField::create([]);
790     $this->assertSame('foo computed', $entity->computed_string_field->get(0)->value);
791     $this->assertEmpty($entity->computed_string_field->get(1));
792
793     // Test \Drupal\Core\TypedData\ComputedItemListTrait::set().
794     $entity = EntityTestComputedField::create([]);
795     $entity->computed_string_field->set(1, 'foo computed 1');
796     $this->assertSame('foo computed', $entity->computed_string_field[0]->value);
797     $this->assertSame('foo computed 1', $entity->computed_string_field[1]->value);
798     $entity->computed_string_field->set(0, 'foo computed 0');
799     $this->assertSame('foo computed 0', $entity->computed_string_field[0]->value);
800     $this->assertSame('foo computed 1', $entity->computed_string_field[1]->value);
801
802     // Test \Drupal\Core\TypedData\ComputedItemListTrait::appendItem().
803     $entity = EntityTestComputedField::create([]);
804     $entity->computed_string_field->appendItem('foo computed 1');
805     $this->assertSame('foo computed', $entity->computed_string_field[0]->value);
806     $this->assertSame('foo computed 1', $entity->computed_string_field[1]->value);
807
808     // Test \Drupal\Core\TypedData\ComputedItemListTrait::removeItem().
809     $entity = EntityTestComputedField::create([]);
810     $entity->computed_string_field->removeItem(0);
811     $this->assertTrue($entity->computed_string_field->isEmpty());
812
813     // Test \Drupal\Core\TypedData\ComputedItemListTrait::isEmpty().
814     \Drupal::state()->set('entity_test_computed_field_item_list_value', []);
815     $entity = EntityTestComputedField::create([]);
816     $this->assertTrue($entity->computed_string_field->isEmpty());
817
818     \Drupal::state()->set('entity_test_computed_field_item_list_value', ['foo computed']);
819     $entity = EntityTestComputedField::create([]);
820     $this->assertFalse($entity->computed_string_field->isEmpty());
821
822     // Test \Drupal\Core\TypedData\ComputedItemListTrait::filter().
823     $filter_callback = function ($item) {
824       return !$item->isEmpty();
825     };
826     $entity = EntityTestComputedField::create([]);
827     $entity->computed_string_field->filter($filter_callback);
828     $this->assertCount(1, $entity->computed_string_field);
829
830     // Add an empty item to the list and check that it is filtered out.
831     $entity->computed_string_field->appendItem();
832     $entity->computed_string_field->filter($filter_callback);
833     $this->assertCount(1, $entity->computed_string_field);
834
835     // Add a non-empty item to the list and check that it is not filtered out.
836     $entity->computed_string_field->appendItem('foo computed 1');
837     $entity->computed_string_field->filter($filter_callback);
838     $this->assertCount(2, $entity->computed_string_field);
839
840     // Test \Drupal\Core\TypedData\ComputedItemListTrait::offsetExists().
841     $entity = EntityTestComputedField::create([]);
842     $this->assertTrue($entity->computed_string_field->offsetExists(0));
843     $this->assertFalse($entity->computed_string_field->offsetExists(1));
844
845     // Test \Drupal\Core\TypedData\ComputedItemListTrait::getIterator().
846     $entity = EntityTestComputedField::create([]);
847     foreach ($entity->computed_string_field as $delta => $item) {
848       $this->assertSame('foo computed', $item->value);
849     }
850
851     // Test \Drupal\Core\TypedData\ComputedItemListTrait::count().
852     $entity = EntityTestComputedField::create([]);
853     $this->assertCount(1, $entity->computed_string_field);
854
855     // Check that computed items are not auto-created when they have no values.
856     \Drupal::state()->set('entity_test_computed_field_item_list_value', []);
857     $entity = EntityTestComputedField::create([]);
858     $this->assertCount(0, $entity->computed_string_field);
859
860     // Test \Drupal\Core\Field\FieldItemList::equals() for a computed field.
861     \Drupal::state()->set('entity_test_computed_field_item_list_value', ['foo computed']);
862     $entity = EntityTestComputedField::create([]);
863     $computed_item_list1 = $entity->computed_string_field;
864
865     $entity = EntityTestComputedField::create([]);
866     $computed_item_list2 = $entity->computed_string_field;
867
868     $this->assertTrue($computed_item_list1->equals($computed_item_list2));
869
870     $computed_item_list2->value = 'foo computed 2';
871     $this->assertFalse($computed_item_list1->equals($computed_item_list2));
872   }
873
874   /**
875    * Tests an entity reference computed field.
876    */
877   public function testEntityReferenceComputedField() {
878     $this->installEntitySchema('entity_test_computed_field');
879
880     // Create 2 entities to be referenced.
881     $ref1 = EntityTest::create(['name' => 'foo', 'type' => 'bar']);
882     $ref1->save();
883     $ref2 = EntityTest::create(['name' => 'baz', 'type' => 'bar']);
884     $ref2->save();
885     \Drupal::state()->set('entity_test_reference_computed_target_ids', [$ref1->id(), $ref2->id()]);
886
887     $entity = EntityTestComputedField::create([]);
888     $entity->save();
889
890     /** @var \Drupal\entity_test\Plugin\Field\ComputedReferenceTestFieldItemList $field */
891     $field = $entity->get('computed_reference_field');
892     /** @var \Drupal\Core\Entity\EntityInterface[] $referenced_entities */
893     $referenced_entities = $field->referencedEntities();
894
895     // Check that ::referencedEntities() is working with computed fields.
896     $this->assertEquals($ref1->id(), $referenced_entities[0]->id());
897     $this->assertEquals($ref2->id(), $referenced_entities[1]->id());
898   }
899
900   /**
901    * Executes the computed properties tests for the given entity type.
902    *
903    * @param string $entity_type
904    *   The entity type to run the tests with.
905    */
906   protected function doTestComputedProperties($entity_type) {
907     $entity = $this->createTestEntity($entity_type);
908     $entity->field_test_text->value = "The <strong>text</strong> text to filter.";
909     $entity->field_test_text->format = filter_default_format();
910
911     $target = "<p>The &lt;strong&gt;text&lt;/strong&gt; text to filter.</p>\n";
912     $this->assertEqual($entity->field_test_text->processed, $target, format_string('%entity_type: Text is processed with the default filter.', ['%entity_type' => $entity_type]));
913
914     // Save and load entity and make sure it still works.
915     $entity->save();
916     $entity = $this->container->get('entity_type.manager')
917       ->getStorage($entity_type)
918       ->load($entity->id());
919     $this->assertEqual($entity->field_test_text->processed, $target, format_string('%entity_type: Text is processed with the default filter.', ['%entity_type' => $entity_type]));
920   }
921
922 }