Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / system / tests / modules / entity_test / entity_test.module
1 <?php
2
3 /**
4  * @file
5  * Test module for the entity API providing several entity types for testing.
6  */
7
8 use Drupal\Core\Access\AccessResult;
9 use Drupal\Core\Entity\ContentEntityInterface;
10 use Drupal\Core\Entity\EntityInterface;
11 use Drupal\Core\Entity\FieldableEntityInterface;
12 use Drupal\Core\Entity\EntityTypeInterface;
13 use Drupal\Core\Field\BaseFieldDefinition;
14 use Drupal\Core\Field\FieldDefinitionInterface;
15 use Drupal\Core\Field\FieldItemListInterface;
16 use Drupal\Core\Field\FieldStorageDefinitionInterface;
17 use Drupal\Core\Form\FormStateInterface;
18 use Drupal\Core\Session\AccountInterface;
19 use Drupal\Core\Entity\Entity\EntityFormDisplay;
20 use Drupal\Core\Url;
21
22 /**
23  * Filter that limits test entity list to revisable ones.
24  */
25 const ENTITY_TEST_TYPES_REVISABLE = 1;
26
27 /**
28  * Filter that limits test entity list to multilingual ones.
29  */
30 const ENTITY_TEST_TYPES_MULTILINGUAL = 2;
31
32 /**
33  * Filter that limits test entity list to routeable ones.
34  */
35 const ENTITY_TEST_TYPES_ROUTING = 3;
36
37 /**
38  * Returns a list of test entity types.
39  *
40  * The returned entity types are one for each available entity storage type:
41  * - The plain entity_test type supports neither revisions nor multilingual
42  *   properties.
43  * - The entity_test_mul type supports multilingual properties.
44  * - The entity_test_rev type supports revisions.
45  * - The entity_test_mulrev type supports both revisions and multilingual
46  *   properties.
47  *
48  * @param int $filter
49  *   Either ENTITY_TEST_TYPES_REVISABLE to only return revisable entity types or
50  *   ENTITY_TEST_TYPES_MULTILINGUAL to only return multilingual ones. Defaults
51  *   to NULL, which returns all.
52  *
53  * @return array
54  *   List with entity_types.
55  */
56 function entity_test_entity_types($filter = NULL) {
57   $types = [];
58   if ($filter === NULL || $filter === ENTITY_TEST_TYPES_ROUTING) {
59     $types[] = 'entity_test';
60   }
61   if ($filter != ENTITY_TEST_TYPES_REVISABLE) {
62     $types[] = 'entity_test_mul';
63     $types[] = 'entity_test_mul_langcode_key';
64     $types[] = 'entity_test_mul_changed';
65   }
66   if ($filter != ENTITY_TEST_TYPES_MULTILINGUAL) {
67     $types[] = 'entity_test_rev';
68   }
69   if ($filter === ENTITY_TEST_TYPES_ROUTING) {
70     $types[] = 'entity_test_base_field_display';
71     $types[] = 'entity_test_string_id';
72     $types[] = 'entity_test_no_id';
73   }
74   $types[] = 'entity_test_mulrev';
75   $types[] = 'entity_test_mulrev_changed';
76
77   return array_combine($types, $types);
78 }
79
80 /**
81  * Implements hook_entity_type_alter().
82  */
83 function entity_test_entity_type_alter(array &$entity_types) {
84   $state = \Drupal::state();
85
86   /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
87   foreach (entity_test_entity_types() as $entity_type) {
88     // Optionally specify a translation handler for testing translations.
89     if ($state->get('entity_test.translation')) {
90       $translation = $entity_types[$entity_type]->get('translation');
91       $translation[$entity_type] = TRUE;
92       $entity_types[$entity_type]->set('translation', $translation);
93     }
94   }
95
96   // Allow entity_test_with_bundle tests to override the entity type definition.
97   $entity_types['entity_test_with_bundle'] = $state->get('entity_test_with_bundle.entity_type', $entity_types['entity_test_with_bundle']);
98
99   // Enable the entity_test_new only when needed.
100   if (!$state->get('entity_test_new')) {
101     unset($entity_types['entity_test_new']);
102   }
103 }
104
105 /**
106  * Implements hook_module_implements_alter().
107  */
108 function entity_test_module_implements_alter(&$implementations, $hook) {
109   // Move our hook_entity_type_alter() implementation to the beginning of the
110   // list in order to run before content_moderation_entity_type_alter().
111   if ($hook === 'entity_type_alter') {
112     $implementations = ['entity_test' => $implementations['entity_test']] + $implementations;
113   }
114 }
115
116 /**
117  * Implements hook_entity_base_field_info().
118  */
119 function entity_test_entity_base_field_info(EntityTypeInterface $entity_type) {
120   $fields = [];
121
122   if ($entity_type->id() == 'entity_test_mulrev' && \Drupal::state()->get('entity_test.field_test_item')) {
123     $fields['field_test_item'] = BaseFieldDefinition::create('field_test')
124       ->setLabel(t('Field test'))
125       ->setDescription(t('A field test.'))
126       ->setRevisionable(TRUE)
127       ->setTranslatable(TRUE);
128   }
129   if ($entity_type->id() == 'entity_test_mulrev' && \Drupal::state()->get('entity_test.multi_column')) {
130     $fields['description'] = BaseFieldDefinition::create('shape')
131       ->setLabel(t('Some custom description'))
132       ->setTranslatable(TRUE);
133   }
134
135   return $fields;
136 }
137
138 /**
139  * Implements hook_entity_base_field_info_alter().
140  */
141 function entity_test_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) {
142   $state = \Drupal::state();
143   if ($entity_type->id() == 'entity_test_mulrev' && ($names = $state->get('entity_test.field_definitions.translatable'))) {
144     foreach ($names as $name => $value) {
145       $fields[$name]->setTranslatable($value);
146     }
147   }
148   if ($entity_type->id() == 'node' && $state->get('entity_test.node_remove_status_field')) {
149     unset($fields['status']);
150   }
151   if ($entity_type->id() == 'entity_test' && $state->get('entity_test.remove_name_field')) {
152     unset($fields['name']);
153   }
154   // In 8001 we are assuming that a new definition with multiple cardinality has
155   // been deployed.
156   // @todo Remove this if we end up using state definitions at runtime. See
157   //    https://www.drupal.org/node/2554235.
158   if ($entity_type->id() == 'entity_test' && $state->get('entity_test.db_updates.entity_definition_updates') == 8001) {
159     $fields['user_id']->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
160   }
161 }
162
163 /**
164  * Creates a new bundle for entity_test entities.
165  *
166  * @param string $bundle
167  *   The machine-readable name of the bundle.
168  * @param string $text
169  *   (optional) The human-readable name of the bundle. If none is provided, the
170  *   machine name will be used.
171  * @param string $entity_type
172  *   (optional) The entity type for which the bundle is created. Defaults to
173  *   'entity_test'.
174  */
175 function entity_test_create_bundle($bundle, $text = NULL, $entity_type = 'entity_test') {
176   $bundles = \Drupal::state()->get($entity_type . '.bundles') ?: [$entity_type => ['label' => 'Entity Test Bundle']];
177   $bundles += [$bundle => ['label' => $text ? $text : $bundle]];
178   \Drupal::state()->set($entity_type . '.bundles', $bundles);
179
180   \Drupal::entityManager()->onBundleCreate($bundle, $entity_type);
181 }
182
183 /**
184  * Deletes a bundle for entity_test entities.
185  *
186  * @param string $bundle
187  *   The machine-readable name of the bundle to delete.
188  * @param string $entity_type
189  *   (optional) The entity type for which the bundle is deleted. Defaults to
190  *   'entity_test'.
191  */
192 function entity_test_delete_bundle($bundle, $entity_type = 'entity_test') {
193   $bundles = \Drupal::state()->get($entity_type . '.bundles') ?: [$entity_type => ['label' => 'Entity Test Bundle']];
194   unset($bundles[$bundle]);
195   \Drupal::state()->set($entity_type . '.bundles', $bundles);
196
197   \Drupal::entityManager()->onBundleDelete($bundle, $entity_type);
198 }
199
200 /**
201  * Implements hook_entity_bundle_info().
202  */
203 function entity_test_entity_bundle_info() {
204   $bundles = [];
205   $entity_types = \Drupal::entityManager()->getDefinitions();
206   foreach ($entity_types as $entity_type_id => $entity_type) {
207     if ($entity_type->getProvider() == 'entity_test' && $entity_type_id != 'entity_test_with_bundle') {
208       $bundles[$entity_type_id] = \Drupal::state()->get($entity_type_id . '.bundles') ?: [$entity_type_id => ['label' => 'Entity Test Bundle']];
209     }
210   }
211   return $bundles;
212 }
213
214 /**
215  * Implements hook_entity_view_mode_info_alter().
216  */
217 function entity_test_entity_view_mode_info_alter(&$view_modes) {
218   $entity_info = \Drupal::entityManager()->getDefinitions();
219   foreach ($entity_info as $entity_type => $info) {
220     if ($entity_info[$entity_type]->getProvider() == 'entity_test' && !isset($view_modes[$entity_type])) {
221       $view_modes[$entity_type] = [
222         'full' => [
223           'label' => t('Full object'),
224           'status' => TRUE,
225           'cache' => TRUE,
226         ],
227         'teaser' => [
228           'label' => t('Teaser'),
229           'status' => TRUE,
230           'cache' => TRUE,
231         ],
232       ];
233     }
234   }
235 }
236
237 /**
238  * Implements hook_entity_form_mode_info_alter().
239  */
240 function entity_test_entity_form_mode_info_alter(&$form_modes) {
241   $entity_info = \Drupal::entityManager()->getDefinitions();
242   foreach ($entity_info as $entity_type => $info) {
243     if ($entity_info[$entity_type]->getProvider() == 'entity_test') {
244       $form_modes[$entity_type] = [
245         'compact' => [
246           'label' => t('Compact version'),
247           'status' => TRUE,
248         ],
249       ];
250     }
251   }
252 }
253
254 /**
255  * Implements hook_entity_extra_field_info().
256  */
257 function entity_test_entity_extra_field_info() {
258   $extra['entity_test']['bundle_with_extra_fields'] = [
259     'display' => [
260       // Note: those extra fields do not currently display anything, they are
261       // just used in \Drupal\Tests\field_ui\Kernel\EntityDisplayTest to test
262       // the behavior of entity display objects.
263       'display_extra_field' => [
264         'label' => t('Display extra field'),
265         'description' => t('An extra field on the display side.'),
266         'weight' => 5,
267         'visible' => TRUE,
268       ],
269       'display_extra_field_hidden' => [
270         'label' => t('Display extra field (hidden)'),
271         'description' => t('An extra field on the display side, hidden by default.'),
272         'visible' => FALSE,
273       ],
274     ]
275   ];
276
277   return $extra;
278 }
279
280 /**
281  * Implements hook_form_BASE_FORM_ID_alter().
282  */
283 function entity_test_form_entity_test_form_alter(&$form) {
284   switch (\Drupal::state()->get('entity_test.form.validate.test')) {
285     case 'form-level':
286       $form['#validate'][] = 'entity_test_form_entity_test_form_validate';
287       $form['#validate'][] = 'entity_test_form_entity_test_form_validate_check';
288       break;
289
290     case 'button-level':
291       $form['actions']['submit']['#validate'][] = 'entity_test_form_entity_test_form_validate';
292   }
293 }
294
295 /**
296  * Validation handler for the entity_test entity form.
297  */
298 function entity_test_form_entity_test_form_validate(array &$form, FormStateInterface $form_state) {
299   $form['#entity_test_form_validate'] = TRUE;
300 }
301
302 /**
303  * Validation handler for the entity_test entity form.
304  */
305 function entity_test_form_entity_test_form_validate_check(array &$form, FormStateInterface $form_state) {
306   if (!empty($form['#entity_test_form_validate'])) {
307     \Drupal::state()->set('entity_test.form.validate.result', TRUE);
308   }
309 }
310
311 /**
312  * Implements hook_form_BASE_FORM_ID_alter().
313  */
314 function entity_test_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
315   $langcode = $form_state->getFormObject()->getFormLangcode($form_state);
316   \Drupal::state()->set('entity_test.form_langcode', $langcode);
317 }
318
319 /**
320  * Loads a test entity.
321  *
322  * @param int $id
323  *   A test entity ID.
324  * @param bool $reset
325  *   A boolean indicating that the internal cache should be reset.
326  *
327  * @return \Drupal\entity_test\Entity\EntityTest
328  *   The loaded entity object, or NULL if the entity cannot be loaded.
329  */
330 function entity_test_load($id, $reset = FALSE) {
331   $storage = \Drupal::entityTypeManager()->getStorage('entity_test');
332   if ($reset) {
333     $storage->resetCache([$id]);
334   }
335   return $storage->load($id);
336 }
337
338 /**
339  * Loads a test entity.
340  *
341  * @param int $id
342  *   A test entity ID.
343  * @param bool $reset
344  *   A boolean indicating that the internal cache should be reset.
345  *
346  * @return \Drupal\entity_test\Entity\EntityTestRev
347  *   The loaded entity object, or NULL if the entity cannot be loaded.
348  */
349 function entity_test_rev_load($id, $reset = FALSE) {
350   $storage = \Drupal::entityTypeManager()->getStorage('entity_test_rev');
351   if ($reset) {
352     $storage->resetCache([$id]);
353   }
354   return $storage->load($id);
355 }
356
357 /**
358  * Loads a test entity.
359  *
360  * @param int $id
361  *   A test entity ID.
362  * @param bool $reset
363  *   A boolean indicating that the internal cache should be reset.
364  *
365  * @return \Drupal\entity_test\Entity\EntityTestMul
366  *   The loaded entity object, or FALSE if the entity cannot be loaded.
367  */
368 function entity_test_mul_load($id, $reset = FALSE) {
369   $storage = \Drupal::entityTypeManager()->getStorage('entity_test_mul');
370   if ($reset) {
371     $storage->resetCache([$id]);
372   }
373   return $storage->load($id);
374 }
375
376 /**
377  * Loads a test entity.
378  *
379  * @param int $id
380  *   A test entity ID.
381  * @param bool $reset
382  *   A boolean indicating that the internal cache should be reset.
383  *
384  * @return \Drupal\entity_test\Entity\EntityTestMulRev
385  *   The loaded entity object, or NULL if the entity cannot be loaded.
386  */
387 function entity_test_mulrev_load($id, $reset = FALSE) {
388   $storage = \Drupal::entityTypeManager()->getStorage('entity_test_mulrev');
389   if ($reset) {
390     $storage->resetCache([$id]);
391   }
392   return $storage->load($id);
393 }
394
395 /**
396  * Implements hook_ENTITY_TYPE_insert() for 'entity_test'.
397  */
398 function entity_test_entity_test_insert($entity) {
399   if ($entity->name->value == 'fail_insert') {
400     throw new Exception("Test exception rollback.");
401   }
402 }
403
404 /**
405  * Implements hook_entity_insert().
406  */
407 function entity_test_entity_insert(EntityInterface $entity) {
408   if ($entity->getEntityTypeId() == 'entity_test_mulrev' && $entity->label() == 'EntityLoadedRevisionTest') {
409     $entity->setNewRevision(FALSE);
410     $entity->save();
411   }
412 }
413
414 /**
415  * Implements hook_entity_update().
416  */
417 function entity_test_entity_update(EntityInterface $entity) {
418   if ($entity instanceof ContentEntityInterface) {
419     \Drupal::state()->set('entity_test.loadedRevisionId', $entity->getLoadedRevisionId());
420   }
421 }
422
423 /**
424  * Implements hook_entity_field_access().
425  *
426  * @see \Drupal\system\Tests\Entity\FieldAccessTest::testFieldAccess()
427  */
428 function entity_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
429   if ($field_definition->getName() == 'field_test_text') {
430     if ($items) {
431       if ($items->value == 'no access value') {
432         return AccessResult::forbidden()->addCacheableDependency($items->getEntity());
433       }
434       elseif ($items->value == 'custom cache tag value') {
435         return AccessResult::allowed()->addCacheableDependency($items->getEntity())->addCacheTags(['entity_test_access:field_test_text']);
436       }
437       elseif ($operation == 'edit' && $items->value == 'no edit access value') {
438         return AccessResult::forbidden()->addCacheableDependency($items->getEntity());
439       }
440     }
441   }
442   if ($field = \Drupal::state()->get('views_field_access_test-field')) {
443     if ($field_definition->getName() === $field) {
444       $result = AccessResult::allowedIfHasPermission($account, 'view test entity field');
445       // For test purposes we want to actively deny access.
446       if ($result->isNeutral()) {
447         $result = AccessResult::forbidden();
448       }
449       return $result;
450     }
451   }
452
453   // No opinion.
454   return AccessResult::neutral();
455 }
456
457 /**
458  * Implements hook_entity_field_access_alter().
459  *
460  * @see \Drupal\system\Tests\Entity\FieldAccessTest::testFieldAccess()
461  */
462 function entity_test_entity_field_access_alter(array &$grants, array $context) {
463   if ($context['field_definition']->getName() == 'field_test_text' && $context['items']->value == 'access alter value') {
464     $grants[':default'] = AccessResult::forbidden()->inheritCacheability($grants[':default'])->addCacheableDependency($context['items']->getEntity());
465   }
466 }
467
468 /**
469  * Implements hook_entity_form_display_alter().
470  */
471 function entity_test_entity_form_display_alter(EntityFormDisplay $form_display, $context) {
472   // Make the field_test_text field 42 characters for entity_test_mul.
473   if ($context['entity_type'] == 'entity_test') {
474     if ($component_options = $form_display->getComponent('field_test_text')) {
475       $component_options['settings']['size'] = 42;
476       $form_display->setComponent('field_test_text', $component_options);
477     }
478   }
479 }
480
481 /**
482  * Implements hook_entity_presave().
483  */
484 function entity_test_entity_presave(EntityInterface $entity) {
485   if (isset($GLOBALS['entity_test_throw_exception'])) {
486     throw new Exception('Entity presave exception', 1);
487   }
488
489   if ($entity->getEntityType()->id() == 'entity_view_display') {
490     $entity->setThirdPartySetting('entity_test', 'foo', 'bar');
491   }
492 }
493
494 /**
495  * Implements hook_entity_predelete().
496  */
497 function entity_test_entity_predelete(EntityInterface $entity) {
498   if (isset($GLOBALS['entity_test_throw_exception'])) {
499     throw new Exception('Entity predelete exception', 2);
500   }
501 }
502
503 /**
504  * Implements hook_entity_operation_alter().
505  */
506 function entity_test_entity_operation_alter(array &$operations, EntityInterface $entity) {
507   $valid_entity_type_ids = [
508     'user_role',
509     'block',
510   ];
511   if (in_array($entity->getEntityTypeId(), $valid_entity_type_ids)) {
512     if (\Drupal::service('router.route_provider')->getRouteByName("entity.{$entity->getEntityTypeId()}.test_operation")) {
513       $operations['test_operation'] = [
514         'title' => format_string('Test Operation: @label', ['@label' => $entity->label()]),
515         'url' => Url::fromRoute("entity.{$entity->getEntityTypeId()}.test_operation", [$entity->getEntityTypeId() => $entity->id()]),
516         'weight' => 50,
517       ];
518     }
519   }
520 }
521
522 /**
523  * Implements hook_entity_translation_create().
524  */
525 function entity_test_entity_translation_create(EntityInterface $translation) {
526   _entity_test_record_hooks('entity_translation_create', $translation->language()->getId());
527 }
528
529 /**
530  * Implements hook_entity_translation_insert().
531  */
532 function entity_test_entity_translation_insert(EntityInterface $translation) {
533   _entity_test_record_hooks('entity_translation_insert', $translation->language()->getId());
534 }
535
536 /**
537  * Implements hook_entity_translation_delete().
538  */
539 function entity_test_entity_translation_delete(EntityInterface $translation) {
540   _entity_test_record_hooks('entity_translation_delete', $translation->language()->getId());
541 }
542
543 /**
544  * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul'.
545  */
546 function entity_test_entity_test_mul_translation_create(EntityInterface $translation) {
547   _entity_test_record_hooks('entity_test_mul_translation_create', $translation->language()->getId());
548 }
549
550 /**
551  * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul'.
552  */
553 function entity_test_entity_test_mul_translation_insert(EntityInterface $translation) {
554   _entity_test_record_hooks('entity_test_mul_translation_insert', $translation->language()->getId());
555 }
556
557 /**
558  * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mul'.
559  */
560 function entity_test_entity_test_mul_translation_delete(EntityInterface $translation) {
561   _entity_test_record_hooks('entity_test_mul_translation_delete', $translation->language()->getId());
562 }
563
564 /**
565  * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul_changed'.
566  */
567 function entity_test_entity_test_mul_changed_translation_create(EntityInterface $translation) {
568   _entity_test_record_hooks('entity_test_mul_changed_translation_create', $translation->language()->getId());
569 }
570
571 /**
572  * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul_changed'.
573  */
574 function entity_test_entity_test_mul_changed_translation_insert(EntityInterface $translation) {
575   _entity_test_record_hooks('entity_test_mul_changed_translation_insert', $translation->language()->getId());
576 }
577
578 /**
579  * Implements hook_ENTITY_TYPE_translation_delete().
580  */
581 function entity_test_entity_test_mul_changed_translation_delete(EntityInterface $translation) {
582   _entity_test_record_hooks('entity_test_mul_changed_translation_delete', $translation->language()->getId());
583 }
584
585 /**
586  * Implements hook_ENTITY_TYPE_translation_create().
587  */
588 function entity_test_entity_test_mulrev_translation_create(EntityInterface $translation) {
589   _entity_test_record_hooks('entity_test_mulrev_translation_create', $translation->language()->getId());
590 }
591
592 /**
593  * Implements hook_ENTITY_TYPE_translation_insert().
594  */
595 function entity_test_entity_test_mulrev_translation_insert(EntityInterface $translation) {
596   _entity_test_record_hooks('entity_test_mulrev_translation_insert', $translation->language()->getId());
597 }
598
599 /**
600  * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mulrev'.
601  */
602 function entity_test_entity_test_mulrev_translation_delete(EntityInterface $translation) {
603   _entity_test_record_hooks('entity_test_mulrev_translation_delete', $translation->language()->getId());
604 }
605
606 /**
607  * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mulrev_changed'.
608  */
609 function entity_test_entity_test_mulrev_changed_translation_create(EntityInterface $translation) {
610   _entity_test_record_hooks('entity_test_mulrev_changed_translation_create', $translation->language()->getId());
611 }
612
613 /**
614  * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mulrev'.
615  */
616 function entity_test_entity_test_mulrev_changed_translation_insert(EntityInterface $translation) {
617   _entity_test_record_hooks('entity_test_mulrev_changed_translation_insert', $translation->language()->getId());
618 }
619
620 /**
621  * Implements hook_ENTITY_TYPE_translation_delete().
622  */
623 function entity_test_entity_test_mulrev_changed_translation_delete(EntityInterface $translation) {
624   _entity_test_record_hooks('entity_test_mulrev_changed_translation_delete', $translation->language()->getId());
625 }
626
627 /**
628  * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul_langcode_key'.
629  */
630 function entity_test_entity_test_mul_langcode_key_translation_create(EntityInterface $translation) {
631   _entity_test_record_hooks('entity_test_mul_langcode_key_translation_create', $translation->language()->getId());
632 }
633
634 /**
635  * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul_langcode_key'.
636  */
637 function entity_test_entity_test_mul_langcode_key_translation_insert(EntityInterface $translation) {
638   _entity_test_record_hooks('entity_test_mul_langcode_key_translation_insert', $translation->language()->getId());
639 }
640
641 /**
642  * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mul_langcode_key'.
643  */
644 function entity_test_entity_test_mul_langcode_key_translation_delete(EntityInterface $translation) {
645   _entity_test_record_hooks('entity_test_mul_langcode_key_translation_delete', $translation->language()->getId());
646 }
647
648 /**
649  * Field default value callback.
650  *
651  * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
652  *   The entity being created.
653  * @param \Drupal\Core\Field\FieldDefinitionInterface $definition
654  *   The field definition.
655  *
656  * @return array
657  *   An array of default values, in the same format as the $default_value
658  *   property.
659  *
660  * @see \Drupal\field\Entity\FieldConfig::$default_value
661  */
662 function entity_test_field_default_value(FieldableEntityInterface $entity, FieldDefinitionInterface $definition) {
663   // Include the field name and entity language in the generated values to check
664   // that they are correctly passed.
665   $string = $definition->getName() . '_' . $entity->language()->getId();
666   // Return a "default value" with multiple items.
667   return [
668     [
669       'shape' => "shape:0:$string",
670       'color' => "color:0:$string",
671     ],
672     [
673       'shape' => "shape:1:$string",
674       'color' => "color:1:$string",
675     ],
676   ];
677 }
678
679 /**
680  * Helper function to be used to record hook invocations.
681  *
682  * @param string $hook
683  *   The hook name.
684  * @param mixed $data
685  *   Arbitrary data associated with the hook invocation.
686  */
687 function _entity_test_record_hooks($hook, $data) {
688   $state = \Drupal::state();
689   $key = 'entity_test.hooks';
690   $hooks = $state->get($key);
691   $hooks[$hook] = $data;
692   $state->set($key, $hooks);
693 }
694
695 /**
696  * Implements hook_entity_prepare_view().
697  */
698 function entity_test_entity_prepare_view($entity_type, array $entities, array $displays) {
699   if ($entity_type == 'entity_test') {
700     foreach ($entities as $entity) {
701       /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
702
703       // Add a dummy field item attribute on field_test_text if it exists.
704       if ($entity->hasField('field_test_text') && $displays[$entity->bundle()]->getComponent('field_test_text')) {
705         foreach ($entity->get('field_test_text') as $item) {
706           $item->_attributes += ['data-field-item-attr' => 'foobar'];
707         }
708       }
709
710       // Add a dummy field item attribute on daterange fields if they exist.
711       $fields = $entity->getFieldDefinitions();
712       foreach ($fields as $field) {
713         if ($field->getType() === 'daterange') {
714           $item = $entity->get($field->getName());
715           $item->_attributes += ['data-field-item-attr' => 'foobar'];
716         }
717       }
718     }
719   }
720 }
721
722 /**
723  * Implements hook_entity_display_build_alter().
724  */
725 function entity_test_entity_display_build_alter(&$build, $context) {
726   /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
727   $entity = $context['entity'];
728   if ($entity->getEntityTypeId() == 'entity_test' && $entity->bundle() == 'display_build_alter_bundle') {
729     $build['entity_display_build_alter']['#markup'] = 'Content added in hook_entity_display_build_alter for entity id ' . $entity->id();
730   }
731 }
732
733 /**
734  * Implements hook_entity_access().
735  */
736 function entity_test_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
737   // Only apply to the 'entity_test' entities.
738   if ($entity->getEntityType()->getProvider() != 'entity_test') {
739     return AccessResult::neutral();
740   }
741   \Drupal::state()->set('entity_test_entity_access', TRUE);
742
743   // Attempt to allow access to entities with the title forbid_access,
744   // this will be overridden by
745   // \Drupal\entity_test\EntityTestAccessControlHandler::checkAccess().
746   if ($entity->label() == 'forbid_access') {
747     return AccessResult::allowed();
748   }
749
750   // Create specific labels to allow or deny access based on certain test
751   // conditions.
752   // @see \Drupal\KernelTests\Core\Entity\EntityAccessControlHandlerTest
753   if ($entity->label() == 'Accessible') {
754     return AccessResult::allowed();
755   }
756   if ($entity->label() == 'Inaccessible') {
757     return AccessResult::forbidden();
758   }
759
760   // Uncacheable because the access result depends on a State key-value pair and
761   // might therefore change at any time.
762   $condition = \Drupal::state()->get("entity_test_entity_access.{$operation}." . $entity->id(), FALSE);
763   return AccessResult::allowedIf($condition)->setCacheMaxAge(0);
764 }
765
766 /**
767  * Implements hook_ENTITY_TYPE_access() for 'entity_test'.
768  */
769 function entity_test_entity_test_access(EntityInterface $entity, $operation, AccountInterface $account) {
770   \Drupal::state()->set('entity_test_entity_test_access', TRUE);
771
772   // No opinion.
773   return AccessResult::neutral();
774 }
775
776 /**
777  * Implements hook_entity_create_access().
778  */
779 function entity_test_entity_create_access(AccountInterface $account, $context, $entity_bundle) {
780   \Drupal::state()->set('entity_test_entity_create_access', TRUE);
781   \Drupal::state()->set('entity_test_entity_create_access_context', $context);
782
783   // No opinion.
784   return AccessResult::neutral();
785 }
786
787 /**
788  * Implements hook_ENTITY_TYPE_create_access() for 'entity_test'.
789  */
790 function entity_test_entity_test_create_access(AccountInterface $account, $context, $entity_bundle) {
791   \Drupal::state()->set('entity_test_entity_test_create_access', TRUE);
792
793   // No opinion.
794   return AccessResult::neutral();
795 }