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
Добавить комментарий