Drupal → Анатомия блоков

20.11.2018

Block API в восьмёрке подверглось значительным изменениям и усложнениям. Теперь, помимо функционала в ядре, есть три модуля для работы с блоками:

  1. block — основа для программного создания блоков и вывода их на странице
  2. block_content — позволяет из админки управлять пользовательскими блоками, их типами и полями
  3. 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

Написанное актуально для
Drupal 8
Похожие записи

Комментарии

Андрей
25.07.2023, 20:05

Скажите, если я создаю блок через настройку, я могу программное менять контент этого блока?

Добавить комментарий