¿Cómo se implementa una miga de pan?

18

Intenté definir una nueva anulación de la ruta de exploración, pero todavía obtengo el sitio predeterminado.

He creado un módulo personalizado, foo_breadcrumb:

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

Aquí está el foo_breadcrumb.services.yml:

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

En el interior src/BreadcrumbBuild.php, tengo:

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

Comencé a trabajar en la única escritura que pude encontrar en Drupal 8 breadcrumbs , pero la cuestión es que parece estar usando una versión anterior de la carga automática de PSR-4 que ya no está en su lugar (para el registro estoy en 8.0.0 -dev-beta3), y entonces analicé cómo funcionan todos los demás módulos en la base de código.

Ahora estoy bastante seguro de que esto es correcto para cargar el módulo; sin embargo no estoy seguro si

class BreadcrumbBuild extends BreadcrumbBuilderBase

es correcto. El problema es que el antiguo tutorial al que me vinculé menciona que se extiende BreadcrumbBuilderBase, pero los documentos más actuales no parecen mencionarlo y me pregunto si está desactualizado y cómo debería hacerlo.

Del mismo modo, realmente no entiendo lo services.ymlque está haciendo el archivo a este respecto, no hay documentación en este lugar.

njp
fuente

Respuestas:

8

Sí, la ruta de navegación cambió y la documentación debe actualizarse.

Del mismo modo, no entiendo realmente qué está haciendo el archivo services.yml a este respecto, no hay documentación en este lugar.

Para Drupal 8: The Crash Course | DrupalCon Amsterdam 2014 , presentación impresionante, aproximadamente 47:02:

Drupal 8 en 2 pasos:

  1. Construye una herramienta
  2. Conectarlo

El cableado puede variar, el enfoque es el mismo.

Cómo "conectamos" la miga de pan:

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

Ahora necesitamos decirle al sistema sobre nuestra clase. Para hacer eso, definimos un nuevo servicio (¿recuerdas esos?) Que hace referencia a nuestra nueva clase. Lo haremos en nuestro archivo * .services.yml, que existe exactamente para este propósito

Similar a un "enlace de información" en versiones anteriores de Drupal, estamos definiendo un servicio llamado mymodule.breadcrumb. Será una instancia de nuestra clase de migas de pan. Si es necesario, también podríamos pasar argumentos al constructor de nuestra clase. Es importante destacar que también etiquetamos el servicio. Los servicios etiquetados son una característica específica del componente Symfony DependencyInjection y le indican al sistema que conecte automáticamente nuestro constructor al administrador de migas de pan. La prioridad especifica en qué orden deben llamarse varios constructores, primero el más alto. En caso de que dos métodos apply () puedan volver verdadero, se usará el generador que tenga la prioridad más alta y el otro ignorado.

Puede usar este código para su objetivo:

Estructura (no importa mucho):

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

Recuerde, borre el caché al final.

rpayanm
fuente
No hay alegría hasta ahora. De hecho, copié la taxonomía en el núcleo lo más cerca posible, ya que tenía una implementación funcional (puedo llamar a dpm ('Test') desde el método apply () y saldrá. Pero no es así en mi código; ni siquiera errores de sintaxis intencionales aparece, lo que me hace sospechar que el enrutamiento del servicio no es correcto. Pero mi yaml es válido ... suspiro :(
njp
1
@njp revisa la ruta de su clase Breadcrumb (agrego una carpeta Breadcrumb) y debe coincidir con el parámetro "class" en su archivo de servicio. Demasiado comprobar todos los nombres de clase, a veces no coinciden en algunos archivos o parámetros.
rpayanm
1
Enhorabuena! Una pregunta: ¿"borró el caché" después de las modificaciones? Quizás podría ser eso.
rpayanm
1
Sí, debe borrar el caché, eso debería ser suficiente para actualizar los servicios. Además, uno que vale la pena mencionar es la prioridad. El primer constructor que devuelve VERDADERO desde aplica () va a ganar, por lo que es posible que deba buscar otros servicios con esa etiqueta (que es una búsqueda de texto fácil) y verificar su peso y las implementaciones de aplica ().
Berdir
1
@njp, por el contrario, la prioridad especifica en qué orden deben llamarse varios constructores, primero el más alto. En caso de que dos métodos apply () puedan volver verdadero, se usará el generador que tenga la prioridad más alta y el otro ignorado.
rpayanm
10

Aquí vamos de nuevo. Estas respuestas son en su mayoría correctas. Una cosa que no puede olvidar son las "etiquetas de caché" y los "contextos de caché".

Estaba configurando un término de taxonomía en un nodo como una ruta de exploración.

Lo hice funcionar con el consejo de esta publicación, pero luego hice clic y noté las mismas migas de pan en cada página.

En pocas palabras, asegúrese de establecer algunos contextos de caché y etiquetas.

Aquí está mi servicio en una esencia: https://gist.github.com/jonpugh/ccaeb01e173abbc6c88f7a332d271e4a

Aquí está mi método 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
fuente
Este problema de almacenamiento en caché me estaba volviendo loco y mucha de la información en línea en blogs, etc. parece perder este punto, ¡gracias!
kbrinner
8

Actualización 2016 Drupal 8

La documentación indica que debe devolver una instancia de la clase de ruta de exploración. Si tiene problemas para que funcione. Aquí está la solución que funcionó para mí.

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

}

Luego el archivo yml

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

PD: si está utilizando bootstrap, vaya a la /admin/appearance/settingspágina de configuración y mire la configuración de migas de pan. Show 'Home' breadcrumb linkdebe ser verificado Y Show current page title at enddebe ser marcado.

Después de todo esto, borre su caché. Cada vez que cambia un archivo YML, incluso en modo de depuración, necesita borrar su caché. puedes ir /core/rebuild.phpsi te quedas atascado y no puedes reconstruir.

Neoaptt
fuente
7

No olvides el almacenamiento en caché

El caché de renderizado se cambió bastante tarde en el ciclo de desarrollo de D8, por lo que no se menciona en la serie d8ftw ni en las otras respuestas a esta pregunta.

La documentación de la API de caché se refiere específicamente a las matrices de renderizado, pero todas esas instrucciones se aplican igualmente a Breadcrumbs. Las migas de pan tienen un toRenderable()método, Drupal intentará almacenarlas en la memoria caché de representación, y eso significa que debe especificar suficiente información para permitir que Drupal lo haga correctamente.

Los detalles están en los documentos, pero la versión corta es la que Breadcrumbimplementa el RefinableCachableDependencyInterface. En su clase de constructor, querrá llamar addCachableDependency()con todas y cada una de las entidades u objetos de configuración que se utilizan para construir la ruta de navegación. La documentación de 'CacheableDependencyInterface & friends' detalla cómo y por qué.

Si hay otros contextos en los que la ruta de exploración podría cambiar, también deberá usarla manualmente addCacheContexts()para asegurarse de que el bloque varía, addCacheTags()para asegurarse de que la entrada de la memoria caché se pueda invalidar correctamente y mergeCacheMaxAge()si la memoria caché es urgente y debe caducar.

Si esto no se hace correctamente, uno de sus servicios personalizados de creación de migas de pan 'ganará', y las migas de pan para esa página específica se servirán en cada página, a todos los visitantes, para siempre.

Sean C.
fuente
4

Hay otra forma de lograr esto.

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

Y luego cree otro archivo en la carpeta de plantillas de su tema llamado "breadcrumb.html.twig" y coloque el siguiente código en este archivo:

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

Eso es. Ahora vacíe el caché y obtendrá una ruta de exploración con el título de la página actual como Inicio / Título de la página actual. Puede cambiar el separador reemplazando "/" con el deseado.

Sachin
fuente
2

Debe usar un módulo contrib para agregar el título de la página actual a la ruta de exploración, como Migración de página actual: https://www.drupal.org/project/current_page_crumb

Si desea codificarlo manualmente, puede extraer el código de la carpeta src de ese módulo. Puede encontrar más detalles sobre las migas de pan Drupal 8 aquí: http://www.gregboggs.com/drupal8-breadcrumbs/

Greg Boggs
fuente
Es tan frustrante que algo tan simple como esto requiera tomar módulos contrib para agregarlo.
Kevin
Tal es el camino Drupal. Aunque Drupal 8 ahora hace un TON en el núcleo que Drupal 7 nunca hizo. Arreglaría las migas de pan Drupal 8 en core si pudiera. Pero, drush en current_page_crumbno es tan malo.
Greg Boggs
0

Había usado migas de pan personalizadas usando token en Drupal 7 y cuando ese módulo no estaba disponible para Drupal 8 terminé creando vistas para mis tipos de contenido individual usando los campos que originalmente eran los campos de token. Usándolo como un bloque e inhabilitando la ruta de exploración normal. Fue un poco más de trabajo que Custom Breadcrumbs pero funciona.

weben
fuente