您如何实现面包屑?


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文件在这方面的功能,对此没有文档。

Answers:


8

是的,面包屑已更改,并且文档必须更新。

同样,我不太了解services.yml文件在这方面的作用,对此没有任何文档。

对于Drupal 8:速成班| 阿姆斯特丹DrupalCon 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;
  }
}

请记住,最后清除缓存。


到目前为止没有喜悦。实际上,我尽可能地在内核中复制了分类法,因为这具有可行的实现(我可以从apply()方法调用dpm('Test')并将其输出。但是在我的代码中不是这样;甚至不是故意的语法错误)出现-这让我怀疑服务路由不正确。但是我的Yaml是有效的...叹气:(
njp 2015年

1
@njp查看您的面包屑类的路径(我添加了一个面包屑文件夹),并且该路径必须与您的服务文件上的“ class”参数匹配。太过检查类的所有名称,有时在某些文件或参数中不匹配。
rpayanm

1
恭喜你!一个问题:修改后您是否“清除了缓存”?也许就是这样。
rpayanm

1
是的,您需要清除缓存,这足以更新服务。另外,可能值得一提的是优先级。第一个从Apply()返回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;
}

这个缓存问题使我发疯,博客中的许多在线信息等都似乎遗漏了这一点-谢谢!
kbrinner

8

更新2016 Drupal 8

文档指出必须返回面包屑类的实例。如果您无法正常使用它。这是对我有用的解决方案。

<?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如果卡住并且无法重建,则可以转到。


7

不要忘记缓存

渲染缓存在D8开发周期的后期进行了更改,因此d8ftw系列或该问题的其他答案中未提及。

缓存API文档专指渲染阵列,但所有这些说明同样适用于面包屑。面包屑有一种toRenderable()方法,Drupal会尝试将它们缓存在渲染缓存中,这意味着您必须指定足够的信息以允许Drupal正确执行。

详细信息在docs中,但简短的版本Breadcrumb实现了RefinableCachableDependencyInterface。在您的构建器类中,您将需要调用addCachableDependency()用于构建面包屑的任何和所有实体或配置对象。 “ CacheableDependencyInterface和朋友”的文档详细介绍了如何以及为什么。

如果在其他情况下面包屑可能会发生变化,那么您还需要手动使用addCacheContexts()以确保块发生变化,addCacheTags()以确保可以正确使缓存条目无效,并且mergeCacheMaxAge()缓存是时间敏感的并且需要过期。

如果操作不正确,您的自定义“面包屑”构建器服务之一将“获胜”,并且该特定页面的面包屑将永远在所有页面上提供给所有访问者。


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 %}

而已。现在刷新缓存,您将获得带有当前页面标题(如“首页/当前页面标题”)的面包屑。您可以通过将分隔符“ /”替换为所需的分隔符来更改分隔符。


2

您应该使用contrib模块将当前页面标题添加到面包屑中,例如Current Page Crumb:https : //www.drupal.org/project/current_page_crumb

如果要手动编码,则可以从该模块的src文件夹中提取代码。您可以在此处找到有关Drupal 8面包屑的更多详细信息:http : //www.gregboggs.com/drupal8-breadcrumbs/


它是如此令人沮丧的东西那么简单,这有需要抓住的contrib模块,将其添加英寸
凯文-

这就是Drupal的方式。尽管Drupal 8现在在核心功能上达到了TON的水平,而Drupal 7却从未做到过。如果可以的话,我会修复核心的Drupal 8面包屑。但是,drush en current_page_crumb还不错。
格雷格·博格斯

0

我在Drupal 7中使用了使用令牌的Custom Breadcrumbs,而当该模块不适用于Drupal 8时,我最终使用最初是令牌字段的字段为我的单个内容类型创建了视图。将其用作一个块并禁用正常的面包屑。它比Custom Breadcrumbs还要多工作,但是可以工作。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.