Pasar al contenido principal

Como crear un campo custom en Drupal 8

En Drupal 7 se hacía todo a través de hooks info y funciones que permitían formar toda la estructura del campo custom, aquí tenéis un ejemplo. Ahora en Drupal 8 se define todo mediante plugins.

Para ello vamos a crear de prueba el campo diff, que almacena 2 valores y te muestra la diferencia de los valores (el segundo menos el primero).

Para crear un campo custom en Drupal hace falta lo siguiente:

Definir un field type

Necesitamos crear un plugin field type para poder declarar el campo custom visible para la Field API. De esta forma podremos seleccionarlo al añadir campos custom a entidades. En esta clase tambien definiremos el esquema de base de datos y la configuración del campo, entre otras cosas.

Necesitaremos crear una clase en nuestro módulo, dentro de la carpeta src/Plugin/FieldType .

Como en todo plugin de Drupal 8 tendremos que añadir unas anotaciones para definir el field type:


/**
 * @FieldType(
 *   id = "diff",
 *   label = @Translation("Diff"),
 *   module = "diff_field",
 *   description = @Translation("Allow insert two numeric values and show his difference."),
 *   default_widget = "diff_field_widget",
 *   default_formatter = "diff_field_formatter"
 * )
 */

Aquí podemos ver los siguientes datos:

  • id: Identificador.
  • label: Nombre.
  • module: Módulo que define el campo.
  • description: Descripción del campo.
  • default_widget: Widget del campo usado por defecto para insertar los datos.
  • default_formatter: Formatter del campo usado por defecto para representar visualmente los datos.

Los métodos más importantes para el field type son:

  • schema: Define la estructura del campo en base de datos.
  • isEmpty: Define las condiciones que debe de tener el campo para decidir si está vacio o no. Es importante ya que se usa para decidir si guardar o no guardar, o borrar una entrada del campo.
  • storageSettingsForm: Esto nos valdrá para poder establecer ciertas restricciones para poder añadir valores a los campos (por ejemplo, añadir una lista de opciones que deberá de ser siempre la misma). Los valores por defecto deben de configurarse en el método defaultStorageSettings. Esta configuración se aplica a todas las instancias que se hagan del campo, es decir, si reutilizas el campo en otro lugar, esta configuración se conserva. 
  • fieldSettingsForm: Esto permitirá configurar el campo a nivel de instancia, es decir, esto se puede configurar de forma distinta en cualquier sitio donde se utilice el campo.
  • propertyDefinitions: Define las propiedades del campo utilizando Data Definitions y así poder establecer reglas de validación sobre cada campo, y la información para que drupal lo pueda manejar.

Ejemplo:


class DiffFieldItem extends FieldItemBase {

  /**
   * {@inheritdoc}
   */
  public static function schema(FieldStorageDefinitionInterface $field_definition) {
    return array(
      'columns' => array(
        'value' => array(
          'type' => 'int',
        ),
        'value2' => array(
          'type' => 'int',
        ),
      ),
    );
  }

  /**
   * {@inheritdoc}
   */
  public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['value'] = DataDefinition::create('integer')
      ->setLabel(t('Value'))
      ->setRequired(TRUE);
    $properties['value2'] = DataDefinition::create('integer')
      ->setLabel(t('Value2'))
      ->setRequired(TRUE);

    return $properties;
  }

}

Definir un field widget

Para poder añadir datos al campo en un formulario de entidad, deberemos crear un field widget custom, que nos creara un elemento de formulario. Un field widget se puede utilizar para más de un campo de Drupal.

Para ello, crearemos un plugin de field type dentro de la carpeta src/Plugin/FieldType.

Anotaciones que deberemos indicar:


/**
 * @FieldWidget(
 *   id = "diff_field_widget",
 *   module = "diff_field",
 *   label = @Translation("Diff field widget"),
 *   field_types = {
 *     "diff"
 *   }
 * )
 */

Valores que añadimos:

  • id: Identificador.
  • label: Nombre.
  • module: Módulo que define el campo.
  • field_types: Campos con los que se podrá usar el widget.

Los métodos más importantes para el field widget son:

  • settingsForm: Ajustes del widget, que influirán en la interacción del usuario con el formulario. Estos settings se podrán mostrar después con el método settingsSummary
  • formElement: Formulario para definir el campo.

Ejemplo de widget:


class DiffFieldWidget extends WidgetBase {

  public function settingsForm(array $form, FormStateInterface $form_state) {
    parent::settingsForm($form, $form_state);
  }
  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
    $value = isset($items[$delta]->value) ? $items[$delta]: NULL;
    $element['value'] = array(
      '#title' => t('First value'),
      '#type' => 'number',
      '#default_value' => $value->value,
    );

    $element['value2'] = array(
      '#title' => t('Second value'),
      '#type' => 'number',
      '#default_value' => $value->value2,
    );

    return $element;
  }

}

Definir field formatter

Con los formatters podemos definir como se visualizará un campo.

Para ello, crearemos un plugin de field type dentro de la carpeta src/Plugin/FieldFormatter.

Deberemos de indicar estas anotaciones para declarar el field formatter:


/**
 * Plugin implementation of the 'diff' field formatter.
 *
 * @FieldFormatter(
 *   id = "diff_field_formatter",
 *   label = @Translation("Diff field format"),
 *   field_types = {
 *     "diff"
 *   }
 * )
 */

Valores que hemos añadido:

  • id: Identificador del formatter.
  • label: Título del formatter.
  • field_types: Field types que pueden usar este formatter.

En la clase que forma el field formatter los métodos más importantes son:

  • defaultSettings: Configuración por defecto del formatter.
  • settingsForm: Formulario de configuración del formatter.
  • settingsSummary: descripción de los ajustes hechos en el formatter.
  • viewElements: El único obligatorio, renderiza el valor del campo.

Ejemplo: 


class DiffFieldFormatter extends FormatterBase {
  /**
   * {@inheritdoc}
   */
  public function viewElements(FieldItemListInterface $items, $langcode) {
    $elements = array();

    foreach ($items as $delta => $item) {
      $value = $item->value - $item->value2;
      $elements[$delta] = array(
        '#type' => 'html_tag',
        '#tag' => 'p',
        '#value' => $value,
      );
    }

    return $elements;
  }

}

 

Con esto ya podríamos añadir nuestro campo propio en los tipos de contenido que queramos (y en cualquier entidad que permita añadir campos).

Omar Lopesino

Omar Lopesino

Senior Drupal developer