logo

Paleta - Deixe colorido🎨

Palette — Construtor visual de páginas. Não precisa ser designer.

Demonstração ao vivo Baixar Palette

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

Cada modulo pode ter quantas config entities precise; tudo explica-se em um ou mais arquivos schema que acompanham o modulo - os do modulo system ficam em core/modules/system/config/schema. A secao relevante de system.schema.yml segue:

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')). Niveis aninhados descrevem o conteudo do arquivo. O schema predefine dois tipos de arquivos: config_object para arquivos globais e config_entity para entidades. Тип 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

O tipo mapping e o tipo base para pares chave-valor. Com config_object a definicao do modo manutencao reutiliza as chaves langcode/_core e acrescenta outra chave para a mensagem. Возвращаясь к определению system.maintenance, метка схемы label:'Maintenance mode' описывает содержимое схемы. Затем фактические элементы перечислены под ключом сопоставления, где определен ключ сообщения, наследуя langcode и _core key от базового типа. Каждый элемент имеет тип и ключ метки, который соответственно описывает тип данных и дает описание данных. Метка обычно такая же или похожа на метку формы конфигурации, где значение может быть отредактировано системным администратором.

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

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

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

2. Tambem usamos schemas para gerar forms reais de traducao das settings com base nos seus dados. Nesse caso tipos ganham importancia crescente e labels tornam-se decisivos. O modulo core config translation usa schemas para construir forms de traducao e salvar traducoes. Os dois tipos tradutiveis embutidos mais importantes sao label (entrada de uma linha) e text (multiplas linhas).

3. Используя знания, встроенные в схемы конфигурации, о том, что хранится в объекте конфигурации, реализация персистентности по умолчанию для объектов конфигурации требует схемы конфигурации для объекта конфигурации, поэтому правильные свойства экспортируются с определенными типами. Embora fornecer schemas seja melhor, se realmente nao quiser implemente toArray() na sua entidade para dispensar schema ao salvar entidades do seu tipo.

4. Схема конфигурации также используется для автоматической привязки значений к ожидаемым типам. Isso garante que embora PHP e webforms prefiram strings a outros tipos os corretos usem-se ao salvar; importante para que ao fazer deploy o diff mostre apenas mudancas reais nao trocas casuais de tipo.

5. В PHPUnit все производные тесты TestBase обеспечивают строгое соблюдение схемы конфигурации по умолчанию. Erros de schema ocorreram faltando ou invalido o arquivo. Embora nao recomendado pode pular definindo no teste:

protected $strictConfigSchema = FALSE;

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

Ha outras ideias para schemas que modulos podem fornecer, ex.: criar interfaces de webservices sobre algumas. Provavelmente ha outros usos que as pessoas descobrirao que nem pensamos.

Свойства

  • 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'

Отображение, как показано выше, representa lista de pares chave-valor (array associativo/hash) onde cada item pode ter tipo diverso, enquanto Sequence e lista indexada simples onde itens sao de um unico tipo ou nome dinamico comum (veja abaixo) e chaves nao importam. Em palavras: nas sequences voce nao sabe nomes/quantidade das chaves enquanto nos mappings todas definem-se explicitamente. Sequences podem usar chaves string.

Todos os demais tipos em schemas (incluindo system.maintenance) apenas herdam outros - ex.: label/path/text/date_format/color_hex definem-se como strings ; a distincao ajuda parsers a identificar tipos textuais para fins diversos.

# 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 также помечены как переводимые. Это означает, что модуль перевода основного интерфейса идентифицирует элементы с этими типами и переводит их на основе предоставленных сообществом или администратором переводов из базы данных, создавая файлы переопределения перевода. Strings tradutiveis podem obter contexto pela chave translation context como aqui para formatos de data: strings como Y recebem contexto extra PHP date format sabendo tradutores que nao e abreviacao de Yes mas formato PHP de anos.

Do mesmo modo defina tipos complexos reutilizaveis sobre os basicos usando o formato descrito acima para o modo manutencao:

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

Isso da tipo mail reutilizavel para settings de email com subject/body na lista mapping. E o mesmo que definir schema para chave de configuracao mas nomeado fora de chave existente sem conflitar outras definicoes. На основании этого определения «почта» может использоваться как тип в другом месте (как это используется в схеме параметров электронной почты пользовательского модуля в 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'
  [....]

Por fim dois tipos complexos importantes para arquivos de configuracao tambem definem-se ali em 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 является действительным ссылочным типом.

Pode encontrar tambem definicao um pouco diferente de sequence com tipo dos itens estritamente lista unica - formato deprecated removido no 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.
  • Evite comentarios sem clareza extra - como Comment settings sobre a secao comment.settings e desnecessario. De qualquer forma itens devem ter labels que os descrevam bem. Comente so quando necessario.
  • Не используйте двойные кавычки для строк, используйте одинарные кавычки.
  • Используйте одинарные кавычки для значений меток, даже если они представляют собой одно слово для согласованности.
  • Nunca use aspas em definicoes/tipos de chaves (em Drupal nomes/tipos sao strings por definicao sem espacos).
  • Em Drupal inteiros em arquivos YAML convertem-se em string portanto entre aspas simples.
  • Добавьте метки как минимум к значениям, которые нужно будет перевести (а также к контейнерам, которые их обертывают). См. Инструмент инспектора конфигурации, подробно описанный ниже в разделе отладки, чтобы проверить, можно ли сгенерировать форму из вашей схемы полезным способом.
  • Atencao a indentacao: nao e requisito estetico mas indent correta importa no YAML para a estrutura desejada.

Примечание. Обычный стиль файла данных конфигурации .yml требует, чтобы вы использовали только одинарные кавычки, когда используется более одного слова, потому что сериализация .yml сделает это в качестве стандартной практики, поэтому этот стандарт упрощает изменение конфигурации. См. Стандарты кодирования файла конфигурации. Однако приведенные выше рекомеdacoes de schema diferem pois escrevem-se sempre a mao sendo melhor aspas em labels por consistencia

PHP API #

Obtenha configuracao com metadata via \Drupal::service('config.typed') (ex. modo manutencao):

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

A estrutura do array sera:

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"
}

Exemplo mais complexo obtendo typed data ligado aos dados do primeiro efeito do estilo medium conforme secao de referencias pai:

// 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"
      }
    }
  }
}

A TypedData API usa-se plenamente nos itens, ex.:

// 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 для получения советов о том, как использовать это для отладки схем.

O modulo core config translation cria UI real sobre os schemas permitindo traduzir configuracao; use-o para depurar se sua configuracao traduz-se corretamente e apareces lugares certos (front) e nao aparece noutros (ex. backend onde edita-se a origem).

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

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

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