entity_test.module

Same filename in other branches
  1. 9 core/modules/system/tests/modules/entity_test/entity_test.module
  2. 8.9.x core/modules/system/tests/modules/entity_test/entity_test.module
  3. 10 core/modules/system/tests/modules/entity_test/entity_test.module

File

core/modules/system/tests/modules/entity_test/entity_test.module

View source
<?php


/**
 * @file
 * Test module for the entity API providing several entity types for testing.
 */
declare (strict_types=1);
use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Database\Query\AlterableInterface;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Entity\Entity\EntityFormDisplay;
use Drupal\Core\Url;

/**
 * Filter that limits test entity list to revisable ones.
 */
const ENTITY_TEST_TYPES_REVISABLE = 1;

/**
 * Filter that limits test entity list to multilingual ones.
 */
const ENTITY_TEST_TYPES_MULTILINGUAL = 2;

/**
 * Filter that limits test entity list to ones that can be routed.
 */
const ENTITY_TEST_TYPES_ROUTING = 3;

/**
 * Returns a list of test entity types.
 *
 * The returned entity types are one for each available entity storage type:
 * - The plain entity_test type supports neither revisions nor multilingual
 *   properties.
 * - The entity_test_mul type supports multilingual properties.
 * - The entity_test_rev type supports revisions.
 * - The entity_test_mulrev type supports both revisions and multilingual
 *   properties.
 *
 * @param int $filter
 *   Either ENTITY_TEST_TYPES_REVISABLE to only return revisable entity types or
 *   ENTITY_TEST_TYPES_MULTILINGUAL to only return multilingual ones. Defaults
 *   to NULL, which returns all.
 *
 * @return array
 *   List with entity_types.
 */
function entity_test_entity_types($filter = NULL) {
    $types = [];
    if ($filter === NULL || $filter === ENTITY_TEST_TYPES_ROUTING) {
        $types[] = 'entity_test';
    }
    if ($filter != ENTITY_TEST_TYPES_REVISABLE) {
        $types[] = 'entity_test_mul';
        $types[] = 'entity_test_mul_langcode_key';
        $types[] = 'entity_test_mul_changed';
    }
    if ($filter != ENTITY_TEST_TYPES_MULTILINGUAL) {
        $types[] = 'entity_test_rev';
    }
    if ($filter === ENTITY_TEST_TYPES_ROUTING) {
        $types[] = 'entity_test_base_field_display';
        $types[] = 'entity_test_string_id';
        $types[] = 'entity_test_no_id';
        $types[] = 'entity_test_mul_with_bundle';
    }
    $types[] = 'entity_test_mulrev';
    $types[] = 'entity_test_mulrev_changed';
    return array_combine($types, $types);
}

/**
 * Implements hook_entity_type_alter().
 */
function entity_test_entity_type_alter(array &$entity_types) {
    $state = \Drupal::state();
    
    /** @var \Drupal\Core\Entity\EntityTypeInterface[] $entity_types */
    foreach (entity_test_entity_types() as $entity_type) {
        // Optionally specify a translation handler for testing translations.
        if ($state->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_rev tests to override the entity type definition.
    $entity_types['entity_test_rev'] = $state->get('entity_test_rev.entity_type', $entity_types['entity_test_rev']);
    $entity_types['entity_test_revpub'] = $state->get('entity_test_revpub.entity_type', $entity_types['entity_test_revpub']);
    // Enable the entity_test_new only when needed.
    if (!$state->get('entity_test_new')) {
        unset($entity_types['entity_test_new']);
    }
    else {
        // Allow tests to override the entity type definition.
        $entity_types['entity_test_new'] = \Drupal::state()->get('entity_test_new.entity_type', $entity_types['entity_test_new']);
    }
    $entity_test_definition = $entity_types['entity_test'];
    $entity_test_definition->set('entity_keys', $state->get('entity_test.entity_keys', []) + $entity_test_definition->getKeys());
    // Allow tests to alter the permission granularity of entity_test_mul.
    $entity_types['entity_test_mul']->set('permission_granularity', \Drupal::state()->get('entity_test_mul.permission_granularity', 'entity_type'));
}

/**
 * Implements hook_entity_base_field_info().
 */
function entity_test_entity_base_field_info(EntityTypeInterface $entity_type) {
    $fields = [];
    if ($entity_type->id() === 'entity_test' && \Drupal::state()->get('entity_test.internal_field')) {
        $fields['internal_string_field'] = BaseFieldDefinition::create('string')->setLabel('Internal field')
            ->setInternal(TRUE);
    }
    if ($entity_type->id() === 'entity_test_mul' && \Drupal::state()->get('entity_test.required_default_field')) {
        $fields['required_default_field'] = BaseFieldDefinition::create('string')->setLabel('Required field with default value')
            ->setRequired(TRUE)
            ->setDefaultValue('this is a default value');
    }
    if ($entity_type->id() === 'entity_test_mul' && \Drupal::state()->get('entity_test.required_multi_default_field')) {
        $fields['required_multi_default_field'] = BaseFieldDefinition::create('string')->setLabel('Required field with default value')
            ->setRequired(TRUE)
            ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
            ->setDefaultValue([
            [
                'value' => 'this is the first default field item',
            ],
            [
                'value' => 'this is the second default value',
            ],
            [
                'value' => 'you get the idea...',
            ],
        ]);
    }
    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);
    }
}

/**
 * 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::service('entity_bundle.listener')->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::service('entity_bundle.listener')->onBundleDelete($bundle, $entity_type);
}

/**
 * Implements hook_entity_bundle_info().
 */
function entity_test_entity_bundle_info() {
    $bundles = [];
    $entity_types = \Drupal::entityTypeManager()->getDefinitions();
    foreach ($entity_types as $entity_type_id => $entity_type) {
        if ($entity_type->getProvider() == 'entity_test' && !in_array($entity_type_id, [
            'entity_test_with_bundle',
            'entity_test_mul_with_bundle',
        ], TRUE)) {
            $bundles[$entity_type_id] = \Drupal::state()->get($entity_type_id . '.bundles', [
                $entity_type_id => [
                    'label' => 'Entity Test Bundle',
                ],
            ]);
        }
    }
    return $bundles;
}

/**
 * Implements hook_entity_bundle_info_alter().
 */
function entity_test_entity_bundle_info_alter(&$bundles) {
    $entity_info = \Drupal::entityTypeManager()->getDefinitions();
    $state = \Drupal::state();
    foreach ($bundles as $entity_type_id => &$all_bundle_info) {
        if ($entity_info[$entity_type_id]->getProvider() == 'entity_test') {
            if ($state->get('entity_test.translation') && $entity_info[$entity_type_id]->isTranslatable()) {
                foreach ($all_bundle_info as &$bundle_info) {
                    $bundle_info['translatable'] = TRUE;
                    if ($state->get('entity_test.untranslatable_fields.default_translation_affected')) {
                        $bundle_info['untranslatable_fields.default_translation_affected'] = TRUE;
                    }
                }
            }
        }
    }
}

/**
 * Implements hook_entity_view_mode_info_alter().
 */
function entity_test_entity_view_mode_info_alter(&$view_modes) {
    $entity_info = \Drupal::entityTypeManager()->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::entityTypeManager()->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_TYPE_view_mode_alter().
 */
function entity_test_entity_test_view_mode_alter(string &$view_mode, EntityInterface $entity) : void {
    if ($view_mode == 'entity_test.vm_alter_test') {
        $view_mode = 'entity_test.vm_alter_full';
    }
}

/**
 * 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);
}

/**
 * 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_mode_alter().
 */
function entity_test_entity_form_mode_alter(&$form_mode, EntityInterface $entity) {
    if ($entity->getEntityTypeId() === 'entity_test' && $entity->get('name')->value === 'compact_form_mode') {
        $form_mode = 'compact';
    }
}

/**
 * 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' => new FormattableMarkup('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());
}

/**
 * Implements hook_entity_revision_create().
 */
function entity_test_entity_revision_create(EntityInterface $new_revision, EntityInterface $entity, $keep_untranslatable_fields) {
    _entity_test_record_hooks('entity_revision_create', [
        'new_revision' => $new_revision,
        'entity' => $entity,
        'keep_untranslatable_fields' => $keep_untranslatable_fields,
    ]);
}

/**
 * Implements hook_ENTITY_TYPE_revision_create() for 'entity_test_mulrev'.
 */
function entity_test_entity_test_mulrev_revision_create(EntityInterface $new_revision, EntityInterface $entity, $keep_untranslatable_fields) {
    if ($new_revision->get('name')->value == 'revision_create_test_it') {
        $new_revision->set('name', 'revision_create_test_it_altered');
    }
    _entity_test_record_hooks('entity_test_mulrev_revision_create', [
        'new_revision' => $new_revision,
        'entity' => $entity,
        'keep_untranslatable_fields' => $keep_untranslatable_fields,
    ]);
}

/**
 * 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 field item attributes on field_test_text if it exists.
            // See \Drupal\Tests\system\Functional\Entity\EntityViewControllerTest::testFieldItemAttributes().
            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',
                        'property' => 'schema:text',
                    ];
                }
            }
            // Add an 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();
    }
    // Create specific labels to allow or deny access based on certain test
    // conditions.
    // @see \Drupal\KernelTests\Core\Entity\EntityAccessControlHandlerTest
    if ($entity->label() == 'Accessible') {
        return AccessResult::allowed();
    }
    if ($entity->label() == 'Inaccessible') {
        return AccessResult::forbidden();
    }
    // 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);
    if ($entity_bundle === 'forbidden_access_bundle') {
        // We need to cover a case in which a bundle is specifically forbidden
        // from creation (as opposed to neutral access).
        return AccessResult::forbidden();
    }
    // 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();
}

/**
 * Implements hook_query_entity_test_access_alter().
 */
function entity_test_query_entity_test_access_alter(AlterableInterface $query) {
    if (!\Drupal::state()->get('entity_test_query_access')) {
        return;
    }
    
    /** @var \Drupal\Core\Database\Query\Select|\Drupal\Core\Database\Query\AlterableInterface $query */
    if (!\Drupal::currentUser()->hasPermission('view all entity_test_query_access entities')) {
        $query->condition('entity_test_query_access.name', 'published entity');
    }
}

/**
 * Implements hook_ENTITY_TYPE_form_mode_alter().
 */
function entity_test_entity_test_form_mode_alter(&$form_mode, EntityInterface $entity) : void {
    if ($entity->getEntityTypeId() === 'entity_test' && $entity->get('name')->value === 'test_entity_type_form_mode_alter') {
        $form_mode = 'compact';
    }
}

Functions

Title Deprecated Summary
entity_test_create_bundle Creates a new bundle for entity_test entities.
entity_test_delete_bundle Deletes a bundle for entity_test entities.
entity_test_entity_access Implements hook_entity_access().
entity_test_entity_base_field_info Implements hook_entity_base_field_info().
entity_test_entity_base_field_info_alter Implements hook_entity_base_field_info_alter().
entity_test_entity_bundle_info Implements hook_entity_bundle_info().
entity_test_entity_bundle_info_alter Implements hook_entity_bundle_info_alter().
entity_test_entity_create_access Implements hook_entity_create_access().
entity_test_entity_display_build_alter Implements hook_entity_display_build_alter().
entity_test_entity_extra_field_info Implements hook_entity_extra_field_info().
entity_test_entity_field_access Implements hook_entity_field_access().
entity_test_entity_field_access_alter Implements hook_entity_field_access_alter().
entity_test_entity_form_display_alter Implements hook_entity_form_display_alter().
entity_test_entity_form_mode_alter Implements hook_entity_form_mode_alter().
entity_test_entity_form_mode_info_alter Implements hook_entity_form_mode_info_alter().
entity_test_entity_insert Implements hook_entity_insert().
entity_test_entity_operation_alter Implements hook_entity_operation_alter().
entity_test_entity_predelete Implements hook_entity_predelete().
entity_test_entity_prepare_view Implements hook_entity_prepare_view().
entity_test_entity_presave Implements hook_entity_presave().
entity_test_entity_revision_create Implements hook_entity_revision_create().
entity_test_entity_test_access Implements hook_ENTITY_TYPE_access() for 'entity_test'.
entity_test_entity_test_create_access Implements hook_ENTITY_TYPE_create_access() for 'entity_test'.
entity_test_entity_test_form_mode_alter Implements hook_ENTITY_TYPE_form_mode_alter().
entity_test_entity_test_insert Implements hook_ENTITY_TYPE_insert() for 'entity_test'.
entity_test_entity_test_mulrev_changed_translation_create Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mulrev_changed'.
entity_test_entity_test_mulrev_changed_translation_delete Implements hook_ENTITY_TYPE_translation_delete().
entity_test_entity_test_mulrev_changed_translation_insert Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mulrev'.
entity_test_entity_test_mulrev_revision_create Implements hook_ENTITY_TYPE_revision_create() for 'entity_test_mulrev'.
entity_test_entity_test_mulrev_translation_create Implements hook_ENTITY_TYPE_translation_create().
entity_test_entity_test_mulrev_translation_delete Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mulrev'.
entity_test_entity_test_mulrev_translation_insert Implements hook_ENTITY_TYPE_translation_insert().
entity_test_entity_test_mul_changed_translation_create Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul_changed'.
entity_test_entity_test_mul_changed_translation_delete Implements hook_ENTITY_TYPE_translation_delete().
entity_test_entity_test_mul_changed_translation_insert Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul_changed'.
entity_test_entity_test_mul_langcode_key_translation_create Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul_langcode_key'.
entity_test_entity_test_mul_langcode_key_translation_delete Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mul_langcode_key'.
entity_test_entity_test_mul_langcode_key_translation_insert Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul_langcode_key'.
entity_test_entity_test_mul_translation_create Implements hook_ENTITY_TYPE_translation_create() for 'entity_test_mul'.
entity_test_entity_test_mul_translation_delete Implements hook_ENTITY_TYPE_translation_delete() for 'entity_test_mul'.
entity_test_entity_test_mul_translation_insert Implements hook_ENTITY_TYPE_translation_insert() for 'entity_test_mul'.
entity_test_entity_test_view_mode_alter Implements hook_ENTITY_TYPE_view_mode_alter().
entity_test_entity_translation_create Implements hook_entity_translation_create().
entity_test_entity_translation_delete Implements hook_entity_translation_delete().
entity_test_entity_translation_insert Implements hook_entity_translation_insert().
entity_test_entity_types Returns a list of test entity types.
entity_test_entity_type_alter Implements hook_entity_type_alter().
entity_test_entity_update Implements hook_entity_update().
entity_test_entity_view_mode_info_alter Implements hook_entity_view_mode_info_alter().
entity_test_field_default_value Field default value callback.

Constants

Title Deprecated Summary
ENTITY_TEST_TYPES_MULTILINGUAL Filter that limits test entity list to multilingual ones.
ENTITY_TEST_TYPES_REVISABLE Filter that limits test entity list to revisable ones.
ENTITY_TEST_TYPES_ROUTING Filter that limits test entity list to ones that can be routed.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.