Расширенные возможности чертежей⚓︎
В чертежах есть расширенные функции, которые позволяют расширять их и иметь динамические поля.
Определение правил проверки⚓︎
Если вам нужны одни и те же правила проверки несколько раз, вы можете создать для них свое собственное правило.
rules:
slug:
pattern: "[a-z][a-z0-9_\-]+"
min: 2
max: 80
form:
fields:
folder:
type: text
label: Folder Name
validate:
rule: slug
В приведенном выше примере создается правило slug, которое затем используется в поле папки формы.
Расширение базового типа (extends@)⚓︎
Вы можете расширить существующий чертёж, что позволяет добавлять новые поля, а также изменять существующие в базовом чертеже.
В расширенном формате вы можете указать контекст поиска для вашего базового файла:
Вы также можете расширить сам проект, если существует несколько версий одного и того же чертежа.
Нет ограничений на количество чертежей, которые вы можете расширить. Поля, определённые в первом чертеже, будут заменены любыми более поздними чертежами в списке.
Понимание свойств типа и контекста⚓︎
В приведенных выше примерах type ссылается на файл, а context — на путь. Свойство context использует Потоки, что означает, что оно разрешается в физическое местоположение.
context: blueprints:// по умолчанию будет давать /user/plugins/admin/blueprints, папку чертежей администратора. type: default при поиске файлов даст default.yaml. Поскольку эти два свойства используются вместе, они дают полный путь, понятный Grav: /user/plugins/admin/blueprints/default.yaml.
Всякий раз, когда вы видите в этих документах синтаксис ://, вы можете быть уверены, что он относится к потоку. И при использовании context этот поток должен разрешаться в существующую папку для работы.
Форма встраивания (import@)⚓︎
Иногда вам может потребоваться совместное использование некоторых полей или подформ между несколькими формами.
Создадим blueprints://partials/gallery.yaml, который мы хотим встроить в нашу форму:
В нашей форме есть раздел, в который мы хотели бы вставить изображения галереи:
form:
fields:
images:
type: section
title: Images
underline: true
import@:
type: partials/gallery
context: blueprints://
Хотя YAML не позволяет использовать один и тот же ключ import@ несколько раз, вы все равно можете импортировать несколько чертежей, добавив уникальный номер после @, например import@1,import@2 и так далее. Число не имеет другого значения, кроме предотвращения ошибок парсера YAML:
form:
fields:
images:
type: section
title: Images
underline: true
import@1:
type: partials/gallery
context: blueprints://
import@2:
type: partials/another-gallery
context: blueprints://
По умолчанию blueprints:// разрешается в /user/plugins/admin/blueprints/, поэтому обратите внимание: если вы работаете в контексте темы (theme), вам нужно будет скорректировать контекст в операторе импорта:
form:
fields:
images:
type: section
title: Images
underline: true
import@:
type: partials/gallery
context: theme://blueprints
Удаление полей / свойств (unset-*@)⚓︎
Если вы хотите удалить поле, вы можете добавить в него unset@: true. Если вы хотите удалить свойство поля, вы просто добавляете имя свойства, например: unset-options@ удаляет все параметры.
Замена полей / свойств (replace-*@)⚓︎
По умолчанию в чертежах используется глубокое объединение свойств. Иногда вместо объединения содержимого поля вы хотите начать с чистой таблицы. Если вы хотите заменить все поле, ваше новое поле должно начинаться с replace@:
В результате author.name будет иметь только два свойства:type и label независимо от того, что форма имела раньше. Вы можете сделать то же самое для отдельных свойств:
Примечание: replace-*@ является псевдонимом для unset-*@.
Использование конфигурации (config-*@)⚓︎
Бывают случаи, когда вы можете захотеть получить значение по умолчанию из конфигурации Grav. Например, вы можете захотеть, чтобы в поле автора по умолчанию был указан автор сайта:
Если имя автора вашего сайта - John Doe, форма эквивалентна:
Вы можете использовать config-*@ для любого поля; например, если вы хотите изменить поле type, вы можете просто иметь config-type @: site.forms.author.type, чтобы вы могли изменить тип поля ввода из вашей конфигурации.
Использование вызовов функций (data-*@)⚓︎
Вы можете выполнять вызовы функций с параметрами из ваших чертежей, чтобы динамически получать значение для любого свойства в вашем поле. Вы можете сделать это, используя нотацию data-*@: в качестве ключа, где * - это имя поля, которое вы хотите заполнить результатом вызова функции.
Например, мы редактируем страницу и хотим иметь поле, которое позволяет нам изменить её родительский элемент или, другими словами, переместить страницу в другое место. Для этого нам нужно значение по умолчанию, указывающее на текущее местоположение, а также список опций, который состоит из всех возможных местоположений. Для этого нам нужен способ спросить у Grav
form:
fields:
route:
type: select
label: Parent
classes: fancy
data-default@: '\Grav\Plugin\Admin::route'
data-options@: '\Grav\Common\Page\Pages::parentsRawRoutes'
options:
'/': '- Root -'
Если бы вы редактировали страницу члена команды, результирующая форма выглядела бы примерно так:
form:
fields:
route:
type: select
label: Parent
classes: fancy
default: /team
options:
'/': '- Root -'
'/home': 'Home'
'/team': 'Team'
'/team/ceo': ' Meet Our CEO'
...
Хотя data-default@: и data-options@:, вероятно, являются наиболее часто используемыми свойствами динамических полей, вы не ограничены ими. Нет никаких ограничений на то, какие свойства вы можете получить, включая type, label, validate и даже fields в текущем поле.
Кроме того, вы можете передавать параметры в вызов функции, просто используя массив, где первое значение — это имя функции, а параметры следуют:
Регистрация пользовательских поставщиков данных (Grav 2.0)⚓︎
Начиная с Grav 2.0.11, вызываемые объекты Class::method, используемые в директивах data-*@, проверяются на соответствие списку разрешённых поставщиков данных. Собственные поставщики ядра Grav (например, \Grav\Common\Page\Pages::pageTypes и \Grav\Common\Utils::timezones) уже разрешены, но пользовательский поставщик в вашем плагине или теме необходимо зарегистрировать до того, как Grav сможет его вызвать. Это особенно важно в Admin 2.0, который получает динамические варианты через API-эндпойнт Resolve Data: незарегистрированный вызываемый объект отклоняется с ошибкой Callable '...' is not an approved data provider.*
Чтобы зарегистрировать своего поставщика, вызовите Blueprint::addAllowedDynamicCallable() один раз при запуске. В теме естественным местом для этого является onThemeInitialized:
<?php
namespace Grav\Theme;
use Grav\Common\Data\Blueprint;
use Grav\Common\Theme;
class MyTheme extends Theme
{
public static function getSubscribedEvents(): array
{
return [
'onThemeInitialized' => ['onThemeInitialized', 0],
];
}
public function onThemeInitialized(): void
{
Blueprint::addAllowedDynamicCallable('Grav\Theme\MyTheme\Utils::getIcons');
}
}
В плагине сделайте то же самое в обработчике onPluginsInitialized. После регистрации вызываемый объект будет работать везде, где на него может ссылаться директива data-*@: в чертежах, обрабатываемых на стороне сервера, и через поля select в Admin 2.0, которые получают свои варианты через API.
Список разрешённых вызываемых объектов применяется только к вызываемым объектам, имена которых поступают из ненадёжных источников, например из формы, определённой в блоке метаданных страницы, или из вызываемого объекта, переданного в API в качестве параметра запроса. Файлы чертежей, поставляемые вместе с плагином или темой, считаются доверенными при серверном рендеринге на фронтенде, однако для разрешения такого вызываемого объекта в Admin его всё равно необходимо зарегистрировать, поэтому пользовательские поставщики всегда следует регистрировать.
Класс поставщика также должен быть доступен через автозагрузку в момент разрешения вызываемого объекта, иначе API вернёт Callable '...' not found. Admin 2.0 разрешает данные чертежа через фронтенд-конвейер /api сайта, где isAdmin() всегда имеет значение false, поэтому загрузка или регистрация класса, обёрнутая в условие только для Admin, там никогда не выполняется. Обеспечьте для своей темы или плагина корректную автозагрузку PSR-4 (с composer.json, содержащим секцию autoload, и методом autoload() в основном классе, который возвращает require __DIR__ . '/vendor/autoload.php';), и никогда не ограничивайте настройку, связанную с чертежом, условием isAdmin().
Изменение порядка полей⚓︎
Когда вы расширяете план или импортируете файл, по умолчанию новые поля добавляются в конец списка. Иногда это не то, что вы хотите сделать, вы можете добавить элемент в качестве первого или после какого-либо существующего поля.
Если вы хотите создать поле, вы можете указать его порядок, используя свойство ordering@. Это поле может содержать имя поля или целое число (-1 = первый элемент).
Вот пример:
form:
fields:
route:
ordering@: -1
type: select
label: Parent
classes: fancy
default: /team
options:
'/': '- Root -'
'/home': 'Home'
'/team': 'Team'
'/team/ceo': ' Meet Our CEO'
...
Это гарантирует, что поле маршрута будет первым полем, которое появится в форме. Это упрощает импорт и / или расширение существующего поля и размещение дополнительных полей там, где вы хотели бы их разместить.
Вот ещё один пример:
В приведенном выше примере мы использовали имя другого поля, чтобы установить порядок. В этом примере мы настроили его так, чтобы поле author отображалось после поля title в форме.
При упорядочивании полей в чертеже страницы вам всё равно нужно ссылаться на имена полей с префиксом header, например: header.title, чтобы упорядочение работало.
Создание нового типа поля формы⚓︎
Если вы создаете специальный тип поля формы, который требует особой обработки в чертежах элементов, вы можете использовать функцию плагина.
<?php
/**
* Get list of form field types specified in this plugin. Only special types needs to be listed.
*
* @return array
*/
public function getFormFieldTypes()
{
return [
'display' => [
'input@' => false
],
'spacer' => [
'input@' => false
]
];
}
Вам не нужно регистрировать эту функцию, поскольку на самом деле это не событие, но запускается при создании объекта плагина. Цель этой функции - дать дополнительные инструкции, как обрабатывать поле, например, приведенный выше код делает типы отображения и разделителя виртуальными, что означает, что они не будут существовать в реальных данных.
Вы можете добавить любые пары ключ: значение, включая динамические свойства, такие как data-options@, которые будут автоматически добавляться к полям.
Переопределение или расширение чертежа плагина⚓︎
Иногда требуется изменить чертёж, предоставляемый плагином: добавить, переместить или удалить поля. Это не делается «из коробки», потому что чертёж плагина содержит не только свойство form и по умолчанию не объявлен как расширяемый. Тем не менее, при разработке плагинов рекомендуется сделать это возможным для пользовательских чертежей.
- Во-первых, плагин должен объявить поддержку чертежей, добавив публичное свойство в свой PHP-файл:
public $features = ['blueprints' => 10]; - Во-вторых, плагин должен импортировать поля формы через
import@из отдельного файла, например:
form:
validation: strict
fields:
tabs:
type: tabs
active: 1
fields:
import@:
type: options
context: blueprints://plugins/yourpluginname
Это импортирует файл user/plugins/yourpluginname/blueprints/plugins/yourpluginname/options.yaml.
- В-третьих, в этом файле должны быть объявлены стандартные части формы:
form:
options:
type: tab
title: PLUGIN_ADMIN.OPTIONS
fields:
enabled:
type: toggle
label: PLUGIN_ADMIN.PLUGIN_STATUS
default: 1
options:
1: PLUGIN_ADMIN.ENABLED
0: PLUGIN_ADMIN.DISABLED
validate:
type: bool
Параметры context и type должны быть именно в таком виде, чтобы избежать возможных конфликтов имён файлов и сделать их легко узнаваемыми — поэтому и используется кажущийся избыточно длинным путь выше.
Пользователь затем может внести свои изменения в файл user/blueprints/plugins/yourpluginname/options.yaml:
И эти изменения автоматически подхватятся на странице настроек плагина.
onBlueprintCreated или доступ к данным чертежа⚓︎
Поскольку чертежи состоят из полей с точками, при получении вложенного поля из чертежа используется нотация / вместо нотации ..
Это позволяет получить доступ к специальным полям данных, например:
<?php
$name = $blueprint->get('form/fields/content.name');
$name = $blueprint->get('form/fields/content/fields/.name');
Для обратной совместимости вы можете указать разделитель в последнем (третьем) параметре set() и get().