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

Схема конфигурации/метаданные

30/04/2020, by maria

Drupal 8 включает поддержку языка схемы/метаданных, созданного с помощью Kwalify (http://www.kuwata-lab.com/kwalify/) для конфигурационных файлов YAML. Сам Kwalify написан на Ruby, и нам потребовались небольшие корректировки в формате, поэтому не все детали Kwalify применимы напрямую, но это довольно близко.

Cheatsheet

Для быстрого понимания и некоторых удобных примеров, посмотрите этот шпаргалку, а затем продолжайте читать, если у вас все еще есть вопросы:

ConfigSchemaCheatSheet1.5Thumb

/sites/default/files/config-schema-cheat-sheet1.5.pdf

Вводный пример

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

<?php
$config = \Drupal::config('system.maintenance');
$message = $config->get('message');
$langcode = $config->get('langcode');
?>

(То, включено ли техническое обслуживание, хранится в state system, а не в конфигурации.)

Значения по умолчанию для этого объекта конфигурации хранятся в файле core/modules/system/config/install/system.maintenance.yml как:

message: '@site is currently under maintenance. We should be back shortly. Thank you for your patience.'
langcode: en

Каждый модуль может иметь столько объектов конфигурации, сколько необходимо. Все это объясняется в одном или нескольких файлах схемы, которые поставляются вместе с модулем. В случае системного модуля файлы находятся в core/modules/system/config/schema. Соответствующий раздел схемы из файла system.schema.yml выглядит следующим образом:

system.maintenance:
  type: config_object
  label: 'Maintenance mode'
  mapping:
    message:
      type: text
      label: 'Message to display when in maintenance mode'

Ключ верхнего уровня ("system.maintenance") в файле относится к базовому имени файла файла .yml ("system.maintenance.yml") и к имени объекта конфигурации (config ('system.maintenance')). Вложенные уровни описывают, что находится в файле. Схема конфигурации предопределяет два типа файлов конфигурации: config_object для глобальных файлов конфигурации и config_entity для сущностей. Тип config_object определен в core.data_types.schema.yml следующим образом:

# Root of a configuration object.

_core_config_info:
  type: mapping
  mapping:
    default_config_hash:
      type: string
      label: 'Default configuration hash'

config_object:
  type: mapping
  mapping:
    langcode:
      type: string
      label: 'Language code'
    _core:
      type: _core_config_info

Сопоставление типов является базовым типом для пар ключ-значение. Используя тип config_object, определение режима обслуживания повторно использует ключи langcode и _core и добавляет еще один ключ для самого сообщения. Возвращаясь к определению system.maintenance, метка схемы label:'Maintenance mode' описывает содержимое схемы. Затем фактические элементы перечислены под ключом сопоставления, где определен ключ сообщения, наследуя langcode и _core key от базового типа. Каждый элемент имеет тип и ключ метки, который соответственно описывает тип данных и дает описание данных. Метка обычно такая же или похожа на метку формы конфигурации, где значение может быть отредактировано системным администратором.

Во всех случаях, поддерживаемых ядром, элемент верхнего уровня в файле .yml будет отображением с элементами, описанными в списке отображения внизу. Вы должны использовать любой из двух определенных подтипов отображения config_object или config_entity. Отдельные элементы в отображении могут быть любого типа в зависимости от того, как вы определили данные. Сам ключ _core и все ключи в _core зарезервированы для ядра Drupal.

Для чего используются файлы схемы?

1. Основные файлы сценариев использования были представлены для многоязычной поддержки. У нас должен быть инструмент для идентификации всех переводимых строк в поставляемой конфигурации, поэтому, когда вы отправляете свои собственные настройки, а также представления по умолчанию, дополнительные роли пользователя, пункты меню и т. д. Мы можем предложить их для перевода в составе вашего модуля/темы выпуска на https://localize.drupal.org. Для этого варианта использования будет достаточно уровней и типов вложенности.

2. Мы также используем схемы для предоставления реальных форм перевода для настройки на основе ваших данных. В этом случае использования типы приобретают все большее значение, а метки становятся решающими. Модуль перевода базовой конфигурации использует схемы для создания форм перевода и сохранения переводов. Двумя наиболее важными встроенными переводимыми типами являются «метка» для однострочного ввода текста и «текст» для многострочного ввода текста.

3. Используя знания, встроенные в схемы конфигурации, о том, что хранится в объекте конфигурации, реализация персистентности по умолчанию для объектов конфигурации требует схемы конфигурации для объекта конфигурации, поэтому правильные свойства экспортируются с определенными типами. Хотя лучше предоставить схемы конфигурации, если вы действительно этого не хотите, реализуйте метод toArray () в своей реализации сущности конфигурации, чтобы не требовать схемы для сохранения сущностей конфигурации вашего типа.

4. Схема конфигурации также используется для автоматической привязки значений к ожидаемым типам. Это гарантирует, что хотя PHP и веб-формы в целом предпочитают строки всем остальным типам, при сохранении конфигурации используются правильные типы. Это важно, поэтому при развертывании конфигурации в разнице будут отображаться только реальные изменения, а не случайные изменения типа.

5. В PHPUnit все производные тесты TestBase обеспечивают строгое соблюдение схемы конфигурации по умолчанию. Это приведет к ошибкам схемы, если файл схемы отсутствует или недействителен. Хотя это и не рекомендуется, его можно пропустить, установив в своем тесте:

protected $strictConfigSchema = FALSE;

Смотрите https://drupal.org/project/config_inspector для модуля, который поможет с отладкой ваших схем. Модуль помогает найти отсутствующие схемы и элементы схемы с различными представлениями ваших данных и схемы.

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

Свойства

  • type: тип значения; может быть базовым или производным типом (см. примеры ниже).
  • label: метка пользовательского интерфейса для значения. Метка не обязательно должна соответствовать соответствующей метке формы конфигурации, но соответствие меток улучшит ясность.
  • translatable: перевод определенного типа; Примечание: вы можете использовать
type: label

как сокращение для:

type: string
translatable: true
  • nullable: может ли значение быть пустым; если не установлено, по умолчанию используется.
  • class: Используется только для базовых типов для назначения класса, реализующего синтаксический анализ (примеры ниже приведены для TypedData и конфигурационных типов, определенных системой).
  • Типо-специфичные свойства:

                     - mapping: Свойство для значения типа отображения, используемого для отображения базовых элементов в отображении. Ключи и типы значений в отображении должны быть описаны в схеме. В отображениях допускаются только строковые ключи.
                     - sequence: Свойство для значения типа последовательности, используемое для перечисления базовых элементов в последовательности. Ключи могут быть целыми числами или строками, они не имеют значения.

Типы, поддерживаемые в файлах метаданных

Как упоминалось выше, самые основные типы, а также некоторые интересные сложные типы определены в core.data_types.schema.yml.

# Undefined type used by the system to assign to elements at any level where
# configuration schema is not defined. Using explicitly has the same effect as
# not defining schema, so there is no point in doing that.
undefined:
  label: 'Undefined'
  class: '\Drupal\Core\Config\Schema\Undefined'

# Explicit type to use when no data typing is possible. Instead of using this
# type, we strongly suggest you use configuration structures that can be
# described with other structural elements of schema, and describe your schema
# with those elements.
ignore:
  label: 'Ignore'
  class: '\Drupal\Core\Config\Schema\Ignore'

# Basic scalar data types from typed data.
boolean:
  label: 'Boolean'
  class: '\Drupal\Core\TypedData\Plugin\DataType\BooleanData'
email:
  label: 'Email'
  class: '\Drupal\Core\TypedData\Plugin\DataType\Email'
integer:
  label: 'Integer'
  class: '\Drupal\Core\TypedData\Plugin\DataType\IntegerData'
float:
  label: 'Float'
  class: '\Drupal\Core\TypedData\Plugin\DataType\FloatData'
string:
  label: 'String'
  class: '\Drupal\Core\TypedData\Plugin\DataType\StringData'
uri:
  label: 'Uri'
  class: '\Drupal\Core\TypedData\Plugin\DataType\Uri'

Как можно видеть, большинство основных типов данных сопоставляются с их аналогами TypedData API. Этот пример также показывает, как легко определить ваши собственные типы. Просто определите класс, который будет соответствовать типу. Два оставшихся (более сложных) типа данных определены на основе реализаций классов:

# Container data types for lists with known and unknown keys.
mapping:
  label: Mapping
  class: '\Drupal\Core\Config\Schema\Mapping'
  definition_class: '\Drupal\Core\TypedData\MapDataDefinition'
sequence:
  label: Sequence
  class: '\Drupal\Core\Config\Schema\Sequence'
  definition_class: '\Drupal\Core\TypedData\ListDataDefinition'

Отображение, как показано выше, представляет собой тип списка пары ключ-значение («ассоциативный массив» или «хэш»), где каждый элемент может иметь различный тип, в то время как Sequence - это простой индексированный список («индексированный массив»), где элементы являются одним из одного типа или основаны на одном и том же имени динамического типа (см. ниже), и ключи не имеют значения. Другими словами, ключевое различие между последовательностями и отображениями заключается в последовательностях, в которых вы не знаете имен ключей и количества ключей, в то время как в отображениях все ключи определены явно. Последовательности могут использовать строковые ключи.

Все остальные типы, определенные в схемах конфигурации (включая саму system.maintenance), просто наследуются от других типов, например, «label», «path», «text», «date_format» и «color_hex» определяются как строки , Различие этих типов может помочь инструментам синтаксического анализа схемы идентифицировать текстовые типы для различных целей.

# Human readable string that must be plain text and editable with a text field.
label:
  type: string
  label: 'Label'
  translatable: true

# Internal Drupal path
path:
  type: string
  label: 'Path'

# Human readable string that can contain multiple lines of text or HTML.
text:
  type: string
  label: 'Text'
  translatable: true

# PHP Date format string that is translatable.
date_format:
  type: string
  label: 'Date format'
  translatable: true
  translation context: 'PHP date format'

# HTML color value.
color_hex:
  type: string
  label: 'Color'

Обратите внимание, что типы label, text и date_format также помечены как переводимые. Это означает, что модуль перевода основного интерфейса идентифицирует элементы с этими типами и переводит их на основе предоставленных сообществом или администратором переводов из базы данных, создавая файлы переопределения перевода. Обратите внимание, что переводимые строки могут получить контекст с ключом контекста перевода, как показано здесь для форматов даты. Таким образом, строки типа «Y» получат дополнительный контекст «Формат даты PHP», поэтому переводчики знают, что это не сокращение «Да», а формат даты PHP в течение многих лет.

Таким же образом вы можете определить повторно используемые сложные типы поверх базовых типов, используя формат, описанный выше для режима обслуживания:

# Mail text with subject and body parts.
mail:
  type: mapping
  label: 'Mail'
  mapping:
    subject:
      type: label
      label: 'Subject'
    body:
      type: text
      label: 'Body'

Это дает вам повторно используемый тип «mail» для настроек текста электронной почты, когда тема и тело находятся в списке отображения. Это то же самое, что и определение схемы для ключа конфигурации, но вы выбрали для него имя, которое не является существующим ключом конфигурации, поэтому оно не будет конфликтовать с другими определениями схемы. На основании этого определения «почта» может использоваться как тип в другом месте (как это используется в схеме параметров электронной почты пользовательского модуля в user.schema.yml):

user.mail:
 type: config_object
 label: 'Email settings'
 mapping:
  cancel_confirm:
    type: mail
    label: 'Account cancellation confirmation'
  password_reset:
    type: mail
    label: 'Password recovery'
  [....]

Наконец, еще раз два важных сложных типа для определения файлов конфигурации также определены здесь в core.data_types.schema.yml:

config_object:
  type: mapping
  mapping:
    langcode:
      type: string
      label: 'Language code'
    _core:
      type: _core_config_info

config_entity:
  type: mapping
  mapping:
    uuid:
      type: string
      label: 'UUID'
    langcode:
      type: string
      label: 'Language code'
    status:
      type: boolean
      label: 'Status'
    dependencies:
      type: config_dependencies
      label: 'Dependencies'
    third_party_settings:
      type: sequence
      label: 'Third party settings'
      sequence:
        type: '[%parent.%parent.%type].third_party.[%key]'
    _core:
      type: _core_config_info

Динамические ссылки на тип

Как показано выше, даже простые типы являются по существу ссылками, а сложные типы, такие как «почта», обычно используются для ссылки на сложные типы. Иногда тип значения не является статичным и может зависеть от данных, например, для стилей изображения, к которым могут применяться различные эффекты, или представлений, состоящих из различных плагинов. Вы можете ссылаться на ключи в данных как часть имени типа, чтобы ссылаться на динамические типы.

Значения переменных в типах должны быть заключены в [] (квадратные скобки), а значения переменных можно комбинировать с известными компонентами. Существует три типа ссылок:

1. Ссылка на ключ элемента: например, type:book.[% Key], где ключ% заменяется ключом элемента.
2. Ссылка на вложенный ключ: например, type: 'views.field.[Table]-[field]', где тип вычисляется на основе значения ключей таблицы и поля во вложенной структуре
3. Ссылка на родительский ключ: например, type: 'views.display.[% Parent.display_plugin]', где ключ display_plugin от родителя используется для определения типа элемента

Есть богатые примеры этого в стилях изображений и представлениях, которые широко используют плагины. Пример из стилей изображения с учетом core/modules/image/config/install/image.style.medium.yml, который имеет эту структуру данных YAML:

name: medium
label: 'Medium (220x220)'
effects:
  bddf0d06-42f9-4c75-a700-a33cafa25ea0:
    id: image_scale
    data:
      width: 220
      height: 220
      upscale: true
    weight: 0
    uuid: bddf0d06-42f9-4c75-a700-a33cafa25ea0
langcode: en

Здесь структура ключа данных зависит от типа эффекта, который указан в свойстве id эффекта. Поэтому используемый тип зависит от данных и не может быть задан статически. По-разному настроенные стили изображения будут использовать разные эффекты. Поэтому нам нужно встроить ссылку на спецификацию типа. Соответствующий раздел схемы из image.schema.yml выглядит следующим образом:

image.style.*:
  type: config_entity
  label: 'Image style'
  mapping:
    name:
      type: string
    label:
      type: label
      label: 'Label'
    effects:
      type: sequence
      sequence:
        type: mapping
        mapping:
          id:
            type: string
          data:
            type: image.effect.[%parent.id]
          weight:
            type: integer
          uuid:
            type: string

Это определяет метаданные для всех стилей изображения (image.style. *) Как отображение имен, меток, ключей эффектов. Тогда сами эффекты представляют собой последовательность (может быть любое количество эффектов), причем каждый элемент в списке является отображением с подробной информацией об эффекте. Ключ последовательности - это uuid эффекта, но это не имеет значения, последовательности не заботятся о своих ключах, поэтому мы определяем только тип элементов. Общими значениями для эффектов являются id, data и weight, однако содержимое данных зависит от значения id родителя (в приведенном выше примере «image_scale» - это имя используемого эффекта). Поэтому, когда эта схема применяется к данным, image.effect.image_scale является действительным ссылочным типом.

Обратите внимание, что вы также можете столкнуться с немного другим определением последовательности, где тип элементов последовательности определен как строго один список элементов. Этот формат устарел и будет удален в Drupal 9:

deprecated.sequence.definition.format:
  type: sequence
  sequence:
    - type: string
      label: 'DO NOT COPY, THIS IS DEPRECATED' 

Названия ваших файлов схем

Ваши файлы схемы должны иметь глобально уникальное имя. Если имя вашего файла схемы совпадает с именем другого расширения, ваш файл или другой файл не будет найден, что может привести к неясным ошибкам. Поэтому рекомендуется добавлять к файлам схемы префикс имени вашего модуля.

Стиль кода, используемый для файлов схемы

Просто следуйте стилю кода .yml, который применим в других местах ядра Drupal. Посмотрите вышеупомянутые примеры для подхода, которому нужно следовать. Ключевые моменты:

  • Включите комментарий верхнего уровня, объясняющий, что находится в файле. Если у вас есть только один файл схемы для всего вашего модуля, достаточно такого комментария: # Schema for the configuration files of the Contact module.
  • Избегайте комментариев, которые не дают дополнительной ясности. Такие как «Настройки комментариев» над разделом, определяющим схему для comment.settings, излишни. В любом случае элементы схемы должны иметь метки, которые должны хорошо их описывать. Добавляйте комментарии только при необходимости.
  • Не используйте двойные кавычки для строк, используйте одинарные кавычки.
  • Используйте одинарные кавычки для значений меток, даже если они представляют собой одно слово для согласованности.
  • Никогда не используйте кавычки для определений и типов ключей (в Drupal имена и типы ключей являются строками по определению и не должны иметь пробелов).
  • В Drupal целочисленные значения, содержащиеся в файлах данных конфигурации YAML, преобразуются в строку и поэтому заключаются в одинарные кавычки.
  • Добавьте метки как минимум к значениям, которые нужно будет перевести (а также к контейнерам, которые их обертывают). См. Инструмент инспектора конфигурации, подробно описанный ниже в разделе отладки, чтобы проверить, можно ли сгенерировать форму из вашей схемы полезным способом.
  • Следите за уровнем отступов. Это не требование стиля кода как таковое, поскольку важно использовать правильный отступ в YAML, чтобы получить желаемую структуру схемы.

Примечание. Обычный стиль файла данных конфигурации .yml требует, чтобы вы использовали только одинарные кавычки, когда используется более одного слова, потому что сериализация .yml сделает это в качестве стандартной практики, поэтому этот стандарт упрощает изменение конфигурации. См. Стандарты кодирования файла конфигурации. Однако приведенные выше рекомендации по схеме отличаются от таковых, поскольку файлы схемы всегда пишутся от руки, и для обеспечения согласованности всегда лучше использовать кавычки вокруг значений меток

PHP API #

Вы можете получить конфигурацию, связанную с метаданными, используя функцию \Drupal::service('config.typed') (например, для режима обслуживания системы):

$definition = \Drupal::service('config.typed')->getDefinition('system.maintenance');

Структура массива будет следующей:

array(5) {
  ["label"]=>
  string(16) "Maintenance mode"
  ["class"]=>
  string(34) "\Drupal\Core\Config\Schema\Mapping"
  ["definition_class"]=>
  string(40) "\Drupal\Core\TypedData\MapDataDefinition"
  ["mapping"]=>
  array(2) {
    ["langcode"]=>
    array(2) {
      ["type"]=>
      string(6) "string"
      ["label"]=>
      string(13) "Language code"
    }
    ["message"]=>
    array(2) {
      ["type"]=>
      string(4) "text"
      ["label"]=>
      string(43) "Message to display when in maintenance mode"
    }
  }
  ["type"]=>
  string(18) "system.maintenance"
}

Более сложный пример для получения типизированных данных, связанных с данными первого эффекта среднего изображения, как упомянуто выше в разделе родительских ссылок:

// Get typed configuration from under the the image.style.medium config 
// key's effects children. Take the uuid key shown above in the example config
// file (corresponding to the first effect in the style) and the data children's elements.
$effects = \Drupal::service('config.typed')->get('image.style.medium')->get('effects.bddf0d06-42f9-4c75-a700-a33cafa25ea0.data')->getDataDefinition();

Это приведет к типу image.effect.image_scale, как описано выше, и вернет определение карты, например:

object(Drupal\Core\TypedData\MapDataDefinition)#1061 (3) {
  ["mainPropertyName":protected]=>
  NULL
  ["propertyDefinitions":protected]=>
  NULL
  ["definition":protected]=>
  array(5) {
    ["type"]=>
    string(24) "image.effect.image_scale"
    ["label"]=>
    string(11) "Image scale"
    ["class"]=>
    string(34) "\Drupal\Core\Config\Schema\Mapping"
    ["definition_class"]=>
    string(40) "\Drupal\Core\TypedData\MapDataDefinition"
    ["mapping"]=>
    array(3) {
      ["width"]=>
      array(2) {
        ["type"]=>
        string(7) "integer"
        ["label"]=>
        string(5) "Width"
      }
      ["height"]=>
      array(2) {
        ["type"]=>
        string(7) "integer"
        ["label"]=>
        string(6) "Height"
      }
      ["upscale"]=>
      array(2) {
        ["type"]=>
        string(7) "boolean"
        ["label"]=>
        string(7) "Upscale"
      }
    }
  }
}

API TypedData можно полностью использовать для элементов. Такие как:

// Get the effects sequence object from the medium image style.
$effects = \Drupal::service('config.typed')->get('image.style.medium')->get('effects');
// $effects represents the sequence keyed by uuids as shown above in the parent reference
// example. Use the getValue() TypedData method to retrieve the value.
$first_uuid = key($effects->getValue());
// Take the data keys for this first effect.
$data = $effects->get($first_uuid)->get('data');
// Examine values and types for width.
$data->get('width')->getPluginId(); // will return 'integer'
$data->get('width')->getValue(); // will return 220 

См. Больше примеров кода для навигации по конфигурации на основе схемы, а также для генерации форм на основе схемы по адресу https://drupal.org/project/config_inspector

Отладка вашей схемы

Модуль инспектора конфигурации предоставляет пользовательский интерфейс для сравнения схем с данными и просмотра того, как генерация и преобразование форм (при их наличии) будут работать со схемой применительно к данным. Это можно использовать для поиска проблем в схеме, см. https://drupal.org/node/1910624#comment-7088154 для получения советов о том, как использовать это для отладки схем.

Основной модуль преобразования конфигурации создает реальный пользовательский интерфейс поверх схем и позволяет людям переводить конфигурацию. Вы можете использовать этот модуль для отладки, если ваша конфигурация корректно переводится и если переводы появляются в нужных местах (на переднем конце) и не появляются в некоторых местах (например, на заднем конце, где люди могут редактировать вашу исходную конфигурацию).

Еще больше справочной информации

Проверьте # 1866610: Представьте формат схемы, вдохновленный Kwalify для конфигурации, и # 1648930: Представьте схему конфигурации и используйте ее для перевода сотен, помимо сотен комментариев, где обсуждались различные подходы и возможности решения (и даже больше побочных проблем), прежде чем мы пришел в этот формат. (А также # 1914366: Переместите все файлы схемы конфигурации в подкаталог схемы, чтобы узнать, почему они находятся там, где они есть). См. Также # 1905152: Интеграция схемы конфигурации, поэтому поставленная конфигурация переведена для получения информации о том, как система схемы интегрируется с локальным модулем. # 1952394: Модуль ядра перевода конфигурации конфигурации в ядре - это то место, где был добавлен модуль перевода.

# 1602106: Документировать файлы конфигурации по умолчанию - это начало документирования обычных правил конфигурации yml.

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.