logo

Extra Block Types (EBT) - Nueva experiencia con Layout Builder❗

Extra Block Types (EBT): tipos de bloques con estilo y personalizables: Presentaciones de diapositivas, Pestañas, Tarjetas, Acordeones y muchos más. Configuraciones integradas para fondo, DOM Box y plugins de JavaScript. Experimenta hoy el futuro de la construcción de diseños.

Módulos de demostración EBT Descargar módulos EBT

❗Extra Paragraph Types (EPT) - Nueva experiencia con Paragraphs

Extra Paragraph Types (EPT): conjunto de módulos basado en párrafos de forma análoga.

Módulos de demostración EPT Descargar módulos EPT

Scroll

Definición y uso de definiciones de Campo de Entidad de Contenido

18/06/2025, by Ivan

Las entidades de contenido deben definir explícitamente todos sus campos proporcionando definiciones en la clase de las entidades. Las definiciones de campo se basan en la API de datos tipados (Typed Data API) (véase cómo las entidades la implementan).

Definiciones de campos

Los tipos de entidad definen sus campos base en un método estático de la clase de entidad. Los campos base no son campos configurables y siempre existen en un tipo de entidad dado, por ejemplo, el título de un nodo o las fechas de creación y modificación. El gestor de entidades añade campos configurables y no configurables proporcionados por otros módulos, invocando hook_entity_field_info() y hook_entity_field_info_alter(). Así también se añaden los campos configurados mediante Field UI (estos hooks ya no existen en la API actual).

Las definiciones de campos son objetos simples que implementan la FieldDefinitionInterface, mientras que los campos base normalmente se crean con la clase BaseFieldDefinition, y los campos configurables implementan directamente la interfaz con los objetos de configuración correspondientes (los llamados Field y FieldInstance).
Las definiciones de campos también son el lugar para definir restricciones de validación para elementos o propiedades del campo. Se pueden usar todas las implementaciones de plugins de tipo de campo. (Esta interfaz y clase ya no existen).

Actualmente, todos los campos son listas de elementos de campo, lo que significa que la clase FieldItem definida como tipo estará envuelta en la clase FieldItemList, que representa la lista de esos elementos.

Todos los campos (incluidos los campos base) también pueden tener widgets y formateadores para su visualización y edición.

Campos base

A continuación, un ejemplo resumido de definiciones de campos para el tipo de entidad nodo.

use Drupal\Core\Field\BaseFieldDefinition;

class Node implements NodeInterface {

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions($entity_type) {
    // El ID del nodo es un entero, usando la clase de elemento FieldItem IntegerItem.
    $fields['nid'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('Node ID'))
      ->setDescription(t('El ID del nodo.'))
      ->setReadOnly(TRUE);

    // El campo UUID usa el tipo uuid_field, que garantiza que se genere un nuevo UUID al crear la entidad.
    $fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->setLabel(t('UUID'))
      ->setDescription(t('El UUID del nodo.'))
      ->setReadOnly(TRUE);

    // El código de idioma se define como language_field, que asegura que se establezca un idioma predeterminado válido para nuevas entidades.
    $fields['langcode'] = BaseFieldDefinition::create('language')
      ->setLabel(t('Código de idioma'))
      ->setDescription(t('El código de idioma del nodo.'));

    // El título es StringItem, el valor por defecto es cadena vacía y define una restricción para que el valor tenga como máximo 255 caracteres.
    $fields['title'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Título'))
      ->setDescription(t('El título de este nodo, siempre tratado como texto plano sin formato.'))
      ->setRequired(TRUE)
      ->setTranslatable(TRUE)
      ->setSettings(array(
        'default_value' => '',
        'max_length' => 255,
      ));

    // El uid es una referencia a la entidad usuario, lo que permite acceder al ID de usuario con $node->uid->target_id
    // y a la entidad usuario con $node->uid->entity. NodeInterface también define getAuthor() y getAuthorId(). (@todo: revisar owner vs. revisionAuthor)
    $fields['uid'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('ID de usuario'))
      ->setDescription(t('El ID del autor del nodo.'))
      ->setSettings(array(
        'target_type' => 'user',
        'default_value' => 0,
      ));

    // El campo changed actualiza automáticamente la marca de tiempo cada vez que
    // la entidad se guarda.
    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Modificado'))
      ->setDescription(t('La hora en que se editó el nodo por última vez.'));
      
    return $fields;
  }
}

Campos multivaluados

Para indicar el número máximo de elementos permitidos en un campo, llama al método setCardinality().
Por ejemplo, para definir un campo que pueda tener 3 elementos:

->setCardinality(3);

Para definir un campo con valores ilimitados, llama a:

->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);

Ejemplo de definición de campo multivaluado para referencia a entidades de tipo “usuario”:

$fields['my_field'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('Etiqueta del campo'))
  ->setDescription(t('Descripción del campo.'))
  ->setRevisionable(TRUE)
  ->setSetting('target_type', 'user')
  ->setSetting('handler', 'default')
  ->setTranslatable(TRUE)
  ->setDisplayOptions('view', [
    'label' => 'hidden',
    'type' => 'author',
    'weight' => 0,
  ])
  ->setDisplayOptions('form', [
    'type' => 'entity_reference_autocomplete',
    'weight' => 5,
    'settings' => [
      'match_operator' => 'CONTAINS',
      'size' => '60',
      'autocomplete_type' => 'tags',
      'placeholder' => '',
    ],
  ])
  ->setDisplayConfigurable('form', TRUE)
  ->setDisplayConfigurable('view', TRUE)
  ->setRequired(TRUE)
  ->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);

La entidad también puede proveer campos que existan sólo para un tipo (bundle) específico o modificar sus propiedades para ese tipo. Por ejemplo, el título de un nodo puede tener etiquetas diferentes para cada bundle. Para permitir cambios por bundle, la definición del campo base debe clonarse antes de hacer modificaciones, porque de otro modo se modificaría la definición del campo base y afectaría a todos los bundles.

use Drupal\node\Entity\NodeType;

  /**
   * {@inheritdoc}
   */
  public static function bundleFieldDefinitions(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
    $node_type = NodeType::load($bundle);
    $fields = array();
    if (isset($node_type->title_label)) {
      $fields['title'] = clone $base_field_definitions['title'];
      $fields['title']->setLabel($node_type->title_label);
    }
    return $fields;
  }

Tipos de campos

El núcleo de Drupal provee una lista de tipos de campo que pueden usarse para campos base. Además, los módulos pueden proveer tipos adicionales que también pueden usarse.

  • string: cadena simple
  • boolean: valor booleano almacenado como entero
  • integer: entero con validaciones para valores mínimos y máximos (también disponible para decimal y float)
  • decimal: decimal con precisión y escala configurables
  • float: número de punto flotante
  • language: contiene código de idioma y el idioma como propiedad calculada
  • timestamp: marca de tiempo Unix almacenada como entero
  • created: marca de tiempo que usa el tiempo actual por defecto
  • changed: marca de tiempo que se actualiza automáticamente al guardar la entidad
  • datetime: fecha almacenada como cadena ISO 8601
  • uri: contiene URI. El módulo Link provee un tipo de campo para enlaces que puede incluir título y puede apuntar a URI interna o externa / ruta
  • uuid: campo UUID que genera uno nuevo como valor predeterminado
  • email: correo electrónico con validación, widgets y formateadores apropiados
  • entity_reference: referencia a entidad mediante target_id y propiedad computada entity. El módulo entity_reference provee widgets y formateadores cuando está habilitado
  • map: puede contener cualquier número de propiedades arbitrarias almacenadas como cadena serializada

Campos configurables

Los campos configurables pueden registrarse en hook_entity_base_field_info() y hook_entity_bundle_field_info(). Los siguientes ejemplos añaden campos base y bundle.

use Drupal\Core\Field\BaseFieldDefinition;

/**
 * Implements hook_entity_base_field_info().
 */
function path_entity_base_field_info(EntityTypeInterface $entity_type) {
  if ($entity_type->id() === 'taxonomy_term' || $entity_type->id() === 'node') {
    $fields['path'] = BaseFieldDefinition::create('path')
      ->setLabel(t('Alias de ruta'))
      ->setComputed(TRUE);

    return $fields;
  }
}

/**
 * Implements hook_entity_bundle_field_info().
 */
function field_entity_bundle_field_info(EntityTypeInterface $entity_type, $bundle, array $base_field_definitions) {
  if ($entity_type->isFieldable()) {
    // Los campos configurables, siempre adjuntos a un bundle específico, se añaden 'por bundle'.
    return Field::fieldInfo()->getBundleInstances($entity_type->id(), $bundle);
  }
}

Existen hooks alter correspondientes para cada uno de los anteriores.

Almacenamiento de campos

Si tu campo no tiene requisitos especiales, la API Entity Field puede encargarse del almacenamiento en base de datos y actualizar las tablas adecuadamente. Esto es el comportamiento por defecto para campos que no están marcados como computados (setComputed(TRUE)) ni como almacenamiento personalizado (setCustomStorage(TRUE)).

Por ejemplo, supongamos que quieres añadir un nuevo campo base para todas las entidades Node que contenga un valor booleano simple para indicar si el contenido está destacado.

use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Field\BaseFieldDefinition;

/**
 * Implements hook_entity_base_field_info().
 */
function MYMODULE_entity_base_field_info(EntityTypeInterface $entity_type) {
  $fields = array();

  // Añadir un campo base 'highlight' para todos los tipos de nodo.
  if ($entity_type->id() === 'node') {
    $fields['highlight'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Destacado'))
      ->setDescription(t('Indica si el nodo está destacado.'))
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE)
      ->setDisplayOptions('form', array(
        'type' => 'boolean_checkbox',
        'settings' => array(
          'display_label' => TRUE,
        ),
      ))
      ->setDisplayConfigurable('form', TRUE);
  }

  return $fields;
}

He intentado muchas veces y visitar update.php no añade la columna en la base de datos, pero ejecutar

  \Drupal::entityTypeManager()->clearCachedDefinitions();
  \Drupal::service('entity.definition_update_manager')->applyUpdates();

puede crear la columna en la base de datos. Nota: esto también ejecutará cualquier actualización pendiente para otras definiciones de campos.

Actualización: el código anterior no funcionará con Drupal 8.7

Consulta un ejemplo en esta entrada de cambios

Instalación de una nueva definición de almacenamiento de campo

function example_update_8701() {
  $field_storage_definition = BaseFieldDefinition::create('boolean')
    ->setLabel(t('Revision translation affected'))
    ->setDescription(t('Indica si la última edición de una traducción pertenece a la revisión actual.'))
    ->setReadOnly(TRUE)
    ->setRevisionable(TRUE)
    ->setTranslatable(TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('revision_translation_affected', 'block_content', 'block_content', $field_storage_definition);
}

Si tu módulo personalizado añade un campo nuevo, se agregará automáticamente al habilitar el módulo y se eliminará al deshabilitarlo.

Si el módulo ya está instalado y necesitas escribir un hook_update_N para actualizar definiciones de campos, puedes hacer algo como:

/**
 * Añade el campo highlight a todos los nodos.
 */
function MYMODULE_update_8001() {
  $entity_type = \Drupal::service('entity_type.manager')->getDefinition('node');
  \Drupal::service('entity.definition_update_manager')->updateEntityType($entity_type);
}

o bien

/**
 * Añade el campo 'revision_translation_affected' a las entidades 'node'.
 */
function node_update_8001() {
  // Instala la definición que tenía este campo en
  // \Drupal\node\Entity\Node::baseFieldDefinitions()
  // en el momento de escribir esta función update. Si se despliega código
  // que cambia esta definición, el módulo correspondiente debe implementar
  // una función update que invoque
  // \Drupal::entityDefinitionUpdateManager()->updateFieldStorageDefinition()
  // con la nueva definición.
  $storage_definition = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Revision translation affected'))
      ->setDescription(t('Indica si la última edición de una traducción pertenece a la revisión actual.'))
      ->setReadOnly(TRUE)
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE);

  \Drupal::entityDefinitionUpdateManager()
    ->installFieldStorageDefinition('revision_translation_affected', 'node', 'node', $storage_definition);
}

Consulta https://www.drupal.org/node/2554097 para más información y ejemplos.

Trabajo con definiciones de campos

Nota. Dado que los objetos son datos complejos, deben seguir ComplexDataInterface. Desde la perspectiva de datos tipados, todos los elementos de datos tipados contenidos en un objeto complejo son propiedades. Esta restricción/convención de nombres puede ser eliminada.

// Comprueba si una entidad tiene un campo determinado.
$entity->hasField('field_tags');

// Devuelve un array con claves nombradas para todos los campos y sus definiciones. Por ejemplo, el campo ‘image’.
$field_definitions = $entity->getFieldDefinitions();

// Devuelve un array con claves nombradas para todas las propiedades de un campo y sus definiciones, por ejemplo, las propiedades ‘file_id’ y ‘alt’ del campo image.
$property_definitions = $entity->image->getFieldDefinition()->getPropertyDefinitions();

// Devuelve solo la definición para la propiedad ‘alt’.
$alt_definition = $entity->image->getFieldDefinition()->getPropertyDefinition('alt');

// Las definiciones de campos de entidad también pueden obtenerse desde el gestor de entidades,
// el siguiente devuelve todos los campos disponibles para todos los bundles.
\Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type);

// El siguiente devuelve los campos disponibles para un bundle dado.
\Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $bundle);

Widgets y formateadores para campos base

Los campos base pueden indicar widgets y formateadores que deben usar, igual que los campos configurables. El widget, formateador y los parámetros necesarios se definen en la clase FieldDefinition así:

use Drupal\Core\Field\BaseFieldDefinition;

// ...

    $fields['title'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Título'))
      ->setDescription(t('El título de este nodo, siempre tratado como texto plano sin formato.'))
      ->setRequired(TRUE)
      ->setTranslatable(TRUE)
      ->setSettings(array(
        'default_value' => '',
        'max_length' => 255,
      ))
      ->setDisplayOptions('view', array(
        'label' => 'hidden',
        'type' => 'string',
        'weight' => -5,
      ))
      ->setDisplayOptions('form', array(
        'type' => 'string',
        'weight' => -5,
      ))
      ->setDisplayConfigurable('form', TRUE);

Esto usa el formateador “string” y el widget correspondiente, además configura el peso para el título del nodo. setDisplayConfigurable() puede usarse para hacer que el campo sea visible en la interfaz de usuario de administración de visualización de formulario/gestión para poder cambiar el orden y la visualización de etiquetas. Actualmente el núcleo no permite cambiar el widget o sus configuraciones desde la interfaz de usuario.

Para configurar un campo como oculto por defecto, también puedes definir la clave de región en el array que pasas a setDisplayOptions() y establecerla como oculta.

Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.