Comment implémentez-vous un fil d'Ariane?

18

J'ai essayé de définir un nouveau remplacement de fil d'Ariane, mais j'obtiens toujours le site par défaut.

J'ai créé un module personnalisé, foo_breadcrumb:

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

Voici le foo_breadcrumb.services.yml:

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

A l'intérieur src/BreadcrumbBuild.php, j'ai:

<?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;
    }
}
?>

J'ai commencé à travailler sur le seul document que je pouvais trouver sur le fil d'Ariane Drupal 8 , mais le problème est qu'il semble utiliser une ancienne version de l'autochargement PSR-4 qui n'est plus en place (pour mémoire, je suis sur 8.0.0 -dev-beta3), et donc je suis passé par la façon dont tous les autres modules fonctionnent dans la base de code.

Maintenant, je suis assez certain que cela est correct pour charger le module; mais je ne sais pas si

class BreadcrumbBuild extends BreadcrumbBuilderBase

est correct. Le problème est que l'ancien tutoriel que j'ai lié aux mentions s'étendait BreadcrumbBuilderBase, mais les documents les plus récents ne semblent pas le mentionner et je me demande s'il est obsolète - et comment je dois le faire.

De même, je ne comprends pas vraiment ce que fait le services.ymlfichier à cet égard, il n'y a aucune documentation pour cela.

njp
la source

Réponses:

8

Ouais le fil d'Ariane a changé et la documentation doit être mise à jour.

De même, je ne comprends pas vraiment ce que fait le fichier services.yml à cet égard, il n'y a aucune documentation pour cela.

Pour Drupal 8: le cours intensif | DrupalCon Amsterdam 2014 , présentation impressionnante, environ 47:02:

Drupal 8 en 2 étapes:

  1. Construire un outil
  2. Câbler

Le câblage peut varier, l'approche est la même.

Comment nous "câblons" le fil d'Ariane:

Pour http://www.palantir.net/blog/d8ftw-breadcrumbs-work :

Maintenant, nous devons parler au système de notre classe. Pour ce faire, nous définissons un nouveau service (vous vous en souvenez?) Référençant notre nouvelle classe. Nous le ferons dans notre fichier * .services.yml, qui existe exactement à cette fin

Semblable à un "info hook" dans les versions précédentes de Drupal, nous définissons un service nommé mymodule.breadcrumb. Ce sera un exemple de notre classe de fil d'Ariane. Si nécessaire, nous pourrions également transmettre des arguments au constructeur de notre classe. Mais surtout, nous étiquetons également le service. Les services balisés sont une caractéristique du composant Symfony DependencyInjection spécifiquement et indiquent au système de connecter automatiquement notre constructeur au gestionnaire de fil d'Ariane. La priorité spécifie dans quel ordre les différents constructeurs doivent être appelés, le plus élevé en premier. Dans le cas où deux méthodes apply () pourraient toutes deux renvoyer true, le générateur ayant la priorité la plus élevée sera utilisé et l'autre ignoré.

Vous pouvez utiliser ce code pour votre objectif:

Structure (peu importe):

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

N'oubliez pas, videz le cache à la fin.

rpayanm
la source
Pas de joie jusqu'ici. En fait, j'ai copié la taxonomie dans le noyau le plus près possible, car elle avait une implémentation fonctionnelle (je peux appeler dpm ('Test') à partir de la méthode apply () et elle sortira. Mais ce n'est pas le cas dans mon code; pas même des erreurs de syntaxe intentionnelles apparaît - ce qui me fait soupçonner que le routage du service n'est pas correct. Mais mon yaml est valide ... soupir :(
njp
1
@njp examine le chemin de votre classe Breadcrumb (j'ajoute un dossier Breadcrumb) et il doit correspondre au paramètre "class" de votre fichier de service. Trop vérifier tous les noms de classe, parfois ne correspond pas à certains fichiers ou paramètres.
rpayanm
1
Félicitations! Une seule question: avez-vous "vidé le cache" après les modifications? Peut-être que ça pourrait être ça.
rpayanm
1
Oui, vous devez vider le cache, cela devrait suffire pour mettre à jour les services. En outre, il convient de mentionner la priorité. Le premier générateur qui renvoie VRAI à partir de apply () va gagner, vous devrez donc peut-être rechercher d'autres services avec cette balise (qui est une recherche de texte facile) et vérifier leur poids et les implémentations apply ().
Berdir
1
@njp au contraire, la priorité spécifie dans quel ordre les différents constructeurs doivent être appelés, le plus élevé en premier. Dans le cas où deux méthodes apply () pourraient toutes deux renvoyer true, le générateur ayant la priorité la plus élevée sera utilisé et l'autre ignoré.
rpayanm
10

On y va encore une fois. Ces réponses sont généralement correctes. Une chose que vous ne pouvez pas oublier est les "balises de cache" et les "contextes de cache".

J'établissais un terme de taxonomie sur un nœud comme fil d'Ariane.

Je l'ai fait fonctionner avec les conseils de ce post, mais j'ai cliqué et j'ai remarqué les mêmes chapelures sur chaque page.

Pour faire court, assurez-vous de définir certains contextes de cache et balises.

Voici mon service dans un résumé: https://gist.github.com/jonpugh/ccaeb01e173abbc6c88f7a332d271e4a

Voici ma méthode 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;
}
Jon Pugh
la source
Ce problème de mise en cache m'a rendu fou et beaucoup d'informations en ligne dans les blogs, etc. semblent manquer ce point - merci!
kbrinner
8

Mise à jour 2016 Drupal 8

La documentation indique que vous devez renvoyer une instance de la classe de fil d'Ariane. Si vous avez du mal à le faire fonctionner. voici la solution qui a fonctionné pour moi.

<?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')
        ];
    }

}

Ensuite, le fichier yml

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

PS: si vous utilisez le bootstrap, allez sur votre /admin/appearance/settingspage de paramètres et regardez les paramètres du fil d'Ariane. Show 'Home' breadcrumb linkdoit être vérifié. Et Show current page title at enddevrait être cochée.

Après tout cela, videz votre cache. Chaque fois que vous modifiez un fichier YML, même en mode débogage, vous devez vider votre cache. vous pouvez y aller /core/rebuild.phpsi vous êtes coincé et ne pouvez pas reconstruire.

Neoaptt
la source
7

N'oubliez pas la mise en cache

Le cache de rendu a été modifié assez tard dans le cycle de développement D8, et il n'est donc pas mentionné dans la série d8ftw, ni dans les autres réponses à cette question.

La documentation de l'API Cache se réfère spécifiquement aux tableaux de rendu, mais toutes ces instructions s'appliquent également à Breadcrumbs. Les miettes de pain ont une toRenderable()méthode, Drupal essaiera de les mettre en cache dans le cache de rendu, et cela signifie que vous devez spécifier suffisamment d'informations pour permettre à Drupal de le faire correctement.

Les détails sont dans la documentation, mais la version courte est celle qui Breadcrumbimplémente le RefinableCachableDependencyInterface. Dans votre classe de générateur, vous souhaiterez appeler addCachableDependency()avec toutes les entités ou tous les objets de configuration utilisés pour créer le fil d'Ariane. La documentation de 'CacheableDependencyInterface & friends' explique plus en détail comment et pourquoi.

S'il existe d'autres contextes où le fil d'Ariane peut changer, vous devrez également utiliser manuellement addCacheContexts()pour vous assurer que le bloc varie, addCacheTags()pour vous assurer que l'entrée de cache peut être correctement invalidée, et mergeCacheMaxAge()si le cache est sensible au temps et doit expirer.

Si cela n'est pas fait correctement, l'un de vos services de création de fil d'Ariane personnalisé «gagnera» et le fil d'Ariane pour cette page spécifique sera servi sur chaque page, à tous les visiteurs, pour toujours.

Sean C.
la source
4

Il existe un autre moyen d'y parvenir.

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

Et puis créez un autre fichier dans le dossier de modèle de votre thème nommé "breadcrumb.html.twig" et mettez le code ci-dessous dans ce fichier:

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

C'est ça. Maintenant, videz le cache et vous obtiendrez le fil d'Ariane avec le titre de la page actuelle comme Accueil / Titre de la page actuelle. Vous pouvez changer le séparateur en remplaçant "/" par celui souhaité.

Sachin
la source
2

Vous devez utiliser un module contrib pour ajouter le titre de la page actuelle au fil d'Ariane tel que Current Page Crumb: https://www.drupal.org/project/current_page_crumb

Si vous souhaitez le coder manuellement, vous pouvez extraire le code du dossier src de ce module. Vous pouvez trouver plus de détails sur le fil d'Ariane Drupal 8 ici: http://www.gregboggs.com/drupal8-breadcrumbs/

Greg Boggs
la source
C'est tellement frustrant que quelque chose d'aussi simple que cela doive nécessiter la saisie de modules contrib pour l'ajouter.
Kevin
Telle est la voie Drupal. Bien que Drupal 8 fasse maintenant une TON dans le noyau que Drupal 7 n'a jamais fait. Je corrigerais le fil d'Ariane Drupal 8 de base si je pouvais. Mais ce drush en current_page_crumbn'est pas si mal.
Greg Boggs
0

J'avais utilisé un fil d'Ariane personnalisé en utilisant un jeton dans Drupal 7 et lorsque ce module n'était pas disponible pour Drupal 8, j'ai fini par créer des vues pour mes types de contenu individuels en utilisant les champs qui étaient à l'origine les champs du jeton. L'utiliser comme un bloc et désactiver le fil d'Ariane normal. C'était un peu plus de travail que le fil d'Ariane personnalisé, mais cela fonctionne.

weben
la source