function EntityFieldManager::buildBaseFieldDefinitions

Same name in other branches
  1. 9 core/lib/Drupal/Core/Entity/EntityFieldManager.php \Drupal\Core\Entity\EntityFieldManager::buildBaseFieldDefinitions()
  2. 8.9.x core/lib/Drupal/Core/Entity/EntityFieldManager.php \Drupal\Core\Entity\EntityFieldManager::buildBaseFieldDefinitions()
  3. 11.x core/lib/Drupal/Core/Entity/EntityFieldManager.php \Drupal\Core\Entity\EntityFieldManager::buildBaseFieldDefinitions()

Builds base field definitions for an entity type.

Parameters

string $entity_type_id: The entity type ID. Only entity types that implement \Drupal\Core\Entity\FieldableEntityInterface are supported.

Return value

\Drupal\Core\Field\FieldDefinitionInterface[] An array of field definitions, keyed by field name.

Throws

\LogicException Thrown if a config entity type is given or if one of the entity keys is flagged as translatable.

1 call to EntityFieldManager::buildBaseFieldDefinitions()
EntityFieldManager::getBaseFieldDefinitions in core/lib/Drupal/Core/Entity/EntityFieldManager.php

File

core/lib/Drupal/Core/Entity/EntityFieldManager.php, line 216

Class

EntityFieldManager
Manages the discovery of entity fields.

Namespace

Drupal\Core\Entity

Code

protected function buildBaseFieldDefinitions($entity_type_id) {
    
    /** @var \Drupal\Core\Entity\ContentEntityTypeInterface $entity_type */
    $entity_type = $this->entityTypeManager
        ->getDefinition($entity_type_id);
    $class = $entity_type->getClass();
    
    /** @var string[] $keys */
    $keys = array_filter($entity_type->getKeys());
    // Fail with an exception for non-fieldable entity types.
    if (!$entity_type->entityClassImplements(FieldableEntityInterface::class)) {
        throw new \LogicException("Getting the base fields is not supported for entity type {$entity_type->getLabel()}.");
    }
    // Retrieve base field definitions.
    
    /** @var \Drupal\Core\Field\FieldStorageDefinitionInterface[] $base_field_definitions */
    $base_field_definitions = $class::baseFieldDefinitions($entity_type);
    // Make sure translatable entity types are correctly defined.
    if ($entity_type->isTranslatable()) {
        // The langcode field should always be translatable if the entity type is.
        if (isset($keys['langcode']) && isset($base_field_definitions[$keys['langcode']])) {
            $base_field_definitions[$keys['langcode']]->setTranslatable(TRUE);
        }
        // A default_langcode field should always be defined.
        if (!isset($base_field_definitions[$keys['default_langcode']])) {
            $base_field_definitions[$keys['default_langcode']] = BaseFieldDefinition::create('boolean')->setLabel($this->t('Default translation'))
                ->setDescription($this->t('A flag indicating whether this is the default translation.'))
                ->setTranslatable(TRUE)
                ->setRevisionable(TRUE)
                ->setDefaultValue(TRUE);
        }
    }
    // Make sure that revisionable entity types are correctly defined.
    if ($entity_type->isRevisionable()) {
        $field_name = $entity_type->getRevisionMetadataKey('revision_default');
        $base_field_definitions[$field_name] = BaseFieldDefinition::create('boolean')->setLabel($this->t('Default revision'))
            ->setDescription($this->t('A flag indicating whether this was a default revision when it was saved.'))
            ->setStorageRequired(TRUE)
            ->setInternal(TRUE)
            ->setTranslatable(FALSE)
            ->setRevisionable(TRUE);
    }
    // Make sure that revisionable and translatable entity types are correctly
    // defined.
    if ($entity_type->isRevisionable() && $entity_type->isTranslatable()) {
        // The 'revision_translation_affected' field should always be defined.
        // This field has been added unconditionally in Drupal 8.4.0 and it is
        // overriding any pre-existing definition on purpose so that any
        // differences are immediately available in the status report.
        $base_field_definitions[$keys['revision_translation_affected']] = BaseFieldDefinition::create('boolean')->setLabel($this->t('Revision translation affected'))
            ->setDescription($this->t('Indicates if the last edit of a translation belongs to current revision.'))
            ->setReadOnly(TRUE)
            ->setRevisionable(TRUE)
            ->setTranslatable(TRUE);
    }
    // Assign base field definitions the entity type provider.
    $provider = $entity_type->getProvider();
    foreach ($base_field_definitions as $definition) {
        // @todo Remove this check once FieldDefinitionInterface exposes a proper
        //   provider setter. See https://www.drupal.org/node/2346329.
        if ($definition instanceof BaseFieldDefinition) {
            $definition->setProvider($provider);
        }
    }
    // Retrieve base field definitions from modules.
    $this->moduleHandler
        ->invokeAllWith('entity_base_field_info', function (callable $hook, string $module) use (&$base_field_definitions, $entity_type) {
        $module_definitions = $hook($entity_type) ?? [];
        // Ensure the provider key actually matches the name of the provider
        // defining the field.
        foreach ($module_definitions as $field_name => $definition) {
            // @todo Remove this check once FieldDefinitionInterface exposes a
            //   proper provider setter. See https://www.drupal.org/node/2346329.
            if ($definition instanceof BaseFieldDefinition && $definition->getProvider() == NULL) {
                $definition->setProvider($module);
            }
            $base_field_definitions[$field_name] = $definition;
        }
    });
    // Automatically set the field name, target entity type and bundle
    // for non-configurable fields.
    foreach ($base_field_definitions as $field_name => $base_field_definition) {
        if ($base_field_definition instanceof BaseFieldDefinition) {
            $base_field_definition->setName($field_name);
            $base_field_definition->setTargetEntityTypeId($entity_type_id);
            $base_field_definition->setTargetBundle(NULL);
        }
    }
    // Invoke alter hook.
    $this->moduleHandler
        ->alter('entity_base_field_info', $base_field_definitions, $entity_type);
    // Ensure defined entity keys are there and have proper revisionable and
    // translatable values.
    foreach (array_intersect_key($keys, array_flip([
        'id',
        'revision',
        'uuid',
        'bundle',
    ])) as $key => $field_name) {
        if (!isset($base_field_definitions[$field_name])) {
            throw new \LogicException("The {$field_name} field definition does not exist and it is used as {$key} entity key.");
        }
        if ($base_field_definitions[$field_name]->isRevisionable()) {
            throw new \LogicException("The {$base_field_definitions[$field_name]->getLabel()} field cannot be revisionable as it is used as {$key} entity key.");
        }
        if ($base_field_definitions[$field_name]->isTranslatable()) {
            throw new \LogicException("The {$base_field_definitions[$field_name]->getLabel()} field cannot be translatable as it is used as {$key} entity key.");
        }
    }
    // Make sure translatable entity types define the "langcode" field properly.
    if ($entity_type->isTranslatable() && (!isset($keys['langcode']) || !isset($base_field_definitions[$keys['langcode']]) || !$base_field_definitions[$keys['langcode']]->isTranslatable())) {
        throw new \LogicException("The {$entity_type->getLabel()} entity type cannot be translatable as it does not define a translatable \"langcode\" field.");
    }
    return $base_field_definitions;
}

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