Как вы реализуете крошку?

18

Я попытался определить новое переопределение крошки, но я все еще получаю сайт по умолчанию.

Я создал собственный модуль, foo_breadcrumb:

   - modules/custom/foo_breadcrumb
     - foo_breadcrumb.info.yml
     - foo_breadcrumb.services.yml
     - src/
         - BreadcrumbBuild.php

Вот это foo_breadcrumb.services.yml:

services:
    foo_breadcrumb.breadcrumb:
        class: Drupal\foo_breadcrumb\BreadcrumbBuild
        tags:
            - { name: breadcrumb_builder, priority: 100 }

Внутри у src/BreadcrumbBuild.phpменя есть:

<?php

namespace Drupal\foo_breadcrumb;

use Drupal\Core\Breadcrumb\BreadcrumbBuilderBase;

class BreadcrumbBuild implements BreadcrumbManager {
    /**
     * {@inheritdoc}
     */
    public function applies(array $attributes) {
        return true;
    }

    /**
     * {@inheritdoc}
     */
    public function build(array $attributes) {
        $breadcrumb[] = $this->l($this->t('Test'), NULL);
        $breadcrumb[] = $this->l($this->t('Test2'), 'test');
        return $breadcrumb;
    }
}
?>

Я начал работать над единственной записью, которую я мог найти на хлебных крошках Drupal 8 , но дело в том, что она, похоже, использует более старую версию автозагрузки PSR-4, которой больше нет (для записи я на 8.0.0 -dev-beta3), и поэтому я понял, как работают все остальные модули в кодовой базе.

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

class BreadcrumbBuild extends BreadcrumbBuilderBase

правильно. Проблема в том, что в старом учебнике, на который я ссылался, упоминаются ссылки BreadcrumbBuilderBase, но более современные документы, похоже, не упоминают об этом, и мне интересно, устарел ли он - и как мне это сделать.

Кроме того, я не очень понимаю, что services.ymlфайл делает в этом отношении, нет документации для этого нигде.

NJP
источник

Ответы:

8

Да, крошка изменилась, и документация должна быть обновлена.

Кроме того, я не очень понимаю, что делает файл services.yml в этом отношении, для этого нет документации.

Для Drupal 8: ускоренный курс | DrupalCon Amsterdam 2014 , потрясающая презентация, около 47:02:

Drupal 8 в 2 этапа:

  1. Создать инструмент
  2. Подключите это

Схема подключения может отличаться, подход один и тот же.

Как мы «связываем это» с хлебными крошками:

Для http://www.palantir.net/blog/d8ftw-breadcrumbs-work :

Теперь нам нужно рассказать системе о нашем классе. Для этого мы определяем новый сервис (помните те?), Ссылающийся на наш новый класс. Мы сделаем это в нашем файле * .services.yml, который существует именно для этой цели.

Подобно «хуку информации» в предыдущих версиях Drupal, мы определяем сервис с именем mymodule.breadcrumb. Это будет экземпляр нашего класса хлебных крошек. При необходимости мы также можем передавать аргументы конструктору нашего класса. Важно отметить, что мы также помечаем сервис. Службы с тегами являются особенностью компонента Symfony DependencyInjection и сообщают системе о необходимости автоматического подключения нашего компоновщика к диспетчеру хлебных крошек. Приоритет указывает, в каком порядке должны быть названы различные сборщики, самый высокий в первую очередь. В случае, если два метода apply () могут оба возвращать true, какой из сборщиков имеет более высокий приоритет, будет использоваться, а другой игнорируется.

Вы можете использовать этот код для вашей цели:

Структура (не имеет большого значения):

- modules/custom/foo_breadcrumb
  - foo_breadcrumb.info.yml
  - foo_breadcrumb.services.yml
  - src/
    - Breadcrumb/
      - BlogBreadcrumbBuilder.php

foo_breadcrumb.services.yml:

services:
  foo_breadcrumb.breadcrumb_blog:
    class: Drupal\foo_breadcrumb\Breadcrumb\BlogBreadcrumbBuilder
    tags:
      - { name: breadcrumb_builder, priority: 100 }

BlogBreadcrumbBuilder.php:

class BlogBreadcrumbBuilder implements BreadcrumbBuilderInterface {
  use StringTranslationTrait;
  use LinkGeneratorTrait;

  /**
   * @inheritdoc
   */
  public function applies(RouteMatchInterface $route_match) {
    // This breadcrumb apply only for all articles
    $parameters = $route_match->getParameters()->all();
    if (isset($parameters['node'])) {
      return $parameters['node']->getType() == 'article';
    }
  }

  /**
   * @inheritdoc
   */
  public function build(RouteMatchInterface $route_match) {
    $breadcrumb = [Link::createFromRoute($this->t('Home'), '<front>')];
    $breadcrumb[] = Link::createFromRoute($this->t('Blog'), '<<<your route for blog>>>');
    return $breadcrumb;
  }
}

Помните, очистите кеш в конце.

rpayanm
источник
Пока радости нет. Я на самом деле скопировал таксономию в ядро ​​настолько близко, насколько это возможно, поскольку у него была рабочая реализация (я могу вызвать dpm ('Test') из метода apply (), и он выведет. Но в моем коде это не так, даже не намеренные синтаксические ошибки) появляются - что заставляет меня подозревать, что маршрутизация службы не является правильной. Но мой yaml действителен ... вздох :(
njp
1
@njp просмотрите путь вашего класса Breadcrumb (я добавляю папку Breadcrumb), и он должен совпадать с параметром "class" в вашем служебном файле. Слишком проверяйте все имена классов, иногда не совпадают в каком-либо файле или параметрах.
rpayanm
1
Поздравляем! Один вопрос: вы "очистили кеш" после модификаций? Возможно, это могло быть так.
rpayanm
1
Да, вам нужно очистить кеш, этого должно быть достаточно для обновления сервисов. Кроме того, тот, который, возможно, стоит упомянуть, является приоритетом. Первый компоновщик, который возвращает TRUE из apply (), победит, поэтому вам может понадобиться поискать другие сервисы с помощью этого тега (это простой текстовый поиск) и проверить их вес и применять () реализации.
Бердир
1
@njp, напротив, приоритет указывает, в каком порядке должны быть вызваны различные компоновщики, сначала самый высокий. В случае, если два метода apply () могут оба возвращать true, какой из сборщиков имеет более высокий приоритет, будет использоваться, а другой игнорируется.
rpayanm
10

Это снова мы. Эти ответы в основном правильные. Одна вещь, о которой вы не можете забыть, это «теги кеша» и «контексты кеша».

Я настраивал термин таксономии на узле как хлебная крошка.

Я работал с советами из этого поста, но потом я обошел все вокруг и заметил одинаковые хлебные крошки на каждой странице.

Короче говоря, не забудьте установить некоторые контексты и теги кеша.

Вот мой сервис в гисте: https://gist.github.com/jonpugh/ccaeb01e173abbc6c88f7a332d271e4a

Вот мой метод build ():

/**
 * {@inheritdoc}
 */
public function build(RouteMatchInterface $route_match) {
  $node = $route_match->getParameter('node');
  $breadcrumb = new Breadcrumb();

  // By setting a "cache context" to the "url", each requested URL gets it's own cache.
  // This way a single breadcrumb isn't cached for all pages on the site.
  $breadcrumb->addCacheContexts(["url"]);

  // By adding "cache tags" for this specific node, the cache is invalidated when the node is edited.
  $breadcrumb->addCacheTags(["node:{$node->nid->value}"]);

  // Add "Home" breadcrumb link.
  $breadcrumb->addLink(Link::createFromRoute($this->t('Home'), '<front>'));

  // Given we have a taxonomy term reference field named "field_section", and that field has data,
  // Add that term as a breadcrumb link.
  if (!empty($node->field_section->entity)) {
    $breadcrumb->addLink($node->field_section->entity->toLink());
  }
  return $breadcrumb;
}
Джон Пью
источник
Эта проблема с кешированием сводила меня с ума, и большая часть информации в Интернете в блогах и т. Д., Кажется, упускает этот момент - спасибо!
Кбриннер
8

Обновление 2016 Drupal 8

В документации говорится, что вы должны вернуть экземпляр класса breadcrumb. Если у вас возникли проблемы с тем, чтобы заставить его работать. вот решение, которое сработало для меня.

<?php

//modules/MY_MODULE/src/MyBreadcrumbBuilder.php

namespace Drupal\registration;

use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface;
use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Breadcrumb\Breadcrumb;
use Drupal\Core\Link;

class MyBreadcrumbBuilder implements BreadcrumbBuilderInterface {

    /**
     * @inheritdoc
     */
    public function applies(RouteMatchInterface $route_match) {
        /* Allways use this. Change this is another module needs to use a new custom breadcrumb */
        return true;
        /* This code allows for only the registration page to get used by this breadcrumb
         * $parameters = explode('.', $route_match->getRouteName());
         * if ($parameters[0] === 'registration') {
         *     return true;
         * } else {
         *     return false;
         * }
         */
    }

    /**
     * @inheritdoc
     */
    public function build(RouteMatchInterface $route_match) {
        $parameters = explode('.', $route_match->getRouteName());
        $b = new Breadcrumb();
        if ($parameters[0] === 'registration') {
            /* If registration page use these links */
            $b->setLinks($this->buildRegistration($parameters[1]));
        }
        return $b;
    }

    /**
     * Creates all the links for the registration breadcrumb
     * @param type $page
     * @return type
     */
    private function buildRegistration($page) {
        return [
            Link::createFromRoute(t('Step One'), 'registration.one'),
            Link::createFromRoute(t('Step Two'), 'registration.two'),
            Link::createFromRoute(t('Step Three'), 'registration.three'),
            Link::createFromRoute(t('Step Four'), 'registration.four'),
            Link::createFromRoute(t('Step Five'), 'registration.five'),
            Link::createFromRoute(t('Step Six'), 'registration.six'),
            Link::createFromRoute(t('Step Seven'), 'registration.seven')
        ];
    }

}

Тогда файл YML

# modules/MY_MODULE/registration/MY_MODULE.services.yml
services:
  registration.breadcrumb:
    class: Drupal\registration\MyBreadcrumbBuilder
    tags:
      - { name: breadcrumb_builder, priority: 100 }

PS: если вы используете загрузчик, перейдите на страницу /admin/appearance/settingsнастроек и посмотрите на настройки хлебных крошек. Show 'Home' breadcrumb linkдолжны быть проверены на. И Show current page title at endдолжно быть проверено.

После того, как все это сделано, очистите ваш кеш. Каждый раз, когда вы меняете файл YML, даже в режиме отладки, вам необходимо очистить кэш. Вы можете пойти, /core/rebuild.phpесли вы застряли и не можете восстановить.

Neoaptt
источник
7

Не забывайте кэширование

Кэш рендеринга был изменен довольно поздно в цикле разработки D8, и поэтому он не упоминается ни в серии d8ftw, ни в других ответах на этот вопрос.

Документация Cache API специально относится к массивам рендеринга, но все эти инструкции в равной степени применимы к хлебным крошкам. У хлебных крошек есть toRenderable()метод, Drupal будет пытаться их кешировать в кеше рендеринга, а это значит, что вы должны указать достаточно информации, чтобы позволить Drupal делать это правильно.

Подробности в документах, но короткая версия, которая Breadcrumbреализует RefinableCachableDependencyInterface. В вашем классе строителя вы захотите вызывать addCachableDependency()все сущности или объекты конфигурации, которые используются для построения хлебных крошек. Документация для 'CacheableDependencyInterface & friends' содержит более подробную информацию о том, как и почему.

Если есть другие контексты, в которых может измениться хлебная крошка, вам также нужно будет использовать вручную, addCacheContexts()чтобы убедиться, что блок меняется, addCacheTags()чтобы убедиться, что запись в кэше может быть правильно признана недействительной, и mergeCacheMaxAge()если кэш чувствителен ко времени и должен истекать.

Если это не будет сделано должным образом, один из ваших пользовательских сервисов Breadcrumb «выиграет», и хлебные крошки для этой конкретной страницы будут предоставлены на каждой странице всем посетителям навсегда.

Шон С.
источник
4

Есть еще один способ добиться этого.

/**
 * Implements hook_preprocess_breadcrumb().
 */
 function theme_name_preprocess_breadcrumb(&$variables){
  if(($node = \Drupal::routeMatch()->getParameter('node')) && $variables['breadcrumb']){
    $variables['breadcrumb'][] = array(
     'text' => $node->getTitle() 
   );
  }
}

А затем создайте другой файл в папке шаблонов вашей темы с именем «breadcrumb.html.twig» и поместите ниже код в этот файл:

{% if breadcrumb %}
  <nav class="breadcrumb" role="navigation" aria-labelledby="system-breadcrumb">
    <h2 id="system-breadcrumb" class="visually-hidden">{{ 'Breadcrumb'|t }}</h2>
    <ul>
    {% for item in breadcrumb %}
      <li>
        {% if item.url %}
          <a href="{{ item.url }}">{{ item.text }}</a>
        {% else %}
          {{ item.text }}
        {% endif %}
      </li> /
    {% endfor %}
    </ul>
  </nav>
{% endif %}

Это оно. Теперь очистите кеш, и вы получите крошку с заголовком текущей страницы, такой как Home / Current Page Title. Вы можете изменить разделитель, заменив "/" на нужный.

Сэчин
источник
2

Вы должны использовать модуль contrib, чтобы добавить заголовок текущей страницы в крошку, такой как Crumb текущей страницы: https://www.drupal.org/project/current_page_crumb

Если вы хотите написать код вручную, вы можете извлечь код из папки src этого модуля. Вы можете найти более подробную информацию о сухарях Drupal 8 здесь: http://www.gregboggs.com/drupal8-breadcrumbs/

Грег Боггс
источник
Это так расстраивает, что что-то столь простое, как это, должно требовать захвата модулей contrib, чтобы добавить это.
Кевин
Таков Друпал. Хотя Drupal 8 теперь делает TON в ядре, чего никогда не делал Drupal 7. Я бы починил основные крошки Drupal 8 в ядре, если бы мог. Но drush en current_page_crumbне все так плохо.
Грег Боггс
0

Я использовал Custom Breadcrumbs с использованием токена в Drupal 7, и когда этот модуль не был доступен для Drupal 8, я закончил тем, что создал представления для своих отдельных типов контента, используя поля, которые изначально были полями токена. Используя его как блок и отключив обычную хлебную крошку. Это было немного больше работы, чем Custom Breadcrumbs, но это работает.

Weben
источник