Block API в восьмёрке подверглось значительным изменениям и усложнениям. Теперь, помимо функционала в ядре, есть три модуля для работы с блоками:
- block — основа для программного создания блоков и вывода их на странице
- block_content — позволяет из админки управлять пользовательскими блоками, их типами и полями
- block_place (скрытый модуль) — расширенный интерфейс управления блоками в духе Panels
Если грубо, то система блоков держится на нескольких основных понятиях:
1. плагины, унаследованные от BlockBase,
2. конфигурационные сущности Block,
3. контент-сущности BlockContent.
Блок-плагины
В основе любого блока лежит его плагин. Плагин блока это класс, унаследованный от BlockBase
и содержащий аннотацию с базовой информацией о блоке (block definition). Класс отвечает за генерацию контента блока (не конечного рендеринга всего блока), контроль доступа, кэширование и работу с дополнительными настройками.
Пример простейшего блок-плагина, выводящего текущую дату:
// modules/mymodule/src/Plugin/Block/CurrentDateBlock.php
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
/**
* @Block(
* id = "mymodule_current_date",
* admin_label = @Translation("Current date")
* )
*/
class CurrentDateBlock extends BlockBase {
public function build() {
return ['#markup' => date('d.m.Y')];
}
}
Примеры системных блок-плагинов — PageTitleBlock (выводит текущий заголовок страницы), SystemBreadcrumbBlock (выводит хлебные крошки).
По умолчанию один класс с плагином реализует только один блок, однако с помощью механизма plugin derivatives один блок-плагин может реализовывать сколь угодно блоков. Пример такого поведения есть в плагине выводящем различные меню — SystemMenuBlock и его одноимённый derivative.
Конфигурационные сущности Block
Чтобы разместить блок, созданный с помощью блок-плагина на странице, нужно из админки (admin/structure/block
) добавить его в нужный регион, тем самым автоматически создав конфиг-сущность Block
. В этой сущности хранится заголовок блока, название региона, позиция в регионе, настройки видимости и другие опции, отвечающие за отображение. Конфиги блоков хранятся в таблице config
.
Пример конфига для вывода блока с системными сообщениями:
id: seven_messages
status: true
langcode: en
theme: seven
region: highlighted
weight: 0
provider: null
plugin: system_messages_block
settings:
id: system_messages_block
label: 'Status messages'
provider: system
label_display: '0'
visibility: { }
dependencies:
module:
- system
theme:
- seven
Контент-сущности BlockContent
Помимо программного создания блоков, блоки с текстовым контентом можно создавать из админки. Для этого существует упомянутый выше модуль block_content, который добавляет на сайт новую контент-сущность BlockContent
("пользовательский блок"). Эту сущность можно создать на странице block/add
. Данные таких блоков хранятся в одноимённой таблице block_content
. Пользовательские блоки, как и любые другие контент-сущности можно расширять своими полями (admin/structure/block/block-content/types
). За генерацию контента таких блоков отвечает блок-плагин BlockContentBlock
.
Процесс вывода блоков
Запрос
↓
Вызывается контроллер текущей страницы и генерится основное содержимое
↓
Основной контент страницы передаётся в HtmlRenderer::renderResponse()
, а внутри сразу в HtmlRenderer::prepare()
↓
В HtmlRenderer::prepare()
с помощью BlockPageVariant::build()
формируется рендер-массив страницы для последующего рендеринга page.html.twig
↓
В BlockPageVariant::build()
с помощью BlockRepository::getVisibleBlocksPerRegion()
получаются конфигурационные сущности Block
видимых блоков
↓
В BlockRepository::getVisibleBlocksPerRegion()
загружаются конфигурационные сущности Block
всех блоков темы и затем отфильтровываются видимые. Таким образом если в текущей теме суммарно выводятся например 100 блоков, то все 100 конфиг-сущности в определённый момент будут загружены в память, плюс 100 раз будет вызван метод Block::access()
.
↓
В BlockPageVariant::build()
для каждой конфиг-сущности видимого блока создаётся инстанс его плагина
↓
Для каждой конфиг-сущности блока вызывается BlockViewBuilder::view()
, который формирует рендер-массив блока с #lazy_builder
(контент блока ещё не сгенерирован)
↓
При рендеринге региона в page.html.twig
для каждого элемента в его рендер-массиве вызывается BlockViewBuilder::preRender()
↓
В BlockViewBuilder::preRender()
с помощью метода блок-плагина build()
генерится контент блока
↓
template_preprocess_block()
↓
block.html.twig
- Плагин блока, генерящий динамический контент с помощью #lazy_builder
- Тюнинг кэширования блоков с формой
- Как добавить настройки к блоку, созданному в стороннем модуле (8)
- Получить экземпляр класса BlockContent по машинному имени его конфига
- Third Party Settings — интерфейс хранения дополнительных настроек конфигурационных сущностей и плагинов
Комментарии
Пасибы, очень важная инфа
Скажите, если я создаю блок через настройку, я могу программное менять контент этого блока?
@Андрей hook_block_build_alter
Добавить комментарий