get('entity_test.translation')) { $translation = $entity_types[$entity_type]->get('translation'); $translation[$entity_type] = TRUE; $entity_types[$entity_type]->set('translation', $translation); } } // Allow entity_test_with_bundle tests to override the entity type definition. $entity_types['entity_test_with_bundle'] = $state->get('entity_test_with_bundle.entity_type', $entity_types['entity_test_with_bundle']); // Enable the entity_test_new only when needed. if (!$state->get('entity_test_new')) { unset($entity_types['entity_test_new']); } } /** * Implements hook_module_implements_alter(). */ function entity_test_module_implements_alter(&$implementations, $hook) { // Move our hook_entity_type_alter() implementation to the beginning of the // list in order to run before content_moderation_entity_type_alter(). if ($hook === 'entity_type_alter') { $implementations = ['entity_test' => $implementations['entity_test']] + $implementations; } } /** * Implements hook_entity_base_field_info(). */ function entity_test_entity_base_field_info(EntityTypeInterface $entity_type) { $fields = []; if ($entity_type->id() == 'entity_test_mulrev' && \Drupal::state()->get('entity_test.field_test_item')) { $fields['field_test_item'] = BaseFieldDefinition::create('field_test') ->setLabel(t('Field test')) ->setDescription(t('A field test.')) ->setRevisionable(TRUE) ->setTranslatable(TRUE); } if ($entity_type->id() == 'entity_test_mulrev' && \Drupal::state()->get('entity_test.multi_column')) { $fields['description'] = BaseFieldDefinition::create('shape') ->setLabel(t('Some custom description')) ->setTranslatable(TRUE); } return $fields; } /** * Implements hook_entity_base_field_info_alter(). */ function entity_test_entity_base_field_info_alter(&$fields, EntityTypeInterface $entity_type) { $state = \Drupal::state(); if ($entity_type->id() == 'entity_test_mulrev' && ($names = $state->get('entity_test.field_definitions.translatable'))) { foreach ($names as $name => $value) { $fields[$name]->setTranslatable($value); } } if ($entity_type->id() == 'node' && $state->get('entity_test.node_remove_status_field')) { unset($fields['status']); } if ($entity_type->id() == 'entity_test' && $state->get('entity_test.remove_name_field')) { unset($fields['name']); } // In 8001 we are assuming that a new definition with multiple cardinality has // been deployed. // @todo Remove this if we end up using state definitions at runtime. See // https://www.drupal.org/node/2554235. if ($entity_type->id() == 'entity_test' && $state->get('entity_test.db_updates.entity_definition_updates') == 8001) { $fields['user_id']->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED); } } /** * Implements hook_entity_field_storage_info(). */ function entity_test_entity_field_storage_info(EntityTypeInterface $entity_type) { if ($entity_type->id() == 'entity_test_update') { return \Drupal::state()->get('entity_test_update.additional_field_storage_definitions', []); } } /** * Creates a new bundle for entity_test entities. * * @param string $bundle * The machine-readable name of the bundle. * @param string $text * (optional) The human-readable name of the bundle. If none is provided, the * machine name will be used. * @param string $entity_type * (optional) The entity type for which the bundle is created. Defaults to * 'entity_test'. */ function entity_test_create_bundle($bundle, $text = NULL, $entity_type = 'entity_test') { $bundles = \Drupal::state()->get($entity_type . '.bundles') ?: [$entity_type => ['label' => 'Entity Test Bundle']]; $bundles += [$bundle => ['label' => $text ? $text : $bundle]]; \Drupal::state()->set($entity_type . '.bundles', $bundles); \Drupal::entityManager()->onBundleCreate($bundle, $entity_type); } /** * Deletes a bundle for entity_test entities. * * @param string $bundle * The machine-readable name of the bundle to delete. * @param string $entity_type * (optional) The entity type for which the bundle is deleted. Defaults to * 'entity_test'. */ function entity_test_delete_bundle($bundle, $entity_type = 'entity_test') { $bundles = \Drupal::state()->get($entity_type . '.bundles') ?: [$entity_type => ['label' => 'Entity Test Bundle']]; unset($bundles[$bundle]); \Drupal::state()->set($entity_type . '.bundles', $bundles); \Drupal::entityManager()->onBundleDelete($bundle, $entity_type); } /** * Implements hook_entity_bundle_info(). */ function entity_test_entity_bundle_info() { $bundles = []; $entity_types = \Drupal::entityManager()->getDefinitions(); foreach ($entity_types as $entity_type_id => $entity_type) { if ($entity_type->getProvider() == 'entity_test' && $entity_type_id != 'entity_test_with_bundle') { $bundles[$entity_type_id] = \Drupal::state()->get($entity_type_id . '.bundles') ?: [$entity_type_id => ['label' => 'Entity Test Bundle']]; } } return $bundles; } /** * Implements hook_entity_view_mode_info_alter(). */ function entity_test_entity_view_mode_info_alter(&$view_modes) { $entity_info = \Drupal::entityManager()->getDefinitions(); foreach ($entity_info as $entity_type => $info) { if ($entity_info[$entity_type]->getProvider() == 'entity_test' && !isset($view_modes[$entity_type])) { $view_modes[$entity_type] = [ 'full' => [ 'label' => t('Full object'), 'status' => TRUE, 'cache' => TRUE, ], 'teaser' => [ 'label' => t('Teaser'), 'status' => TRUE, 'cache' => TRUE, ], ]; } } } /** * Implements hook_entity_form_mode_info_alter(). */ function entity_test_entity_form_mode_info_alter(&$form_modes) { $entity_info = \Drupal::entityManager()->getDefinitions(); foreach ($entity_info as $entity_type => $info) { if ($entity_info[$entity_type]->getProvider() == 'entity_test') { $form_modes[$entity_type] = [ 'compact' => [ 'label' => t('Compact version'), 'status' => TRUE, ], ]; } } } /** * Implements hook_entity_extra_field_info(). */ function entity_test_entity_extra_field_info() { $extra['entity_test']['bundle_with_extra_fields'] = [ 'display' => [ // Note: those extra fields do not currently display anything, they are // just used in \Drupal\Tests\field_ui\Kernel\EntityDisplayTest to test // the behavior of entity display objects. 'display_extra_field' => [ 'label' => t('Display extra field'), 'description' => t('An extra field on the display side.'), 'weight' => 5, 'visible' => TRUE, ], 'display_extra_field_hidden' => [ 'label' => t('Display extra field (hidden)'), 'description' => t('An extra field on the display side, hidden by default.'), 'visible' => FALSE, ], ] ]; return $extra; } /** * Implements hook_form_BASE_FORM_ID_alter(). */ function entity_test_form_entity_test_form_alter(&$form) { switch (\Drupal::state()->get('entity_test.form.validate.test')) { case 'form-level': $form['#validate'][] = 'entity_test_form_entity_test_form_validate'; $form['#validate'][] = 'entity_test_form_entity_test_form_validate_check'; break; case 'button-level': $form['actions']['submit']['#validate'][] = 'entity_test_form_entity_test_form_validate'; } } /** * Validation handler for the entity_test entity form. */ function entity_test_form_entity_test_form_validate(array &$form, FormStateInterface $form_state) { $form['#entity_test_form_validate'] = TRUE; } /** * Validation handler for the entity_test entity form. */ function entity_test_form_entity_test_form_validate_check(array &$form, FormStateInterface $form_state) { if (!empty($form['#entity_test_form_validate'])) { \Drupal::state()->set('entity_test.form.validate.result', TRUE); } } /** * Implements hook_form_BASE_FORM_ID_alter(). */ function entity_test_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) { $langcode = $form_state->getFormObject()->getFormLangcode($form_state); \Drupal::state()->set('entity_test.form_langcode', $langcode); } /** * Loads a test entity. * * @param int $id * A test entity ID. * @param bool $reset * A boolean indicating that the internal cache should be reset. * * @return \Drupal\entity_test\Entity\EntityTest * The loaded entity object, or NULL if the entity cannot be loaded. */ function entity_test_load($id, $reset = FALSE) { $storage = \Drupal::entityTypeManager()->getStorage('entity_test'); if ($reset) { $storage->resetCache([$id]); } return $storage->load($id); } /** * Loads a test entity. * * @param int $id * A test entity ID. * @param bool $reset * A boolean indicating that the internal cache should be reset. * * @return \Drupal\entity_test\Entity\EntityTestRev * The loaded entity object, or NULL if the entity cannot be loaded. */ function entity_test_rev_load($id, $reset = FALSE) { $storage = \Drupal::entityTypeManager()->getStorage('entity_test_rev'); if ($reset) { $storage->resetCache([$id]); } return $storage->load($id); } /** * Loads a test entity. * * @param int $id * A test entity ID. * @param bool $reset * A boolean indicating that the internal cache should be reset. * * @return \Drupal\entity_test\Entity\EntityTestMul * The loaded entity object, or FALSE if the entity cannot be loaded. */ function entity_test_mul_load($id, $reset = FALSE) { $storage = \Drupal::entityTypeManager()->getStorage('entity_test_mul'); if ($reset) { $storage->resetCache([$id]); } return $storage->load($id); } /** * Loads a test entity. * * @param int $id * A test entity ID. * @param bool $reset * A boolean indicating that the internal cache should be reset. * * @return \Drupal\entity_test\Entity\EntityTestMulRev * The loaded entity object, or NULL if the entity cannot be loaded. */ function entity_test_mulrev_load($id, $reset = FALSE) { $storage = \Drupal::entityTypeManager()->getStorage('entity_test_mulrev'); if ($reset) { $storage->resetCache([$id]); } return $storage->load($id); } /** * Implements hook_ENTITY_TYPE_insert() for 'entity_test'. */ function entity_test_entity_test_insert($entity) { if ($entity->name->value == 'fail_insert') { throw new Exception("Test exception rollback."); } } /** * Implements hook_entity_insert(). */ function entity_test_entity_insert(EntityInterface $entity) { if ($entity->getEntityTypeId() == 'entity_test_mulrev' && $entity->label() == 'EntityLoadedRevisionTest') { $entity->setNewRevision(FALSE); $entity->save(); } } /** * Implements hook_entity_update(). */ function entity_test_entity_update(EntityInterface $entity) { if ($entity instanceof ContentEntityInterface) { \Drupal::state()->set('entity_test.loadedRevisionId', $entity->getLoadedRevisionId()); } } /** * Implements hook_entity_field_access(). * * @see \Drupal\system\Tests\Entity\FieldAccessTest::testFieldAccess() */ function entity_test_entity_field_access($operation, FieldDefinitionInterface $field_definition, AccountInterface $account, FieldItemListInterface $items = NULL) { if ($field_definition->getName() == 'field_test_text') { if ($items) { if ($items->value == 'no access value') { return AccessResult::forbidden()->addCacheableDependency($items->getEntity()); } elseif ($items->value == 'custom cache tag value') { return AccessResult::allowed()->addCacheableDependency($items->getEntity())->addCacheTags(['entity_test_access:field_test_text']); } elseif ($operation == 'edit' && $items->value == 'no edit access value') { return AccessResult::forbidden()->addCacheableDependency($items->getEntity()); } } } if ($field = \Drupal::state()->get('views_field_access_test-field')) { if ($field_definition->getName() === $field) { $result = AccessResult::allowedIfHasPermission($account, 'view test entity field'); // For test purposes we want to actively deny access. if ($result->isNeutral()) { $result = AccessResult::forbidden(); } return $result; } } // No opinion. return AccessResult::neutral(); } /** * Implements hook_entity_field_access_alter(). * * @see \Drupal\system\Tests\Entity\FieldAccessTest::testFieldAccess() */ function entity_test_entity_field_access_alter(array &$grants, array $context) { if ($context['field_definition']->getName() == 'field_test_text' && $context['items']->value == 'access alter value') { $grants[':default'] = AccessResult::forbidden()->inheritCacheability($grants[':default'])->addCacheableDependency($context['items']->getEntity()); } } /** * Implements hook_entity_form_display_alter(). */ function entity_test_entity_form_display_alter(EntityFormDisplay $form_display, $context) { // Make the field_test_text field 42 characters for entity_test_mul. if ($context['entity_type'] == 'entity_test') { if ($component_options = $form_display->getComponent('field_test_text')) { $component_options['settings']['size'] = 42; $form_display->setComponent('field_test_text', $component_options); } } } /** * Implements hook_entity_presave(). */ function entity_test_entity_presave(EntityInterface $entity) { if (isset($GLOBALS['entity_test_throw_exception'])) { throw new Exception('Entity presave exception', 1); } if ($entity->getEntityType()->id() == 'entity_view_display') { $entity->setThirdPartySetting('entity_test', 'foo', 'bar'); } } /** * Implements hook_entity_predelete(). */ function entity_test_entity_predelete(EntityInterface $entity) { if (isset($GLOBALS['entity_test_throw_exception'])) { throw new Exception('Entity predelete exception', 2); } } /** * Implements hook_entity_operation_alter(). */ function entity_test_entity_operation_alter(array &$operations, EntityInterface $entity) { $valid_entity_type_ids = [ 'user_role', 'block', ]; if (in_array($entity->getEntityTypeId(), $valid_entity_type_ids)) { if (\Drupal::service('router.route_provider')->getRouteByName("entity.{$entity->getEntityTypeId()}.test_operation")) { $operations['test_operation'] = [ 'title' => format_string('Test Operation: @label', ['@label' => $entity->label()]), 'url' => Url::fromRoute("entity.{$entity->getEntityTypeId()}.test_operation", [$entity->getEntityTypeId() => $entity->id()]), 'weight' => 50, ]; } } } /** * Implements hook_entity_translation_create(). */ function entity_test_entity_translation_create(EntityInterface $translation) { _entity_test_record_hooks('entity_translation_create', $translation->language()->getId()); } /** * Implements hook_entity_translation_insert(). */ function entity_test_entity_translation_insert(EntityInterface $translation) { _entity_test_record_hooks('entity_translation_insert', $translation->language()->getId()); } /** * Implements hook_entity_translation_delete(). */ function entity_test_entity_translation_delete(EntityInterface $translation) { _entity_test_record_hooks('entity_translation_delete', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul'. */ function entity_test_entity_test_mul_translation_create(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_translation_create', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul'. */ function entity_test_entity_test_mul_translation_insert(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_translation_insert', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mul'. */ function entity_test_entity_test_mul_translation_delete(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_translation_delete', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul_changed'. */ function entity_test_entity_test_mul_changed_translation_create(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_changed_translation_create', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul_changed'. */ function entity_test_entity_test_mul_changed_translation_insert(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_changed_translation_insert', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_delete(). */ function entity_test_entity_test_mul_changed_translation_delete(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_changed_translation_delete', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_create(). */ function entity_test_entity_test_mulrev_translation_create(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mulrev_translation_create', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_insert(). */ function entity_test_entity_test_mulrev_translation_insert(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mulrev_translation_insert', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mulrev'. */ function entity_test_entity_test_mulrev_translation_delete(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mulrev_translation_delete', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mulrev_changed'. */ function entity_test_entity_test_mulrev_changed_translation_create(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mulrev_changed_translation_create', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mulrev'. */ function entity_test_entity_test_mulrev_changed_translation_insert(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mulrev_changed_translation_insert', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_delete(). */ function entity_test_entity_test_mulrev_changed_translation_delete(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mulrev_changed_translation_delete', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul_langcode_key'. */ function entity_test_entity_test_mul_langcode_key_translation_create(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_langcode_key_translation_create', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul_langcode_key'. */ function entity_test_entity_test_mul_langcode_key_translation_insert(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_langcode_key_translation_insert', $translation->language()->getId()); } /** * Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mul_langcode_key'. */ function entity_test_entity_test_mul_langcode_key_translation_delete(EntityInterface $translation) { _entity_test_record_hooks('entity_test_mul_langcode_key_translation_delete', $translation->language()->getId()); } /** * Field default value callback. * * @param \Drupal\Core\Entity\FieldableEntityInterface $entity * The entity being created. * @param \Drupal\Core\Field\FieldDefinitionInterface $definition * The field definition. * * @return array * An array of default values, in the same format as the $default_value * property. * * @see \Drupal\field\Entity\FieldConfig::$default_value */ function entity_test_field_default_value(FieldableEntityInterface $entity, FieldDefinitionInterface $definition) { // Include the field name and entity language in the generated values to check // that they are correctly passed. $string = $definition->getName() . '_' . $entity->language()->getId(); // Return a "default value" with multiple items. return [ [ 'shape' => "shape:0:$string", 'color' => "color:0:$string", ], [ 'shape' => "shape:1:$string", 'color' => "color:1:$string", ], ]; } /** * Helper function to be used to record hook invocations. * * @param string $hook * The hook name. * @param mixed $data * Arbitrary data associated with the hook invocation. */ function _entity_test_record_hooks($hook, $data) { $state = \Drupal::state(); $key = 'entity_test.hooks'; $hooks = $state->get($key); $hooks[$hook] = $data; $state->set($key, $hooks); } /** * Implements hook_entity_prepare_view(). */ function entity_test_entity_prepare_view($entity_type, array $entities, array $displays) { if ($entity_type == 'entity_test') { foreach ($entities as $entity) { /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ // Add a dummy field item attribute on field_test_text if it exists. if ($entity->hasField('field_test_text') && $displays[$entity->bundle()]->getComponent('field_test_text')) { foreach ($entity->get('field_test_text') as $item) { $item->_attributes += ['data-field-item-attr' => 'foobar']; } } // Add a dummy field item attribute on daterange fields if they exist. $fields = $entity->getFieldDefinitions(); foreach ($fields as $field) { if ($field->getType() === 'daterange') { $item = $entity->get($field->getName()); $item->_attributes += ['data-field-item-attr' => 'foobar']; } } } } } /** * Implements hook_entity_display_build_alter(). */ function entity_test_entity_display_build_alter(&$build, $context) { /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */ $entity = $context['entity']; if ($entity->getEntityTypeId() == 'entity_test' && $entity->bundle() == 'display_build_alter_bundle') { $build['entity_display_build_alter']['#markup'] = 'Content added in hook_entity_display_build_alter for entity id ' . $entity->id(); } } /** * Implements hook_entity_access(). */ function entity_test_entity_access(EntityInterface $entity, $operation, AccountInterface $account) { // Only apply to the 'entity_test' entities. if ($entity->getEntityType()->getProvider() != 'entity_test') { return AccessResult::neutral(); } \Drupal::state()->set('entity_test_entity_access', TRUE); // Attempt to allow access to entities with the title forbid_access, // this will be overridden by // \Drupal\entity_test\EntityTestAccessControlHandler::checkAccess(). if ($entity->label() == 'forbid_access') { return AccessResult::allowed(); } // Uncacheable because the access result depends on a State key-value pair and // might therefore change at any time. $condition = \Drupal::state()->get("entity_test_entity_access.{$operation}." . $entity->id(), FALSE); return AccessResult::allowedIf($condition)->setCacheMaxAge(0); } /** * Implements hook_ENTITY_TYPE_access() for 'entity_test'. */ function entity_test_entity_test_access(EntityInterface $entity, $operation, AccountInterface $account) { \Drupal::state()->set('entity_test_entity_test_access', TRUE); // No opinion. return AccessResult::neutral(); } /** * Implements hook_entity_create_access(). */ function entity_test_entity_create_access(AccountInterface $account, $context, $entity_bundle) { \Drupal::state()->set('entity_test_entity_create_access', TRUE); \Drupal::state()->set('entity_test_entity_create_access_context', $context); // No opinion. return AccessResult::neutral(); } /** * Implements hook_ENTITY_TYPE_create_access() for 'entity_test'. */ function entity_test_entity_test_create_access(AccountInterface $account, $context, $entity_bundle) { \Drupal::state()->set('entity_test_entity_test_create_access', TRUE); // No opinion. return AccessResult::neutral(); }