e5fa873d0969ec954e2b54ce62d5026e854f447e
[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  * Implements hook_entity_field_storage_info().
165  */
166 function entity_test_entity_field_storage_info(EntityTypeInterface $entity_type) {
167   if ($entity_type->id() == 'entity_test_update') {
168     return \Drupal::state()->get('entity_test_update.additional_field_storage_definitions', []);
169   }
170 }
171
172 /**
173  * Creates a new bundle for entity_test entities.
174  *
175  * @param string $bundle
176  *   The machine-readable name of the bundle.
177  * @param string $text
178  *   (optional) The human-readable name of the bundle. If none is provided, the
179  *   machine name will be used.
180  * @param string $entity_type
181  *   (optional) The entity type for which the bundle is created. Defaults to
182  *   'entity_test'.
183  */
184 function entity_test_create_bundle($bundle, $text = NULL, $entity_type = 'entity_test') {
185   $bundles = \Drupal::state()->get($entity_type . '.bundles') ?: [$entity_type => ['label' => 'Entity Test Bundle']];
186   $bundles += [$bundle => ['label' => $text ? $text : $bundle]];
187   \Drupal::state()->set($entity_type . '.bundles', $bundles);
188
189   \Drupal::entityManager()->onBundleCreate($bundle, $entity_type);
190 }
191
192 /**
193  * Deletes a bundle for entity_test entities.
194  *
195  * @param string $bundle
196  *   The machine-readable name of the bundle to delete.
197  * @param string $entity_type
198  *   (optional) The entity type for which the bundle is deleted. Defaults to
199  *   'entity_test'.
200  */
201 function entity_test_delete_bundle($bundle, $entity_type = 'entity_test') {
202   $bundles = \Drupal::state()->get($entity_type . '.bundles') ?: [$entity_type => ['label' => 'Entity Test Bundle']];
203   unset($bundles[$bundle]);
204   \Drupal::state()->set($entity_type . '.bundles', $bundles);
205
206   \Drupal::entityManager()->onBundleDelete($bundle, $entity_type);
207 }
208
209 /**
210  * Implements hook_entity_bundle_info().
211  */
212 function entity_test_entity_bundle_info() {
213   $bundles = [];
214   $entity_types = \Drupal::entityManager()->getDefinitions();
215   foreach ($entity_types as $entity_type_id => $entity_type) {
216     if ($entity_type->getProvider() == 'entity_test' && $entity_type_id != 'entity_test_with_bundle') {
217       $bundles[$entity_type_id] = \Drupal::state()->get($entity_type_id . '.bundles') ?: [$entity_type_id => ['label' => 'Entity Test Bundle']];
218     }
219   }
220   return $bundles;
221 }
222
223 /**
224  * Implements hook_entity_view_mode_info_alter().
225  */
226 function entity_test_entity_view_mode_info_alter(&$view_modes) {
227   $entity_info = \Drupal::entityManager()->getDefinitions();
228   foreach ($entity_info as $entity_type => $info) {
229     if ($entity_info[$entity_type]->getProvider() == 'entity_test' && !isset($view_modes[$entity_type])) {
230       $view_modes[$entity_type] = [
231         'full' => [
232           'label' => t('Full object'),
233           'status' => TRUE,
234           'cache' => TRUE,
235         ],
236         'teaser' => [
237           'label' => t('Teaser'),
238           'status' => TRUE,
239           'cache' => TRUE,
240         ],
241       ];
242     }
243   }
244 }
245
246 /**
247  * Implements hook_entity_form_mode_info_alter().
248  */
249 function entity_test_entity_form_mode_info_alter(&$form_modes) {
250   $entity_info = \Drupal::entityManager()->getDefinitions();
251   foreach ($entity_info as $entity_type => $info) {
252     if ($entity_info[$entity_type]->getProvider() == 'entity_test') {
253       $form_modes[$entity_type] = [
254         'compact' => [
255           'label' => t('Compact version'),
256           'status' => TRUE,
257         ],
258       ];
259     }
260   }
261 }
262
263 /**
264  * Implements hook_entity_extra_field_info().
265  */
266 function entity_test_entity_extra_field_info() {
267   $extra['entity_test']['bundle_with_extra_fields'] = [
268     'display' => [
269       // Note: those extra fields do not currently display anything, they are
270       // just used in \Drupal\Tests\field_ui\Kernel\EntityDisplayTest to test
271       // the behavior of entity display objects.
272       'display_extra_field' => [
273         'label' => t('Display extra field'),
274         'description' => t('An extra field on the display side.'),
275         'weight' => 5,
276         'visible' => TRUE,
277       ],
278       'display_extra_field_hidden' => [
279         'label' => t('Display extra field (hidden)'),
280         'description' => t('An extra field on the display side, hidden by default.'),
281         'visible' => FALSE,
282       ],
283     ]
284   ];
285
286   return $extra;
287 }
288
289 /**
290  * Implements hook_form_BASE_FORM_ID_alter().
291  */
292 function entity_test_form_entity_test_form_alter(&$form) {
293   switch (\Drupal::state()->get('entity_test.form.validate.test')) {
294     case 'form-level':
295       $form['#validate'][] = 'entity_test_form_entity_test_form_validate';
296       $form['#validate'][] = 'entity_test_form_entity_test_form_validate_check';
297       break;
298
299     case 'button-level':
300       $form['actions']['submit']['#validate'][] = 'entity_test_form_entity_test_form_validate';
301   }
302 }
303
304 /**
305  * Validation handler for the entity_test entity form.
306  */
307 function entity_test_form_entity_test_form_validate(array &$form, FormStateInterface $form_state) {
308   $form['#entity_test_form_validate'] = TRUE;
309 }
310
311 /**
312  * Validation handler for the entity_test entity form.
313  */
314 function entity_test_form_entity_test_form_validate_check(array &$form, FormStateInterface $form_state) {
315   if (!empty($form['#entity_test_form_validate'])) {
316     \Drupal::state()->set('entity_test.form.validate.result', TRUE);
317   }
318 }
319
320 /**
321  * Implements hook_form_BASE_FORM_ID_alter().
322  */
323 function entity_test_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
324   $langcode = $form_state->getFormObject()->getFormLangcode($form_state);
325   \Drupal::state()->set('entity_test.form_langcode', $langcode);
326 }
327
328 /**
329  * Loads a test entity.
330  *
331  * @param int $id
332  *   A test entity ID.
333  * @param bool $reset
334  *   A boolean indicating that the internal cache should be reset.
335  *
336  * @return \Drupal\entity_test\Entity\EntityTest
337  *   The loaded entity object, or NULL if the entity cannot be loaded.
338  */
339 function entity_test_load($id, $reset = FALSE) {
340   $storage = \Drupal::entityTypeManager()->getStorage('entity_test');
341   if ($reset) {
342     $storage->resetCache([$id]);
343   }
344   return $storage->load($id);
345 }
346
347 /**
348  * Loads a test entity.
349  *
350  * @param int $id
351  *   A test entity ID.
352  * @param bool $reset
353  *   A boolean indicating that the internal cache should be reset.
354  *
355  * @return \Drupal\entity_test\Entity\EntityTestRev
356  *   The loaded entity object, or NULL if the entity cannot be loaded.
357  */
358 function entity_test_rev_load($id, $reset = FALSE) {
359   $storage = \Drupal::entityTypeManager()->getStorage('entity_test_rev');
360   if ($reset) {
361     $storage->resetCache([$id]);
362   }
363   return $storage->load($id);
364 }
365
366 /**
367  * Loads a test entity.
368  *
369  * @param int $id
370  *   A test entity ID.
371  * @param bool $reset
372  *   A boolean indicating that the internal cache should be reset.
373  *
374  * @return \Drupal\entity_test\Entity\EntityTestMul
375  *   The loaded entity object, or FALSE if the entity cannot be loaded.
376  */
377 function entity_test_mul_load($id, $reset = FALSE) {
378   $storage = \Drupal::entityTypeManager()->getStorage('entity_test_mul');
379   if ($reset) {
380     $storage->resetCache([$id]);
381   }
382   return $storage->load($id);
383 }
384
385 /**
386  * Loads a test entity.
387  *
388  * @param int $id
389  *   A test entity ID.
390  * @param bool $reset
391  *   A boolean indicating that the internal cache should be reset.
392  *
393  * @return \Drupal\entity_test\Entity\EntityTestMulRev
394  *   The loaded entity object, or NULL if the entity cannot be loaded.
395  */
396 function entity_test_mulrev_load($id, $reset = FALSE) {
397   $storage = \Drupal::entityTypeManager()->getStorage('entity_test_mulrev');
398   if ($reset) {
399     $storage->resetCache([$id]);
400   }
401   return $storage->load($id);
402 }
403
404 /**
405  * Implements hook_ENTITY_TYPE_insert() for 'entity_test'.
406  */
407 function entity_test_entity_test_insert($entity) {
408   if ($entity->name->value == 'fail_insert') {
409     throw new Exception("Test exception rollback.");
410   }
411 }
412
413 /**
414  * Implements hook_entity_insert().
415  */
416 function entity_test_entity_insert(EntityInterface $entity) {
417   if ($entity->getEntityTypeId() == 'entity_test_mulrev' && $entity->label() == 'EntityLoadedRevisionTest') {
418     $entity->setNewRevision(FALSE);
419     $entity->save();
420   }
421 }
422
423 /**
424  * Implements hook_entity_update().
425  */
426 function entity_test_entity_update(EntityInterface $entity) {
427   if ($entity instanceof ContentEntityInterface) {
428     \Drupal::state()->set('entity_test.loadedRevisionId', $entity->getLoadedRevisionId());
429   }
430 }
431
432 /**
433  * Implements hook_entity_field_access().
434  *
435  * @see \Drupal\system\Tests\Entity\FieldAccessTest::testFieldAccess()
436  */
437 function entity_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) {
438   if ($field_definition->getName() == 'field_test_text') {
439     if ($items) {
440       if ($items->value == 'no access value') {
441         return AccessResult::forbidden()->addCacheableDependency($items->getEntity());
442       }
443       elseif ($items->value == 'custom cache tag value') {
444         return AccessResult::allowed()->addCacheableDependency($items->getEntity())->addCacheTags(['entity_test_access:field_test_text']);
445       }
446       elseif ($operation == 'edit' && $items->value == 'no edit access value') {
447         return AccessResult::forbidden()->addCacheableDependency($items->getEntity());
448       }
449     }
450   }
451   if ($field = \Drupal::state()->get('views_field_access_test-field')) {
452     if ($field_definition->getName() === $field) {
453       $result = AccessResult::allowedIfHasPermission($account, 'view test entity field');
454       // For test purposes we want to actively deny access.
455       if ($result->isNeutral()) {
456         $result = AccessResult::forbidden();
457       }
458       return $result;
459     }
460   }
461
462   // No opinion.
463   return AccessResult::neutral();
464 }
465
466 /**
467  * Implements hook_entity_field_access_alter().
468  *
469  * @see \Drupal\system\Tests\Entity\FieldAccessTest::testFieldAccess()
470  */
471 function entity_test_entity_field_access_alter(array &$grants, array $context) {
472   if ($context['field_definition']->getName() == 'field_test_text' && $context['items']->value == 'access alter value') {
473     $grants[':default'] = AccessResult::forbidden()->inheritCacheability($grants[':default'])->addCacheableDependency($context['items']->getEntity());
474   }
475 }
476
477 /**
478  * Implements hook_entity_form_display_alter().
479  */
480 function entity_test_entity_form_display_alter(EntityFormDisplay $form_display, $context) {
481   // Make the field_test_text field 42 characters for entity_test_mul.
482   if ($context['entity_type'] == 'entity_test') {
483     if ($component_options = $form_display->getComponent('field_test_text')) {
484       $component_options['settings']['size'] = 42;
485       $form_display->setComponent('field_test_text', $component_options);
486     }
487   }
488 }
489
490 /**
491  * Implements hook_entity_presave().
492  */
493 function entity_test_entity_presave(EntityInterface $entity) {
494   if (isset($GLOBALS['entity_test_throw_exception'])) {
495     throw new Exception('Entity presave exception', 1);
496   }
497
498   if ($entity->getEntityType()->id() == 'entity_view_display') {
499     $entity->setThirdPartySetting('entity_test', 'foo', 'bar');
500   }
501 }
502
503 /**
504  * Implements hook_entity_predelete().
505  */
506 function entity_test_entity_predelete(EntityInterface $entity) {
507   if (isset($GLOBALS['entity_test_throw_exception'])) {
508     throw new Exception('Entity predelete exception', 2);
509   }
510 }
511
512 /**
513  * Implements hook_entity_operation_alter().
514  */
515 function entity_test_entity_operation_alter(array &$operations, EntityInterface $entity) {
516   $valid_entity_type_ids = [
517     'user_role',
518     'block',
519   ];
520   if (in_array($entity->getEntityTypeId(), $valid_entity_type_ids)) {
521     if (\Drupal::service('router.route_provider')->getRouteByName("entity.{$entity->getEntityTypeId()}.test_operation")) {
522       $operations['test_operation'] = [
523         'title' => format_string('Test Operation: @label', ['@label' => $entity->label()]),
524         'url' => Url::fromRoute("entity.{$entity->getEntityTypeId()}.test_operation", [$entity->getEntityTypeId() => $entity->id()]),
525         'weight' => 50,
526       ];
527     }
528   }
529 }
530
531 /**
532  * Implements hook_entity_translation_create().
533  */
534 function entity_test_entity_translation_create(EntityInterface $translation) {
535   _entity_test_record_hooks('entity_translation_create', $translation->language()->getId());
536 }
537
538 /**
539  * Implements hook_entity_translation_insert().
540  */
541 function entity_test_entity_translation_insert(EntityInterface $translation) {
542   _entity_test_record_hooks('entity_translation_insert', $translation->language()->getId());
543 }
544
545 /**
546  * Implements hook_entity_translation_delete().
547  */
548 function entity_test_entity_translation_delete(EntityInterface $translation) {
549   _entity_test_record_hooks('entity_translation_delete', $translation->language()->getId());
550 }
551
552 /**
553  * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul'.
554  */
555 function entity_test_entity_test_mul_translation_create(EntityInterface $translation) {
556   _entity_test_record_hooks('entity_test_mul_translation_create', $translation->language()->getId());
557 }
558
559 /**
560  * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul'.
561  */
562 function entity_test_entity_test_mul_translation_insert(EntityInterface $translation) {
563   _entity_test_record_hooks('entity_test_mul_translation_insert', $translation->language()->getId());
564 }
565
566 /**
567  * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mul'.
568  */
569 function entity_test_entity_test_mul_translation_delete(EntityInterface $translation) {
570   _entity_test_record_hooks('entity_test_mul_translation_delete', $translation->language()->getId());
571 }
572
573 /**
574  * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul_changed'.
575  */
576 function entity_test_entity_test_mul_changed_translation_create(EntityInterface $translation) {
577   _entity_test_record_hooks('entity_test_mul_changed_translation_create', $translation->language()->getId());
578 }
579
580 /**
581  * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul_changed'.
582  */
583 function entity_test_entity_test_mul_changed_translation_insert(EntityInterface $translation) {
584   _entity_test_record_hooks('entity_test_mul_changed_translation_insert', $translation->language()->getId());
585 }
586
587 /**
588  * Implements hook_ENTITY_TYPE_translation_delete().
589  */
590 function entity_test_entity_test_mul_changed_translation_delete(EntityInterface $translation) {
591   _entity_test_record_hooks('entity_test_mul_changed_translation_delete', $translation->language()->getId());
592 }
593
594 /**
595  * Implements hook_ENTITY_TYPE_translation_create().
596  */
597 function entity_test_entity_test_mulrev_translation_create(EntityInterface $translation) {
598   _entity_test_record_hooks('entity_test_mulrev_translation_create', $translation->language()->getId());
599 }
600
601 /**
602  * Implements hook_ENTITY_TYPE_translation_insert().
603  */
604 function entity_test_entity_test_mulrev_translation_insert(EntityInterface $translation) {
605   _entity_test_record_hooks('entity_test_mulrev_translation_insert', $translation->language()->getId());
606 }
607
608 /**
609  * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mulrev'.
610  */
611 function entity_test_entity_test_mulrev_translation_delete(EntityInterface $translation) {
612   _entity_test_record_hooks('entity_test_mulrev_translation_delete', $translation->language()->getId());
613 }
614
615 /**
616  * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mulrev_changed'.
617  */
618 function entity_test_entity_test_mulrev_changed_translation_create(EntityInterface $translation) {
619   _entity_test_record_hooks('entity_test_mulrev_changed_translation_create', $translation->language()->getId());
620 }
621
622 /**
623  * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mulrev'.
624  */
625 function entity_test_entity_test_mulrev_changed_translation_insert(EntityInterface $translation) {
626   _entity_test_record_hooks('entity_test_mulrev_changed_translation_insert', $translation->language()->getId());
627 }
628
629 /**
630  * Implements hook_ENTITY_TYPE_translation_delete().
631  */
632 function entity_test_entity_test_mulrev_changed_translation_delete(EntityInterface $translation) {
633   _entity_test_record_hooks('entity_test_mulrev_changed_translation_delete', $translation->language()->getId());
634 }
635
636 /**
637  * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul_langcode_key'.
638  */
639 function entity_test_entity_test_mul_langcode_key_translation_create(EntityInterface $translation) {
640   _entity_test_record_hooks('entity_test_mul_langcode_key_translation_create', $translation->language()->getId());
641 }
642
643 /**
644  * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul_langcode_key'.
645  */
646 function entity_test_entity_test_mul_langcode_key_translation_insert(EntityInterface $translation) {
647   _entity_test_record_hooks('entity_test_mul_langcode_key_translation_insert', $translation->language()->getId());
648 }
649
650 /**
651  * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mul_langcode_key'.
652  */
653 function entity_test_entity_test_mul_langcode_key_translation_delete(EntityInterface $translation) {
654   _entity_test_record_hooks('entity_test_mul_langcode_key_translation_delete', $translation->language()->getId());
655 }
656
657 /**
658  * Field default value callback.
659  *
660  * @param \Drupal\Core\Entity\FieldableEntityInterface $entity
661  *   The entity being created.
662  * @param \Drupal\Core\Field\FieldDefinitionInterface $definition
663  *   The field definition.
664  *
665  * @return array
666  *   An array of default values, in the same format as the $default_value
667  *   property.
668  *
669  * @see \Drupal\field\Entity\FieldConfig::$default_value
670  */
671 function entity_test_field_default_value(FieldableEntityInterface $entity, FieldDefinitionInterface $definition) {
672   // Include the field name and entity language in the generated values to check
673   // that they are correctly passed.
674   $string = $definition->getName() . '_' . $entity->language()->getId();
675   // Return a "default value" with multiple items.
676   return [
677     [
678       'shape' => "shape:0:$string",
679       'color' => "color:0:$string",
680     ],
681     [
682       'shape' => "shape:1:$string",
683       'color' => "color:1:$string",
684     ],
685   ];
686 }
687
688 /**
689  * Helper function to be used to record hook invocations.
690  *
691  * @param string $hook
692  *   The hook name.
693  * @param mixed $data
694  *   Arbitrary data associated with the hook invocation.
695  */
696 function _entity_test_record_hooks($hook, $data) {
697   $state = \Drupal::state();
698   $key = 'entity_test.hooks';
699   $hooks = $state->get($key);
700   $hooks[$hook] = $data;
701   $state->set($key, $hooks);
702 }
703
704 /**
705  * Implements hook_entity_prepare_view().
706  */
707 function entity_test_entity_prepare_view($entity_type, array $entities, array $displays) {
708   if ($entity_type == 'entity_test') {
709     foreach ($entities as $entity) {
710       /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
711
712       // Add a dummy field item attribute on field_test_text if it exists.
713       if ($entity->hasField('field_test_text') && $displays[$entity->bundle()]->getComponent('field_test_text')) {
714         foreach ($entity->get('field_test_text') as $item) {
715           $item->_attributes += ['data-field-item-attr' => 'foobar'];
716         }
717       }
718
719       // Add a dummy field item attribute on daterange fields if they exist.
720       $fields = $entity->getFieldDefinitions();
721       foreach ($fields as $field) {
722         if ($field->getType() === 'daterange') {
723           $item = $entity->get($field->getName());
724           $item->_attributes += ['data-field-item-attr' => 'foobar'];
725         }
726       }
727     }
728   }
729 }
730
731 /**
732  * Implements hook_entity_display_build_alter().
733  */
734 function entity_test_entity_display_build_alter(&$build, $context) {
735   /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
736   $entity = $context['entity'];
737   if ($entity->getEntityTypeId() == 'entity_test' && $entity->bundle() == 'display_build_alter_bundle') {
738     $build['entity_display_build_alter']['#markup'] = 'Content added in hook_entity_display_build_alter for entity id ' . $entity->id();
739   }
740 }
741
742 /**
743  * Implements hook_entity_access().
744  */
745 function entity_test_entity_access(EntityInterface $entity, $operation, AccountInterface $account) {
746   // Only apply to the 'entity_test' entities.
747   if ($entity->getEntityType()->getProvider() != 'entity_test') {
748     return AccessResult::neutral();
749   }
750   \Drupal::state()->set('entity_test_entity_access', TRUE);
751
752   // Attempt to allow access to entities with the title forbid_access,
753   // this will be overridden by
754   // \Drupal\entity_test\EntityTestAccessControlHandler::checkAccess().
755   if ($entity->label() == 'forbid_access') {
756     return AccessResult::allowed();
757   }
758
759   // Uncacheable because the access result depends on a State key-value pair and
760   // might therefore change at any time.
761   $condition = \Drupal::state()->get("entity_test_entity_access.{$operation}." . $entity->id(), FALSE);
762   return AccessResult::allowedIf($condition)->setCacheMaxAge(0);
763 }
764
765 /**
766  * Implements hook_ENTITY_TYPE_access() for 'entity_test'.
767  */
768 function entity_test_entity_test_access(EntityInterface $entity, $operation, AccountInterface $account) {
769   \Drupal::state()->set('entity_test_entity_test_access', TRUE);
770
771   // No opinion.
772   return AccessResult::neutral();
773 }
774
775 /**
776  * Implements hook_entity_create_access().
777  */
778 function entity_test_entity_create_access(AccountInterface $account, $context, $entity_bundle) {
779   \Drupal::state()->set('entity_test_entity_create_access', TRUE);
780   \Drupal::state()->set('entity_test_entity_create_access_context', $context);
781
782   // No opinion.
783   return AccessResult::neutral();
784 }
785
786 /**
787  * Implements hook_ENTITY_TYPE_create_access() for 'entity_test'.
788  */
789 function entity_test_entity_test_create_access(AccountInterface $account, $context, $entity_bundle) {
790   \Drupal::state()->set('entity_test_entity_test_create_access', TRUE);
791
792   // No opinion.
793   return AccessResult::neutral();
794 }