Field API Drupal 8 - Власні форматтери та віджети

11.03.2014
Field API D8 - Custom Formatters & Widgets
Автор:

В Drupal 8 кардинально змінився процес створення власних форматтерів та віджетів. Якщо в Drupal 7 це можна було зробити за допомогою хуків, то у новій версії цей процес більше схожий на написання Ctools плагінів. Далі в цьому блозі ми розкажемо чому.

В Drupal 8 замість хуків з’явилися методи класів, і це фактично означає, що головний файл модуля .module може бути навіть порожнім. Застосування класів передбачає успадкування. Наприклад, це чітко можна помітити в ядрі вісімки (image форматтер успадковує file форматтер). Далі розглянемо створення власного форматтера для поля.

Спочатку потрібно створити папку для плагінів в модулі, тепер всі вони (форматтери, віджети та ін.) розміщуються в окремих файлах. Шлях буде приблизно таким:

example_module/lib/Drupal/example_module/Plugin/field/FieldFormatter/ExampleFormatter.php

Велика кількість директорій є незмінним атрибутом стандарту PSR-0. На drupal.org існує ціла тема, присвячена обговоренню цього, а також схожого до нього стандарту PSR-4 та їх актуальності.

У Drupal 7 створення власного форматтера розпочиналося з hook_field_formatter_info() - у новій же версії більшість (якщо не всі) інфо-хуки замінено анотаціями. В даному випадку  використовується анотаційний клас \Drupal\field\Annotation\FieldFormatter. Наведемо приклад плагін-стайл форматтера:

<?php
/**
* Plugin implementation of the 'example_formatter' formatter
*
* @FieldFormatter(
*   id = "example_formatter",
*   label = @Translation("Example formatter"),
*   field_types = {
*   "text",
*   },
*   settings = {
*   "trim_length" = "300",
*   },
*   edit = {
* "editor" = "form"
*   }
* )
*/
class ExampleFormatter extends FormatterBase { 
 }

Далі веб розробнику потрібно використати hook_field_formatter_settings_form() - тепер це FormatterInterface::settingsForm(). Фактично це так і залишилась простою формою. Єдине, що можна підкреслити, це те, що налаштування форматтера доступні викликом $this->getSetting(‘settings_key’). Також зміни торкнулися і таких хуків, як hook_field_formatter_prepare_view() - тепер вони виглядають так: FormatterInterface::prepareView() та hook_field_formatter_view() - FormatterInterface::viewElements(). Крім того, методи тепер отримають значення поля як об’єкта  \Drupal\Core\Field\FieldItemListInterface - раніше це був простий масив $items. Більше про це можна прочитати в темі Drupal 8 Entity API

Що ж стосується хуків-альтерів, то вони залишилися незмінними - hook_field_formatter_settings_summary_alter()hook_field_formatter_info_alter()  та  hook_field_formatter_settings_form_alter().

Наступним кроком буде створення власного віджету. Тут роботи буде дещо більше, ніж при написанні форматтера. Раніше цей процес відбувався за допомогою 4-х хуків. Тепер його перенесено у методи в класах із використанням нового Plugin API. Так як і у прикладі зі створенням форматтера,hook_field_widget_info() перекочував у анотацію. Створимо файл example_module/lib/Drupal/example_module/Plugin/field/FieldWidget/ExampleWidget.php, який є аналогією до форматтера та звичайно приклад:

<?php
/**
* Plugin implementation of the 'example_widget' widget
*
* @FieldWidget(
*   id = "example_widget",
*   label = @Translation("Example widget"),
*   field_types = {
*   "text",
*   "text_long"
*   },
*   settings = {
*   "size" = "600",
*   }
* )
*/
class ExampleWidget extends WidgetBase { }

Саме поняття “instance” тепер зникає; налаштування, описані в анотації, можна витягнути з $this->getSetting('settings_key') або $this->getSettings() без вказівки ключа. Якщо потрібно звернутись до інших властивостей поля, то можна скористатися методом $this->getFieldDefinition(), який вертає об’єкт \Drupal\Core\Entity\Field\FieldDefinitionInterface. Даний інтерфейс об’єднує те, що раніше розділялось і називалось $field та $instance. Наведемо приклад WidgetInterface::settingsForm():

<?php
  /**
   * {@inheritdoc}
   */
  public function settingsForm(array $form, array &$form_state) {
    $element = array();

    $element['size'] = array(
      '#type' => 'number',
      '#title' => t('Size of textfield'),
      '#default_value' => $this->getSetting('size'),
      '#required' => TRUE,
      '#min' => 1,
  );

  return $element;
  }

hook_field_widget_form() стає WidgetInterface::formElement():

<?php
  /**
   * {@inheritdoc}
   */
  public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, array &$form_state) {
    $main_widget = $element + array(
      '#type' => 'textfield',
      '#default_value' => isset($items[$delta]->value) ? $items[$delta]->value : NULL,
      '#size' => $this->getSetting('size'),
      '#placeholder' => $this->getSetting('placeholder'),
      '#maxlength' => $this->getSetting('max_length'),
      '#attributes' => array('class' => array('text-full')),
  );

  if ($this->getSetting('text_processing')) {
      $element = $main_widget;
      $element['#type'] = 'text_format';
      $element['#format'] = isset($items[$delta]->format) ? $items[$delta]->format : NULL;
      $element['#base_type'] = $main_widget['#type'];
  }
  else {
      $element['value'] = $main_widget;
  }

  return $element;
  }

Крім того, hook_field_widget_error() було замінено на WidgetInterface::errorElement(). Також додалося декілька нових методів, таких як WidgetInterface::settingsSummary() та WidgetInterface::massageFormValues(). Інформацію про них можна прочитати на drupal.org.

Отже, можна зробити висновок, що новий Plugin API є доволі зручним інструментом для написання власного функціоналу, а саме віджетів і форматтерів. Сама будова Field API в Drupal 8 є доволі схожою до старішої версії, але уже помітний чіткий вплив об’єктно-орієнтованого програмування та PSR-0 тобто чітка розмежованість файлів по директоріях відповідно до так званих namespaces, що категоризує та групує файли у процесі розробки.

2 votes, Рейтинг: 5

Також по темі

1

Підтримка транзакцій з'явилася вже в Drupal 7, включаючи ті бази даних, які самостійно їх не підтримують. Давайте розглянемо як правильно їх використовувати, щоб досягнути потрібного результату....

2

У своїй практиці ми досить часто використовуємо Git Flow модель роботи з репозиторієм. Схема роботи з якою більш детально описана нижче.

3

Продовжуючи розгляд можливостей модуля Panels, в цьому блозі мова піде про створення власного контексту за допомогою Chaos tool suite.

4

При розробці збірки CommerceBox у нас виникло питання, як зберігати у фічі певний функціонал для apps. Метод Feature Injection вирішує цю проблему.  

5

Apps - це модуль, що позиціонується як наступний крок у розвитку...

Subscribe to our blog updates