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
04/10/2025, by Ivan

Menu

Questo tutorial è stato originariamente pubblicato su Web Wash. Tuttavia, Berdir ha chiesto se potevo pubblicarlo anche qui, quindi eccolo.

Il modulo in Drupal 7 permette di memorizzare esempi di codice/snippet in un campo. Viene fornito con un campo personalizzato chiamato “Campo snippet” e mostra tre elementi del form: descrizione, codice sorgente e modalità di evidenziazione della sintassi (cioè il linguaggio di programmazione).

Ma ora è arrivato il momento di aggiornare il modulo a Drupal 8.

In questa guida vi mostrerò come ho creato un campo personalizzato “base” in Drupal 8. Non entrerò nei dettagli di PSR–4, annotazioni o plugin, altrimenti la guida diventerebbe enorme.

Invece, aggiungerò i link ad altre risorse che spiegano questi concetti in maniera più approfondita.

Detto questo, se cercate una documentazione dettagliata sulla Field API in Drupal 8, consultate queste serie:

 

In Drupal 8 i campi non vengono implementati tramite hook come in Drupal 7. Invece vengono creati con la nuova Plugin API di Drupal 8. Questo significa che, invece di implementare hook, definiamo una classe per il widget, il formattatore e il tipo di campo. Molti hook di Drupal 7, come hook_field_schema, hook_field_is_empty e altri, sono diventati metodi nelle classi.

Passo 1: implementare il tipo di campo

La prima cosa da fare è definire una classe del tipo di campo chiamata SnippetsItem, che estende la classe FieldItemBase.

1. In Drupal 8 le classi vengono caricate con PSR-4.

Quindi, per definire la classe SnippetsItem, dobbiamo creare il file SnippetsItem.php e posizionarlo in “module” /src/Plugin/Field/FieldType/SnippetsItem.php

/**
 * @file
 * Contains \Drupal\snippets\Plugin\Field\FieldType\SnippetsItem.
 */

namespace Drupal\snippets\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;

Nel file aggiungiamo il namespace Drupal\snippets\Plugin\Field\FieldType e tre istruzioni use:

  • Drupal\Core\Field\FieldItemBase
  • Drupal\Core\Field\FieldStorageDefinitionInterface
  • Drupal\Core\TypedData\DataDefinition

2. Ora dobbiamo definire i dettagli del campo, come l’ID, l’etichetta, il widget predefinito e il formattatore. È l’equivalente di hook_field_info in Drupal 7.

In Drupal 8 molti hook informativi sono stati sostituiti dalle annotazioni.

/**
 * Plugin implementation of the 'snippets' field type.
 *
 * @FieldType(
 *   id = "snippets_code",
 *   label = @Translation("Snippets field"),
 *   description = @Translation("This field stores code snippets in the database."),
 *   default_widget = "snippets_default",
 *   default_formatter = "snippets_default"
 * )
 */
class SnippetsItem extends FieldItemBase { }

Quindi, invece di implementare hook_field_info, definiamo il campo come annotazione nel docblock sopra la classe.

Gli attributi delle annotazioni sono autoesplicativi. Assicurati che default_widget e default_formatter facciano riferimento agli ID delle annotazioni del widget e del formatter, non alle classi.

Se vuoi approfondire le annotazioni, visita la pagina di documentazione dei plugin basati su annotazioni su drupal.org.

3. Ora che abbiamo la classe del tipo di campo, dobbiamo definire alcuni metodi. Il primo è schema().

In Drupal 7, per creare un campo personalizzato, si definiva lo schema con hook_field_schema. In Drupal 8 si definisce lo schema aggiungendo il metodo schema() nella classe SnippetsItem.

La documentazione Schema API descrive la struttura dell’array dello schema e i valori possibili.

/**
 * {@inheritdoc}
 */
public static function schema(FieldStorageDefinitionInterface $field) {
  return array(
    'columns' => array(
      'source_description' => array(
        'type' => 'varchar',
        'length' => 256,
        'not null' => FALSE,
      ),
      'source_code' => array(
        'type' => 'text',
        'size' => 'big',
        'not null' => FALSE,
      ),
      'source_lang' => array(
        'type' => 'varchar',
        'length' => 256,
        'not null' => FALSE,
      ),
    ),
  );
}

4. Poi aggiungiamo il metodo isEmpty(), per definire quando un campo è vuoto. È l’equivalente di hook_field_is_empty in Drupal 7.

/**
 * {@inheritdoc}
 */
public function isEmpty() {
  $value = $this->get('source_code')->getValue();
  return $value === NULL || $value === '';
}

5. Infine, aggiungiamo il metodo propertyDefinitions().

/**
 * {@inheritdoc}
 */
static $propertyDefinitions;

/**
 * {@inheritdoc}
 */
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['source_description'] = DataDefinition::create('string')
      ->setLabel(t('Snippet description'));

    $properties['source_code'] = DataDefinition::create('string')
      ->setLabel(t('Snippet code'));

    $properties['source_lang'] = DataDefinition::create('string')
      ->setLabel(t('Programming Language'))
      ->setDescription(t('Snippet code language'));

    return $properties;
  }

Questo metodo definisce i tipi di dati contenuti nei valori del campo. “Campo snippet” ha tre valori: descrizione, codice e linguaggio. Li ho aggiunti come stringhe nel metodo.

Per saperne di più, vai alla sezione Come Entity API implementa Typed Data API su drupal.org.

Clicca qui per vedere il file completo. Nota: deve essere aggiornato a PSR-4, per maggiori dettagli vedi https://www.drupal.org/node/2128865.

Passo 2: implementare il widget di campo

Dopo aver definito il tipo di campo, creiamo il widget. Serve una classe SnippetsDefaultWidget che estende WidgetBase.

1. Creiamo il file SnippetsDefaultWidget.php e lo aggiungiamo in “module” /src/Plugin/Field/FieldWidget/SnippetsDefaultWidget.php.

/**
 * @file
 * Contains \Drupal\snippets\Plugin\Field\FieldWidget\SnippetsDefaultWidget.
 */

namespace Drupal\snippets\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

Il namespace deve essere Drupal\snippets\Plugin\Field\FieldWidget e bisogna aggiungere tre use:

  • Drupal\Core\Field\FieldItemListInterface
  • Drupal\Core\Field\WidgetBase
  • Drupal\Core\Form\FormStateInterface

2. Poi definiamo il widget con l’annotazione. È l’equivalente di hook_field_widget_info in Drupal 7.

/**
 * Plugin implementation of the 'snippets_default' widget.
 *
 * @FieldWidget(
 *   id = "snippets_default",
 *   label = @Translation("Snippets default"),
 *   field_types = {
 *     "snippets_code"
 *   }
 * )
 */
class SnippetsDefaultWidget extends WidgetBase { }

Assicurati che field_types nell’annotazione faccia riferimento all’ID del tipo di campo, in questo caso snippets_code, definito in @FieldType.

3. Infine definiamo il form del widget, aggiungendo formElement() alla classe SnippetsDefaultWidget. È l’equivalente di hook_field_widget_form in Drupal 7.

/**
 * {@inheritdoc}
 */
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {

  $element['source_description'] = array(
        '#title' => $this->t('Description'),
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]->source_description) ? $items[$delta]->source_description : NULL,
      );
  $element['source_code'] = array(
        '#title' => $this->t('Code'),
        '#type' => 'textarea',
        '#default_value' => isset($items[$delta]->source_code) ? $items[$delta]->source_code : NULL,
      );
  $element['source_lang'] = array(
        '#title' => $this->t('Source language'),
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]->source_lang) ? $items[$delta]->source_lang : NULL,
      );
  return $element;
}

Clicca qui per vedere il file completo. Nota: deve essere aggiornato a PSR-4, maggiori dettagli su https://www.drupal.org/node/2128865.

Passo 3: implementare il formattatore di campo

L’ultimo pezzo è il formattatore, definito con una classe SnippetsDefaultFormatter che estende FormatterBase.

1. Creiamo SnippetsDefaultFormatter.php in “module”/src/Plugin/Field/FieldFormatter/SnippetsDefaultFormatter.php.

/**
 * @file
 * Contains \Drupal\snippets\Plugin\field\formatter\SnippetsDefaultFormatter.
 */

namespace Drupal\snippets\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;

Il namespace deve essere Drupal\snippets\Plugin\Field\FieldFormatter e bisogna aggiungere: Drupal\Core\Field\FieldItemListInterface e Drupal\Core\Field\FormatterBase.

2. Definiamo il formattatore come annotazione. È l’equivalente di hook_field_formatter_info.

/**
 * Plugin implementation of the 'snippets_default' formatter.
 *
 * @FieldFormatter(
 *   id = "snippets_default",
 *   label = @Translation("Snippets default"),
 *   field_types = {
 *     "snippets_code"
 *   }
 * )
 */
class SnippetsDefaultFormatter extends FormatterBase { }

3. Aggiungiamo il metodo viewElements() per definire l’output del campo. È l’equivalente di hook_field_formatter_view in Drupal 7.

/**
 * {@inheritdoc}
 */
public function viewElements(FieldItemListInterface $items, $langcode) {
  $elements = array();
  foreach ($items as $delta => $item) {
    // Render output usando il tema snippets_default.
    $source = array(
      '#theme' => 'snippets_default',
      '#source_description' => $item->source_description,
      '#source_code' => $item->source_code,
    );
    
    $elements[$delta] = array('#markup' => drupal_render($source));
  }

  return $elements;
}

Nota che qui utilizzo un template personalizzato snippets_default per renderizzare gli snippet prima che vengano mostrati dal formatter.

La ragione è che non volevo aggiungere troppa logica o HTML dentro viewElements().

Clicca qui per vedere il file completo. Nota: deve essere aggiornato a PSR-4, maggiori dettagli su https://www.drupal.org/node/2128865.

Conclusione

Come detto, la principale differenza in Drupal 8 è che i campi vengono creati con la Plugin API, non con gli hook. Una volta capita questa differenza, la creazione di un campo è molto simile a Drupal 7. Molti metodi in Drupal 8 corrispondono agli hook in Drupal 7.

Se vuoi provare gli snippet, scarica la release 8.x-dev e testala.