С 8й версии друпал предлагает механизм переопределения/задания хлебных крошек через реализацию сервиса breadcrumb_builder.
Немного теории
При создании хлебных крошек, Drupal вызывает объявленные сервисы в порядке их приоритетов, и опрашивает их, определяя кто будет наполняют бредкрамб ссылками.
Каждый из сервисов должен реализовывать интерфейс BreadcrumbBuilderInterface. У него всего два метода: applies и build, и оба получают объект, совместимый с RouteMatchInterface.
Первый (applies) служит для того, чтобы сигнализировать, что маршрут может быть обработан данным сервисом. Он возвращает boolean значение. Тот сервис (в порядке приоритетов), который вернет true, будет вызван далее через метод build.
Build должен создать и вернуть крошки в виде объекта Drupal\Core\Breadcrumb\Breadcrumb.
Чуть чуть практики
Когда стало ясно, как это работает, покажу пример из своей практики.
Мне нужно было вывести хлебные крошки (breadcrumbs), основанные на категории для страницы товара модуля Commerce. Т.к. категории могли быть вложенными, то требуется построить иерархический бредкрамб, включающий родительские страницы таксономии.
Реализацию я сделал в виде модуля, названного custom_blocks. Для модуля нужен описатель, файл custom_blocks.info.yml. Я разместил его в /modules/custom/custom_blocks:
1 2 3 4 |
name : 'Custom funcs' description : 'Provides custom functionality for the website.' core_version_requirement: ^9.5 || ^10 type: module |
Чтобы объявить ядру о наличии сервиса, его описание требуется добавить в файл custom_blocks.services.yml в том же каталоге модуля (/modules/custom/custom_blocks):
1 2 3 4 5 6 |
services: custom_blocks.breadcrumb: class: Drupal\custom_blocks\ProductBreadcrumbBuilder arguments: [] tags: - { name: breadcrumb_builder, priority: 10 } |
Теперь Drupal ожидает, что вы разместите реализацию BreadcrumbBuilderInterface в файле /modules/custom/custom_blocks/src/ProductBreadcrumbBuilder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
<?php namespace Drupal\custom_blocks; use Drupal\Core\Breadcrumb\Breadcrumb; use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Link; use Drupal\taxonomy\Entity\Term; // implements BreadcrumbBuilderInterface class ProductBreadcrumbBuilder implements BreadcrumbBuilderInterface { /** * {@inheritdoc} */ public function applies(RouteMatchInterface $route_match) { // нужно определить является ли страница commerce_product, // для это попробуем получить объект из маршрута $product = $route_match->getParameter('commerce_product'); // если удалось, то сигнализируем ядру, что маршрут может // быть обработан данным сервисом if ($product) { return TRUE; } // вернем ложь в противном случае return FALSE; } /** * {@inheritdoc} */ public function build(RouteMatchInterface $route_match) { $breadcrumb = new Breadcrumb(); $breadcrumb->addLink(Link::createFromRoute(t('Home'), '<front>')); $product = $route_match->getParameter('commerce_product'); // текущую категорию получим из поля field_categ $tids = []; $tid = $product->field_categ->target_id; // родительские категории мы получаем в обратном порядке, // потому я их не добавляю в breadcrumbs, а сохраняю в массиве while ($tid) { $category_term = Term::load($tid); array_push($tids, Link::createFromRoute( $category_term->name->value, 'entity.taxonomy_term.canonical', ['taxonomy_term' => $tid])); $tid = $category_term->parent->target_id; } // теперь добавим ссылки в нужном нам порядке while ($tids) { $breadcrumb->addLink(array_pop($tids)); } // добавим контекст кеширования хлебных крошек $breadcrumb->addCacheContexts(['route']); return $breadcrumb; } } |