Обзор: создание настраиваемого поля
Этот учебник был первоначально опубликован в 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.