Extra Block Types (EBT) - New Layout Builder experience❗

Extra Block Types (EBT) - styled, customizable block types: Slideshows, Tabs, Cards, Accordions and many others. Built-in settings for background, DOM Box, javascript plugins. Experience the future of layout building today.

Demo EBT modules Download EBT modules

❗Extra Paragraph Types (EPT) - New Paragraphs experience

Extra Paragraph Types (EPT) - analogical paragraph based set of modules.

Demo EPT modules Download EPT modules

Scroll

Обзор: создание настраиваемого поля

20/05/2020, by maria
Этот учебник был первоначально опубликован в Web Wash. Однако Бердир спросил, могу ли я разместить учебник здесь, так что вот оно.

Модуль в Drupal 7 позволяет хранить примеры кода / фрагменты в поле. Он поставляется с настраиваемым полем под названием «Поле фрагментов» и отображает три элемента формы: описание, исходный код и режим подсветки синтаксиса (какой язык программирования).

Но теперь пришло время обновить модуль до Drupal 8.

В этом уроке я покажу вам, как я создал «базовое» настраиваемое поле в Drupal 8. Я не буду вдаваться в подробности о PSR – 4, аннотациях или плагинах, или этот урок будет огромным.

Вместо этого я добавлю ссылки на другие сайты, которые объясняют эту концепцию дальше.

При этом, если вы ищете подробную документацию по Field API в Drupal 8, ознакомьтесь со следующими сериями:

 

В Drupal 8 поля не реализованы с использованием хуков, как в Drupal 7. Вместо этого они создаются с использованием нового API-плагина Drupal 8. Это означает, что вместо реализации хуков мы определяем класс для виджета, средства форматирования и элемента поля. Большинство хуков Drupal 7, таких как hook_field_schema, hook_field_is_empty и другие; теперь методы в классах.

Шаг 1: Реализация элемента поля

Первая часть работы, которую нам нужно сделать, это определить класс элемента поля с именем SnippetsItem, который расширяет класс FieldItemBase.

1. В Drupal 8 классов загружаются с использованием PSR-4.

Итак, чтобы определить класс SnippetsItem, нам нужно создать файл SnippetsItem.php и поместить его в «модуль» /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;

Затем в файл мы добавляем пространство имен Drupal\snippets\Plugin\Field\FieldType и три оператора использования: Drupal\Core\Field\FieldItemBase, Drupal\Core\Field\FieldStorageDefinitionInterface и Drupal\Core\TypedData\DataDefinition.

2. Теперь нам нужно определить фактические детали поля, такие как идентификатор поля, метка, виджет по умолчанию, форматтер и т. д. Это эквивалентно реализации hook_field_info в Drupal 7.

В Drupal 8 многие, если не все, информационные хуки были заменены аннотациями.

/**
 * 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 { }

Поэтому вместо реализации hook_field_info мы определяем поле как аннотацию внутри комментария над классом.

Атрибуты аннотаций не требуют пояснений. Просто убедитесь, что default_widget и default_formatter ссылаются на идентификатор аннотации виджета и форматера, а не на класс.

Если вы хотите узнать больше об аннотациях, посетите страницу документации плагинов на основе аннотаций на drupal.org.

3. Теперь, когда у нас есть класс элемента поля, нам нужно определить несколько методов. Первое, что мы рассмотрим, это schema()

В Drupal 7 при создании настраиваемого поля вы определяете schema с помощью hook_field_schema. В Drupal 8 мы определяем schema, добавляя метод schema() в класс SnippetsItem.

Документация по API Schema содержит описание структуры массива схемы и возможных значений.
/**
 * {@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. Теперь нам нужно добавить метод isEmpty () и определить, что составляет пустой элемент поля. Этот метод аналогичен реализации hook_field_is_empty в Drupal 7.

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

5. Последний метод, который мы добавим в класс, это метод 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;
  }

Этот метод используется для определения типа данных, которые существуют в значениях поля. «Поле фрагментов» имеет только три значения: описание, код и язык. Поэтому я просто добавил эти значения в метод в виде строк.

Чтобы узнать больше об этом, перейдите к разделу Как Entity API реализует документацию API Typed Data на drupal.org.

Нажмите здесь, чтобы увидеть весь файл. Примечание: его необходимо обновить до спецификации PSR-4, для получения более подробной информации см. Https://www.drupal.org/node/2128865.

Шаг 2: реализовать виджет поля

Теперь, когда мы определили элемент поля, давайте создадим виджет поля. Нам нужно создать класс с именем SnippetsDefaultWidget, который расширяет класс WidgetBase.

1. Итак, создайте файл SnippetsDefaultWidget.php и добавьте его в «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;

Убедитесь, что пространство имен файла - Drupal\snippets\Plugin\Field\FieldWidget и добавьте следующие три оператора использования: Drupal\Core\Field\FieldItemListInterface и Drupal\Core\Field\WidgetBase и Drupal\Core\Form\FormStateInterface.

2. Далее нам нужно определить виджет с помощью аннотации. Это эквивалентно использованию hook_field_widget_info в 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 { }

Просто наперед, убедитесь, что атрибут field_types в аннотации ссылается на типы полей, используя их ID. Для этого модуля это snippets_code, потому что мы добавили id = "snippets_code" в аннотацию @FieldType.

3. И, наконец, нам нужно определить фактическую форму виджета. Мы делаем это, добавляя метод formElement() в класс SnippetsDefaultWidget. Этот метод аналогичен использованию hook_field_widget_form в 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;
}

Нажмите здесь, чтобы увидеть весь файл. Примечание: его необходимо обновить до спецификации PSR-4, для получения более подробной информации см. Https://www.drupal.org/node/2128865.

Шаг 3: внедрить средство форматирования полей

Последний элемент головоломки - это средство форматирования поля, и мы создаем его, определяя класс с именем SnippetsDefaultFormatter, который расширяет класс FormatterBase.

1. Создайте файл SnippetsDefaultFormatter.php и добавьте его в «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;

Убедитесь, что пространство имен файла - Drupal\snippets\Plugin\Field\FieldFormatter и добавьте следующие операторы использования: Drupal\Core\Field\FieldItemListInterface и Drupal\Core\Field\FormatterBase.

2. Далее нам нужно определить форматер как аннотацию. Так же, как мы делали для виджета и типа поля, это эквивалентно использованию 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. Теперь осталось только добавить метод viewElements() и определить фактический модуль форматирования поля. Опять же, этот метод аналогичен использованию hook_field_formatter_view в Drupal 7.

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

  return $elements;
}

Следует обратить внимание на то, что я использую пользовательский шаблон snippets_default для рендеринга фрагментов до того, как они будут отображены средством форматирования.

Причина этого в том, что я не хотел помещать много логики или HTML-кода в метод viewElements().

Нажмите здесь, чтобы увидеть весь файл. Примечание: его необходимо обновить до спецификации PSR-4, для получения более подробной информации см. Https://www.drupal.org/node/2128865.

Вывод

Как указывалось ранее, самым большим изменением в Drupal 8 является то, что поля создаются с помощью API плагинов, а не хуков. Как только вы это поймете, концепция создания поля очень похожа на Drupal 7. Многие методы в Drupal 8 соответствуют ловушкам в Drupal 7.

Если вы хотите протестировать фрагменты кода, скачайте релиз 8.x-dev и попробуйте.

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.