Cum se implementează un breadcrumb? (Drupal, 8, Breadcrumbs)

njp a intrebat.

Am încercat să definesc o nouă suprapunere a breadcrumb-ului, dar tot obțin valoarea implicită a site-ului.

Am creat un modul personalizat, foo_breadcrumb:

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

Aici este foo_breadcrumb.services.yml:

services:
    foo_breadcrumb.breadcrumb:
        class: Drupalfoo_breadcrumbBreadcrumbBuild
        tags:
            - { name: breadcrumb_builder, priority: 100 }

În interiorul src/BreadcrumbBuild.php, , am:

<?php

namespace Drupalfoo_breadcrumb;

use DrupalCoreBreadcrumbBreadcrumbBuilderBase;

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

Am început să lucrez de la singurul articol pe care l-am găsit despre breadcrumbs în Drupal 8, , dar chestia este că se pare că folosește o versiune mai veche a autoloading-ului PSR-4 care nu mai este în vigoare (ca să știți că sunt pe 8.0.0-dev-beta3), așa că am mers pe modul în care funcționează toate celelalte module din baza de cod.

Acum sunt destul de sigur că acest lucru este corect pentru ca modulul să se încarce; cu toate acestea, nu sunt sigur dacă

class BreadcrumbBuild extends BreadcrumbBuilderBase

este corectă. Problema este că vechiul tutorial la care am făcut legătura menționează extinderea de la BreadcrumbBuilderBase, , dar documentația mai actuală nu pare să menționeze acest lucru și mă întreb dacă este depășită – și cum ar trebui să fac acest lucru.

De asemenea, nu prea înțeleg ce înseamnă services.yml face în această privință, nu există nicăieri documentație în acest sens.

7 răspunsuri
rpayanm

Da breadcrumb schimbat și documentația trebuie să fie actualizată.

De asemenea, nu prea înțeleg ce face fișierul services.yml în această privință, nu există documentație nicăieri pentru acest lucru.

Pentru Drupal 8: Curs accelerat | DrupalCon Amsterdam 2014, , prezentare impresionantă, aproximativ 47:02:

Drupal 8 în 2 pași:

  1. Construiți un instrument
  2. Conectează-l

Cablarea poate varia, abordarea este aceeași.

Cum îl „cablăm” pe breadcrumb:

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

Acum trebuie să spunem sistemului despre clasa noastră. Pentru a face acest lucru, definim un nou serviciu (vă mai amintiți de acestea?) care face referire la noua noastră clasă. Vom face acest lucru în fișierul nostru *.services.yml, care există exact în acest scop

Similar cu un „cârlig de informare” din versiunile anterioare ale Drupal, definim un serviciu numit mymodule.breadcrumb. Acesta va fi o instanță a clasei noastre breadcrumb. Dacă este necesar, am putea trece și argumente la constructorul clasei noastre. Este important, însă, să etichetăm și serviciul. Serviciile etichetate sunt o caracteristică specifică a componentei Symfony DependencyInjection și spun sistemului să conecteze automat constructorul nostru la managerul breadcrumb. Prioritatea specifică în ce ordine ar trebui să fie chemați diverși constructori, cel mai mare mai întâi. În cazul în care două metode applies() ar putea returna amândouă true, va fi folosit constructorul care are prioritatea cea mai mare, iar celălalt va fi ignorat.

Puteți utiliza acest cod pentru scopul dumneavoastră:

Structură (nu contează prea mult):

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

Nu uitați, ștergeți memoria cache la sfârșit.

Comentarii

  • Nici o bucurie până acum. De fapt, am copiat taxonomia din core cât mai aproape posibil, deoarece aceasta avea o implementare funcțională (pot apela dpm(‘Test’) din metoda applies() și va ieși. Dar nu este așa în codul meu; nici măcar nu apar erori de sintaxă intenționate – ceea ce mă face să suspectez că rutarea serviciului nu este corectă. Dar yaml-ul meu este valid… sigh 🙁 –  > Por njp.
  • @njjp revedeți calea clasei Breadcrumb (eu adaug un folder Breadcrumb) și trebuie să se potrivească cu parametrul „class” din fișierul de serviciu. De asemenea, verificați toate numele clasei, uneori nu se potrivesc în unele fișiere sau parametri. –  > Por rpayanm.
  • Felicitări! O singură întrebare: ați „curățat memoria cache” după modificări? Poate că ar putea fi asta. –  > Por rpayanm.
  • Da, trebuie să ștergeți memoria cache, asta ar trebui să fie suficient pentru a actualiza serviciile. De asemenea, un lucru care ar putea fi demn de menționat este prioritatea. Primul constructor care returnează TRUE de la applies() va câștiga, așa că ar putea fi necesar să căutați alte servicii cu această etichetă (care este o căutare text ușoară) și să verificați implementările lor de weight și applies(). –  > Por Berdir.
  • @njp dimpotrivă, prioritatea specifică în ce ordine ar trebui să fie chemați diverși constructori, cel mai mare mai întâi. În cazul în care două metode applies() ar putea returna amândouă true, va fi utilizat constructorul care are prioritatea cea mai mare, iar celălalt va fi ignorat. –  > Por rpayanm.
Jon Pugh

O luăm de la capăt. Aceste răspunsuri sunt în mare parte corecte. Un lucru de care nu trebuie să uitați este „cache tags” și „cache contexts”.

Configuram un termen de taxonomie pe un nod ca breadcrumb.

Am reușit să o fac să funcționeze cu ajutorul sfaturilor din acest post, dar apoi am făcut clic și am observat aceleași breadcrumb-uri pe fiecare pagină.

Pe scurt, asigurați-vă că setați niște contexte și etichete cache.

Iată serviciul meu într-un gist: https://gist.github.com/jonpugh/ccaeb01e173abbc6c88f7a332d271e4a

Aici este metoda mea 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;
}

Comentarii

  • Această problemă de caching mă înnebunea și multe dintre informațiile online de pe bloguri etc. par să omită acest aspect – vă mulțumesc! –  > Por kbrinner.
Neoaptt

Actualizare 2016 Drupal 8

Documentația precizează că trebuie să returnați o instanță a clasei breadcrumb. Dacă aveți probleme în a o face să funcționeze. iată soluția care a funcționat pentru mine.

<?php

//modules/MY_MODULE/src/MyBreadcrumbBuilder.php

namespace Drupalregistration;

use DrupalCoreBreadcrumbBreadcrumbBuilderInterface;
use DrupalCoreRoutingRouteMatchInterface;
use DrupalCoreBreadcrumbBreadcrumb;
use DrupalCoreLink;

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

}

Apoi, fișierul yml

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

PS: dacă folosiți bootstrap mergeți la /admin/appearance/settings pagina de setări și uitați-vă la setările breadcrumbs. Show 'Home' breadcrumb link ar trebui să fie bifat pe. Și Show current page title at end ar trebui să fie bifate.

După ce ați făcut toate acestea, ștergeți memoria cache. De fiecare dată când modificați un fișier YML, chiar și în modul de depanare, trebuie să ștergeți memoria cache. puteți accesa /core/rebuild.php dacă vă blocați și nu puteți reconstrui.

Sean C.

Nu uitați de memoria cache

Cache-ul de randare a fost schimbat destul de târziu în ciclul de dezvoltare al D8 și, prin urmare, nu este menționat în seria d8ftw sau în celelalte răspunsuri la această întrebare.

Site-ul Documentația API Cache se referă în mod specific la matricele de randare, dar toate aceste instrucțiuni se aplică în egală măsură la Breadcrumbs. Breadcrumbs au un toRenderable() metodă, Drupal va încerca să le stocheze în memoria cache de randare, iar asta înseamnă că trebuie să trebuie să specificați suficiente informații pentru a permite lui Drupal să o facă în mod corespunzător.

Detaliile se găsesc în documente, dar versiunea scurtă este că Breadcrumb implementează metoda RefinableCachableDependencyInterface. În clasa dvs. de construire, veți dori să apelați addCachableDependency() cu oricare și toate entitățile sau obiectele de configurare care sunt folosite pentru a construi breadcrumb-ul. Documentația pentru ‘CacheableDependencyInterface & friends’ intră în mai multe detalii despre cum și de ce.

Dacă există alte contexte în care breadcrumb-ul s-ar putea schimba, va trebui, de asemenea, să utilizați manual addCacheContexts() pentru a vă asigura că blocul variază, addCacheTags() pentru a vă asigura că intrarea în memoria cache poate fi invalidată corect și mergeCacheMaxAge() dacă memoria cache este sensibilă la timp și trebuie să expire.

Dacă acest lucru nu este făcut în mod corespunzător, unul dintre serviciile dvs. personalizate de creare a firimiturilor de pâine va „câștiga”, iar firimiturile de pâine pentru acea pagină specifică vor fi servite pe fiecare pagină, pentru toți vizitatorii, pentru totdeauna.

Sachin

Există o altă modalitate de a realiza acest lucru.

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

Și apoi creați un alt fișier în folderul de șabloane al temei dvs. numit „breadcrumb.html.twig” și puneți codul de mai jos în acest fișier :

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

Asta este. Acum curățați memoria cache și veți obține breadcrumb cu titlul paginii curente, cum ar fi Home/Current Page Title. puteți schimba separatorul înlocuind „/” cu cel dorit.

Greg Boggs

Ar trebui să folosiți un modul contrib pentru a adăuga titlul paginii curente la breadcrumb, cum ar fi Current Page Crumb: https://www.drupal.org/project/current_page_crumb

Dacă ați dorit să codificați manual, puteți extrage codul din folderul src al acelui modul. Puteți găsi mai multe detalii despre breadcrumbs Drupal 8 aici: http://www.gregboggs.com/drupal8-breadcrumbs/

Comentarii

  • Este atât de frustrant faptul că ceva atât de simplu ca acesta trebuie să necesite să se apuce de module contrib pentru a-l adăuga. –  > Por Kevin.
  • Așa e în Drupal. Cu toate că Drupal 8 face acum o TONĂ în nucleu pe care Drupal 7 nu a făcut-o niciodată. Aș repara miezurile de pâine din Drupal 8 în nucleu dacă aș putea. Dar, drush en current_page_crumb nu este atât de rău. –  > Por Greg Boggs.
weben

Am folosit Custom Breadcrumbs folosind token în Drupal 7 și când acel modul nu a fost disponibil pentru Drupal 8 am ajuns să creez vizualizări pentru tipurile mele de conținut individual folosind câmpurile care erau inițial câmpuri token. Folosindu-l ca un bloc și dezactivând breadcrumb-ul normal. A fost un pic mai mult de muncă decât Breadcrumbs personalizat, dar funcționează.