Опубликовано Ivan Abramenko от Вт, 11/19/2019 - 10:42

В этом уроке мы разберем как выводить блоки программно через кастомный модуль в Drupal 8.

Примеры кода можно посмотреть на github:
https://github.com/levmyshkin/drupalbook8

Начнем с добавления файла содержащего PHP класс, именно так создаются блоки в Drupal 8 через кастомный модуль. Процесс создания файла такой же как и класса для страницы, как мы делали здесь:
12.3. Создаем кастомный Drupal 8 модуль. Вывод страницы программно.

Только нам нужно создать файл с plugin'ом:

modules/custom/drupalbook/src/Plugin/Block/FirstBlock.php

first block

Давайте скопируем этот код блока и потом разберем каждый из частей кода modules/custom/drupalbook/src/Plugin/Block/FirstBlock.php:

namespace Drupal\drupalbook\Plugin\Block;
 
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
 
/**
 * Provides a block with a simple text.
 *
 * @block(
 *   id = "drupalbook_first_block_block",
 *   admin_label = @block("My first block"),
 * )
 */
class FirstBlock extends BlockBase {
  /**
   * {@block}
   */
  public function build() {
    $config = $this->getConfiguration();
 
    if (!empty($config['drupalbook_first_block_settings'])) {
      $text = $this->t('Hello @Name in block!', ['@Name' => $config['drupalbook_first_block_settings']]);
    }
    else {
      $text = $this->t('Hello World in block!');
    }
 
    return [
      '#markup' => $text,
    ];
  }
 
  /**
   * {@block}
   */
  protected function blockAccess(AccountInterface $account) {
    return AccessResult::allowedIfHasPermission($account, 'access content');
  }
 
  /**
   * {@block}
   */
  public function blockForm($form, FormStateInterface $form_state) {
    $config = $this->getConfiguration();
 
    $form['drupalbook_first_block_settings'] = [
      '#type' => 'textfield',
      '#title' => $this->t('Name'),
      '#description' => $this->t('Who do you want to say hello to?'),
      '#default_value' => !empty($config['drupalbook_first_block_settings']) ? $config['drupalbook_first_block_settings'] : '',
    ];
 
    return $form;
  }
 
  /**
   * {@block}
   */
  public function blockSubmit($form, FormStateInterface $form_state) {
    $this->configuration['drupalbook_first_block_settings'] = $form_state->getValue('drupalbook_first_block_settings');
  }
}?>

Теперь нужно почистить кэш, чтобы наш блок подхватился друпалом и мы смогли бы его вывести.

Чтобы вывести блок, нужно теперь зайти в настройку блоков и добавить наш блок:

block layout

Выведем наш блок в регоине Left Sidebar или другой колонке, где вам будет удобно.

sidebar first

Начните набирать название вашего блока и друпал автоматически предложит вам выбрать ваш блок. Если вашего блока нет, то проверьте, что нужный код и лежит в нужном файле, а файл лежит в нужной папке и после этого не забудьте почистить кэш.

place block

Теперь когда наш блок вывелся, давайте разберемся как работает код для добавления блока:

my first block

В начале файла у нас идет namespace, для определения где должен быть наш файл плагина блока, чтобы друпал мог автоматически подключить его. Также мы подключаем классы из других файлов, используя use.

\drupalbook\Plugin\Block;
 
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;?>

Дальше в комментариях идет аннотация. Нам не нужно определять блок где-нибудь в YML-файлах, он будет автоматически подгружен друпалом с помощью аннатации.

/**
 * Provides a block with a simple text.
 *
 * @block(
 *   id = "drupalbook_first_block_block",
 *   admin_label = @block("My first block"),
 * )
 */?>

Здесь мы указываем @Block, что это будет плагин блока. id, admin_label будет автоматически подхватывается друпалом, поэтому id должен быть уникальным. @Translation помогает перевести потом label блока через админку друпала.

extends BlockBase {?>

Мы наследуемся от класса BlockBase, вы можете зажать ctrl и кликнуть на BlockBase в PhpStorm и посмотреть какие методы можно переопределить в нашем блоке, мы используем не все из них. Переопределять другие методы можно по мере необходимости.

Давайте разберем дальше методы класса в порядке от более понятному к менее понятному:

/**
 * {@block}
 */
protected function blockAccess(AccountInterface $account) {
  return AccessResult::allowedIfHasPermission($account, 'access content');
}
?>

Мы уже рассматривали доступ к странице в этой статье, в блоках мы можем использовать те же права доступа:

http://drupalbook.ru/drupal/126-rout-s-parametrom

Здесь мы используем тот же класс AccessResult.

/**
 * {@block}
 */
public function blockForm($form, FormStateInterface $form_state) {
  $config = $this->getConfiguration();
 
  $form['drupalbook_first_block_settings'] = [
    '#type' => 'textfield',
    '#title' => $this->t('Name'),
    '#description' => $this->t('Who do you want to say hello to?'),
    '#default_value' => !empty($config['drupalbook_first_block_settings']) ? $config['drupalbook_first_block_settings'] : '',
  ];
 
  return $form;
}?>

Мы можем использовать отдельную форму настройки блока для каждого блока, который мы создаем программно. Если вы зайдете в настройки блока:

configure block

Здесь вы можете увидеть наше поле Name, которое мы добавили в методе blockForm():

configure block

Мы используем Drupal Form API для создания полей для формы:

https://www.drupal.org/docs/8/api/form-api

https://api.drupal.org/api/drupal/elements/8.5.x

Мы еще будем разбирать Form API в дальнейшем подробно и сделаем мультстеп попап форму. Пока что вы можете посмотреть какие еще типы полей вы можете использовать с помощью Form API. Каждое поле добавляется с помощью массива. Попробуйте добавить еще полей в форму блока.

/**
 * {@block}
 */
public function blockSubmit($form, FormStateInterface $form_state) {
  $this->configuration['drupalbook_first_block_settings'] = $form_state->getValue('drupalbook_first_block_settings');
}?>

Здесь мы сохраняем значение полей с формы в конфигурацию друпала. Мы также будем рассматривать конфигурацию подробнее в следующих уроках, пока что вам достаточно понимать, что в друпал есть общее хранилище всех конфигураций и все модули используют это хранилище конфигов. Эти конфиги можно переносить с одного вашего сайта на другой. Например если вы изменили настройки блока на локальной копии сайта, то потом эти конфиги можно будет выгрузить и загрузить на живом сайте и ваши настройки блока применяться на живом сайте.

/**
 * {@block}
 */
public function build() {
  $config = $this->getConfiguration();
 
  if (!empty($config['drupalbook_first_block_settings'])) {
    $text = $this->t('Hello @Name in block!', ['@Name' => $config['drupalbook_first_block_settings']]);
  }
  else {
    $text = $this->t('Hello World in block!');
  }
 
  return [
    '#markup' => $text,
  ];
}
?>

И теперь основной метод build(), который выводит контент блока. В этом методе мы проверяем конфигурацию блока и если у нас есть Имя, то мы выводим текст с именем. Обратите внимание на метод $this->t(), он позволяет перевести текст через админку друпала на другие языки. Даже если вы делаете сайт на русском языке, то лучше всего все текст писать на английском, а потом обернуть текст в $this->t() и перевести через админку друпала. Также у нас используется placeholder @name, он нужен для того чтобы переводить только нужный текст, а не значения полей, которые мы вводим в конфигарационных формах. Это позволяет избегать множества строк перевода, например если не использовать placeholder, то для перевода в админке будут доступны все варианты текста, которые пройдут через $this->t():

Hello Josh ...
Hello Mike ...
Hello Ivan ...
и так далее.

На этом все я думаю вам стало понятно как выводить и настраивать кастомные блоки в Drupal 8, дальше мы будем рассматривать более сложные примеры с использованием блоков, страниц, форм.

Примеры кода можно посмотреть на github: 
https://github.com/levmyshkin/drupalbook8