Здесь подробно рассмотрим небольшую задачу для сайта под управлением CMS Drupal.
Требуется выводить поисковую форму для товаров в виде блока. Форма состоит всего из одного текстового поля, и должна искать товары по названию и аналогам. В поле будет использоваться авто-дополнение текста, показывая список, где можно выбрать товар. При выборе товара из списка, пользователь будет перенаправлен на страницу товара.
Компоненты задачи
Во-первых, у нас фигурирует форма, хоть и очень простая. Я буду реализовывать форму, расширяя класс Drupal\Core\Form\FormBase.
Далее — форма должна быть отображена в составе блока, поэтому я создам класс на базе Drupal\Core\Block\BlockBase.
Для формы нам требуется источник данных для списка авто-дополнения. Добавим маршрут и реализуем контроллер на базе Drupal\Core\Controller\ControllerBase.
Все эти компоненты я объединю в один модуль.
Файловая структура
Модуль, названный custom_blocks, хранит все нужные нам файлы, исключая только стили, которые мы рассматривать не будем. Стили размещены где то в /themes.
Форма
Для описания формы создадим класс ProductSearch с id ‘product_search‘ в файлe /src/Form/ProductSearch.php, как того требует стандарт PSR-4.
Блок
Блок SearchGoodsBlock реализуем в файле /src/Plugin/Block/SearchGoodsBlock.php. Ему потребуется собственный шаблон /templates/search-form-for-goods.html.twig, который в свою очередь будет использовать библиотеку /libs/product-search-autocomplete.js, где я добавлю переход на страницу товара при выборе элемента списка.
Контроллер
Контроллер с длинным названием
/src/Controller/ProductSearchAutoCompleteController.php
будет обслуживать список авто-дополнения (‘#autocomplete_route_name’) формы, возвращая список товаров как пару значений value: label. В value я запишу url страницы товара.
Модуль
YML файлы и файл модуля custom_blocks.module настраивают описанные компоненты.
custom_blocks.info.yml — описатель модуля: название, версия ядра и пара зависимостей — вот и всё что там указано.
1 2 3 4 5 6 7 8 9 |
name : 'Custom website blocks' description : 'Provides a set of custom blocks for website.' core_version_requirement: ^9.5 || ^10 type: module dependencies: - drupal:block - drupal:config |
custom_blocks.libraries.yml — здесь описан js файл, который мы подключим в шаблоне блока.
1 2 3 4 5 6 |
product-search-autocomplete: version: VERSION js: libs/product-search-autocomplete.js: { } dependencies: - core/jquery |
custom_blocks.routing.yml — объявляет endpoints и связывает их с контроллерами. У нас тут всего один маршрут.
1 2 3 4 5 6 7 |
custom_blocks.autocomplete.product_search: path: '/custom_blocks/autocomplete/product_search' defaults: _controller: '\Drupal\custom_blocks\Controller\ProductSearchAutoCompleteController::handleAutocomplete' _format: json requirements: _permission: 'access content' |
custom_blocks.module — реализует hook_theme, чтобы объявить шаблон для отрисовки блока.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
<?php /** * @file */ /** * Implements hook_theme(). */ function custom_blocks_theme($existing, $type, $theme, $path) { return [ 'search_form_for_goods' => [ 'variables' => ['title' => NULL, 'subtitle' => NULL, 'product_search_form' => NULL], ], ]; } |
Программный вывод блока
Все компоненты готовы, теперь выведем блок.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
$block_manager = \Drupal::service('plugin.manager.block'); // заголовок и подзаголовок передаём в виде конфигурации блока $config = [ 'title' => 'Enter filter name', 'subtitle' => 'We will offer you a compatible sample from our range.', ]; $plugin_block = $block_manager->createInstance('search_goods_block', $config); $access_result = $plugin_block->access(\Drupal::currentUser()); if (is_object($access_result) && $access_result->isForbidden() || is_bool($access_result) && !$access_result) { $html = ''; } else { $html = $plugin_block->build(); } // готовый блок можно далее передать в шаблон $vars['goods_search'] = $html; |