logo

Extra Block Types (EBT) - Nuova esperienza con Layout Builder❗

Extra Block Types (EBT) - tipi di blocchi stilizzati e personalizzabili: Slideshows, Tabs, Cards, Accordion e molti altri. Impostazioni integrate per sfondo, DOM Box, plugin javascript. Vivi oggi il futuro della costruzione dei layout.

Demo moduli EBT Scarica moduli EBT

❗Extra Paragraph Types (EPT) - Nuova esperienza con Paragraphs

Extra Paragraph Types (EPT) - insieme di moduli basati su paragrafi in modo analogo.

Demo moduli EPT Scarica moduli EPT

Scorri

Definizione e utilizzo delle definizioni dei campi delle Content Entity

30/09/2025, by Ivan

Le Content entities devono definire esplicitamente tutti i loro campi, fornendo le definizioni all’interno della classe delle entità. Le definizioni dei campi si basano sull’API dei dati tipizzati (Typed data API) (vedi anche Come le entità lo implementano).

Definizioni dei campi

I tipi di entità definiscono i loro campi di base nel metodo statico della classe dell’entità. I campi di base sono campi non configurabili che esistono sempre in un dato tipo di entità, ad esempio il titolo di un nodo o le date di creazione e modifica. L’Entity Manager completa i campi con campi configurabili e non configurabili forniti da altri moduli, invocando hook_entity_field_info() e hook_entity_field_info_alter(). È così che vengono aggiunti anche i campi configurati tramite Field UI (questi hook non esistono più secondo l’API).

Le definizioni dei campi sono semplici oggetti che implementano FieldDefinitionInterface, mentre i campi di base sono generalmente creati con la classe BaseFieldDefinition, e i campi configurabili implementano direttamente l’interfaccia con i relativi oggetti di configurazione (i cosiddetti Field e FieldInstance).
Le definizioni dei campi sono anche il posto dove definire i vincoli di validazione per gli elementi del campo o per le proprietà di un elemento. Possono essere usate tutte le implementazioni dei plugin di tipo campo. (Questa interfaccia e classe non esistono più).

I campi sono sempre una lista di FieldItem, il che significa che la classe FieldItem definita come tipo sarà incapsulata nella classe FieldItemList, che rappresenta la lista degli elementi del campo.

Tutti i campi (inclusi i campi di base) possono avere widget e formatter per la loro visualizzazione e modifica.

Campi di base

Ecco un esempio ridotto di elenco delle definizioni dei campi per il tipo di entità nodo.

use Drupal\Core\Field\BaseFieldDefinition;

class Node implements NodeInterface {

  /**
   * {@inheritdoc}
   */
  public static function baseFieldDefinitions($entity_type) {
    // L'ID del nodo è un intero, usa la classe IntegerItem.
    $fields['nid'] = BaseFieldDefinition::create('integer')
      ->setLabel(t('Node ID'))
      ->setDescription(t('The node ID.'))
      ->setReadOnly(TRUE);

    // Il campo UUID usa il tipo uuid_field che garantisce che un nuovo UUID
    // venga generato automaticamente quando viene creata un’entità.
    $fields['uuid'] = BaseFieldDefinition::create('uuid')
      ->setLabel(t('UUID'))
      ->setDescription(t('The node UUID.'))
      ->setReadOnly(TRUE);

    // Il codice lingua è definito come language_field, che garantisce che
    // venga impostata una lingua valida di default per le nuove entità.
    $fields['langcode'] = BaseFieldDefinition::create('language')
      ->setLabel(t('Language code'))
      ->setDescription(t('The node language code.'));

    // Il titolo è uno StringItem, con valore predefinito stringa vuota e
    // una proprietà vincolata a massimo 255 caratteri.
    $fields['title'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Title'))
      ->setDescription(t('The title of this node, always treated as non-markup plain text.'))
      ->setRequired(TRUE)
      ->setTranslatable(TRUE)
      ->setSettings(array(
        'default_value' => '',
        'max_length' => 255,
      ));

    // Il campo uid è un entity reference al tipo entità user, che permette
    // di accedere all’ID utente con $node->uid->target_id e all’entità utente
    // con $node->uid->entity.
    $fields['uid'] = BaseFieldDefinition::create('entity_reference')
      ->setLabel(t('User ID'))
      ->setDescription(t('The user ID of the node author.'))
      ->setSettings(array(
        'target_type' => 'user',
        'default_value' => 0,
      ));

    // Il campo changed aggiorna automaticamente il timestamp ogni volta che
    // l’entità viene salvata.
    $fields['changed'] = BaseFieldDefinition::create('changed')
      ->setLabel(t('Changed'))
      ->setDescription(t('The time that the node was last edited.'))
    return $fields;
  }
}

Campi multivalore

Per specificare il numero massimo di elementi consentiti per un campo, usa il metodo setCardinality().
Ad esempio, per definire un campo che può avere fino a 3 elementi:

->setCardinality(3);

Per definire un campo con valori illimitati, chiama:

->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);

Esempio di definizione di un campo multivalore per riferimenti a entità «user»:

$fields['my_field'] = BaseFieldDefinition::create('entity_reference')
  ->setLabel(t('The label of the field'))
  ->setDescription(t('The description of the field.'))
  ->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);

L’entità può anche fornire campi che esistono solo per un bundle specifico, o modificarli per bundle. Ad esempio, il titolo del nodo può avere un’etichetta diversa per ogni bundle. Per applicare modifiche per bundle, la definizione del campo base deve essere clonata prima di modificarla, altrimenti modificheresti il campo base per tutti i bundle.

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;
}

Tipi di campo

Il core di Drupal fornisce un elenco di tipi di campo che possono essere usati per i campi di base. Inoltre, i moduli possono fornire tipi di campo aggiuntivi utilizzabili.

  • string: una semplice stringa
  • boolean: un valore booleano memorizzato come intero
  • integer: intero con impostazioni di validazione per valori minimi e massimi (esiste anche per decimal e float)
  • decimal: numero decimale con precisione e scala configurabili
  • float: numero in virgola mobile
  • language: contiene codice lingua e lingua come proprietà calcolata
  • timestamp: timestamp Unix memorizzato come intero
  • created: timestamp che usa l’orario corrente come valore di default
  • changed: timestamp che si aggiorna automaticamente all’ora corrente al salvataggio
  • datetime: data memorizzata in formato ISO 8601
  • URI: contiene un URI. Il modulo link fornisce un campo link, che può includere un’etichetta e puntare a URI/route interne o esterne
  • uuid: campo UUID che genera un nuovo UUID di default
  • email: email con validazione, widget e formatter dedicati
  • entity_reference: riferimento a un’entità tramite target_id e proprietà entity calcolata. entity_reference.module fornisce widget e formatter quando abilitato
  • map: può contenere un numero arbitrario di proprietà, memorizzate come stringa serializzata

Campi configurabili

Campi aggiuntivi possono essere registrati in hook_entity_base_field_info() e hook_entity_bundle_field_info(). Nei seguenti esempi vengono aggiunti campi base e di 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('The path alias'))
      ->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()) {
    // I campi configurabili, che sono sempre associati a un bundle specifico,
    // vengono aggiunti “per bundle”.
    return Field::fieldInfo()->getBundleInstances($entity_type->id(), $bundle);
  }
}

Esistono gli alter hook corrispondenti per ciascuno dei casi sopra.

Storage dei campi

Se il tuo campo non ha requisiti particolari, l’API Entity Field può occuparsi dello storage nel database e aggiornare automaticamente lo schema. Questo è il comportamento di default per i campi che non sono marcati come calcolati (setComputed(TRUE)) o che non hanno specificato uno storage personalizzato (setCustomStorage(TRUE)).

Ad esempio, supponiamo di voler aggiungere un nuovo campo base a tutti i Node che contiene un semplice booleano per indicare se il contenuto è in evidenza.

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();

  // Aggiunge un campo 'Highlight' a tutti i tipi di nodo.
  if ($entity_type->id() === 'node') {
    $fields['highlight'] = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Highlight'))
      ->setDescription(t('Whether or not the node is highlighted.'))
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE)
      ->setDisplayOptions('form', array(
        'type' => 'boolean_checkbox',
        'settings' => array(
          'display_label' => TRUE,
        ),
      ))
      ->setDisplayConfigurable('form', TRUE);
  }

  return $fields;
}

Ho provato molte volte e visitare update.php non aggiungerà la colonna nel database, ma eseguire:

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

può creare la colonna nel database. Nota: questo eseguirà anche tutti gli update in sospeso per altre definizioni di campi.

Aggiornamento: il codice sopra non funziona con Drupal 8.7

Guarda l’esempio in questa nota di cambiamento

Installare una nuova definizione di field storage

function example_update_8701() {
  $field_storage_definition = BaseFieldDefinition::create('boolean')
    ->setLabel(t('Revision translation affected'))
    ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
    ->setReadOnly(TRUE)
    ->setRevisionable(TRUE)
    ->setTranslatable(TRUE);

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

Se il tuo modulo personalizzato aggiunge un nuovo campo, questo verrà aggiunto automaticamente all’attivazione del modulo e rimosso alla sua disinstallazione.

Se il tuo modulo è già installato e devi scrivere un hook_update_N per aggiornare le definizioni dei campi, puoi fare così:

/**
 * Aggiunge il campo highlight a tutti i nodi.
 */
function MYMODULE_update_8001() {
  $entity_type = \Drupal::service('entity_type.manager')->getDefinition('node');
  \Drupal::service('entity.definition_update_manager')->updateEntityType($entity_type);
}

oppure

/**
 * Aggiunge il campo 'revision_translation_affected' alle entità 'node'.
 */
function node_update_8001() {
  // Installa la definizione che questo campo aveva in
  // \Drupal\node\Entity\Node::baseFieldDefinitions()
  // al momento della scrittura di questa funzione di update. Se/quando il codice
  // viene modificato, il modulo corrispondente deve implementare una funzione di update
  // che invochi
  // \Drupal::entityDefinitionUpdateManager()->updateFieldStorageDefinition()
  // con la nuova definizione.
  $storage_definition = BaseFieldDefinition::create('boolean')
      ->setLabel(t('Revision translation affected'))
      ->setDescription(t('Indicates if the last edit of a translation belongs to current revision.'))
      ->setReadOnly(TRUE)
      ->setRevisionable(TRUE)
      ->setTranslatable(TRUE);

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

Vedi https://www.drupal.org/node/2554097 per ulteriori informazioni ed esempi.

Lavorare con le definizioni dei campi

Nota: Poiché le entità sono dati complessi, devono implementare ComplexDataInterface. Dal punto di vista dei dati tipizzati, tutti gli elementi tipizzati contenuti in un oggetto dati complesso sono proprietà. Questo vincolo può essere rimosso.

// Controlla se un’entità ha un certo campo.
$entity->hasField('field_tags');

// Restituisce un array con chiavi nominali per tutti i campi e le loro
// definizioni. Ad esempio il campo 'image'.
$field_definitions = $entity->getFieldDefinitions();

// Restituisce un array con le proprietà di un campo e le loro definizioni.
// Ad esempio per il campo 'image', le proprietà 'file_id' e 'alt'.
$property_definitions = $entity->image->getFieldDefinition()->getPropertyDefinitions();

// Restituisce solo la definizione per la proprietà 'alt'.
$alt_definition = $entity->image->getFieldDefinition()->getPropertyDefinition('alt');

// Le definizioni dei campi possono anche essere richieste all’entity manager,
// il seguente restituisce tutti i campi disponibili per tutti i bundle.
\Drupal::service('entity_field.manager')->getFieldStorageDefinitions($entity_type);

// Il seguente restituisce i campi disponibili per un dato bundle.
\Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $bundle);

Widget e formatter per campi di base

I campi di base possono specificare widget e formatter da usare, come i campi configurabili. Widget, formatter e parametri richiesti vengono definiti nella classe FieldDefinition come segue:

use Drupal\Core\Field\BaseFieldDefinition;

// ...

    $fields['title'] = BaseFieldDefinition::create('string')
      ->setLabel(t('Title'))
      ->setDescription(t('The title of this node, always treated as non-markup plain text.'))
      ->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);

In questo esempio vengono usati il formatter «string» e il widget, e viene configurato il peso del titolo del nodo. setDisplayConfigurable() può essere usato per rendere il campo visibile nell’interfaccia di gestione della visualizzazione/moduli, così da poter modificare ordine e visualizzazione delle etichette. Al momento, il core non permette di modificare widget o le loro impostazioni tramite interfaccia.

Per impostare un campo come nascosto di default, puoi anche definire la chiave «region» nell’array passato a setDisplayOptions() e impostarla su «hidden».