¿Cómo modifico el título de un enlace de menú?

8

En mi sitio web, los usuarios pueden acumular algunos 'puntos' con el tiempo. Tengo un menú en la barra superior con algunos enlaces (por ejemplo, "inicio", "perfil", "cerrar sesión"). Quiero modificar el elemento de menú "perfil" y agregar los puntos de número que posee el usuario conectado actual.

Intenté varios ganchos, y casi logré obtener lo que quería hook_link_alter().

function mycustommodule_link_alter(&$variables) {
  if ($variables['text'] == "profile") {
    // Do some work.
    $variables['text'] = $variables['text'] . " (you have $nb_points points)";
  }
}

Limpié el caché (con drush cr), y el elemento del menú muestra el valor que quiero. Pero, si el valor cambia por alguna razón, muestra el valor anterior. Debo borrar el caché todas las veces para actualizar su valor.

¿Cómo puedo evitar limpiar el caché para actualizar el título del menú todas las veces que cambian los puntos obtenidos del usuario?

matthieu lopez
fuente
Parece que necesita un complemento personalizado para esto. Interesante pregunta. En general, debe evitar implementar cualquier gancho de la vieja escuela en D8. La pregunta es cómo modificar el título del menú mediante un complemento personalizado.
Codium
¿Tu menú está en un bloque? Si ese es el caso, quizás intente establecer el caché en 0 para ese bloque
pbonnefoi
Es un bloque creado desde la interfaz de administración. No tuve acceso a la configuración de caché :)
matthieu lopez
Le sugiero que comience con drupal.org/docs/8/api/menu-api , el '# caché' => ['max-age' => 0], no es una solución. necesita crear un enlace de menú dinámico.
Arnold PÉTER
"el elemento del menú muestra el valor que quiero" ¿Ha verificado el menú con otra cuenta de usuario? Sospecho que muestra la misma cantidad de puntos para todos los usuarios.
Ya.teck

Respuestas:

7

Sugiero implementar un complemento de enlace de menú personalizado. El siguiente código supone que el nombre de su módulo es un ejemplo .

<?php

namespace Drupal\example\Plugin\Menu;

use Drupal\Core\Database\Connection;
use Drupal\Core\Menu\MenuLinkDefault;
use Drupal\Core\Menu\StaticMenuLinkOverridesInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * A menu link that displays number of points.
 */
class ExampleMenuLink extends MenuLinkDefault {

  /**
   * The database connection.
   *
   * @var \Drupal\Core\Database\Connection
   */
  protected $dbConnection;

  /**
   * Constructs a new points menu link.
   *
   * @param array $configuration
   *   A configuration array containing information about the plugin instance.
   * @param string $plugin_id
   *   The plugin_id for the plugin instance.
   * @param mixed $plugin_definition
   *   The plugin implementation definition.
   * @param \Drupal\Core\Menu\StaticMenuLinkOverridesInterface $static_override
   *   The static override storage.
   * @param \Drupal\Core\Database\Connection $db_connection
   *   The database connection.
   */
  public function __construct(array $configuration, $plugin_id, $plugin_definition, StaticMenuLinkOverridesInterface $static_override, Connection $db_connection) {
    parent::__construct($configuration, $plugin_id, $plugin_definition, $static_override);
    $this->dbConnection = $db_connection;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
    return new static(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $container->get('menu_link.static.overrides'),
      $container->get('database')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getTitle() {
    $count = $this->dbConnection->query('SELECT COUNT(*) FROM {example_points}')->fetchField();
    return $this->t('You have (@count) points', ['@count' => $count]);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    // Invalidate these tags when number of points is changed.
    return ['example.points_count'];
  }

}

Si no desea inyectar el servicio de base de datos, la clase sería mucho más simple.

<?php

namespace Drupal\example\Plugin\Menu;

use Drupal\Core\Menu\MenuLinkDefault;
use Drupal\Core\Menu\StaticMenuLinkOverridesInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * A menu link that displays number of points.
 */
class ExampleMenuLink extends MenuLinkDefault {

  /**
   * {@inheritdoc}
   */
  public function getTitle() {
    $count = \Drupal::database()->query('SELECT COUNT(*) FROM {example_points}')->fetchField();
    return $this->t('You have (@count) points', ['@count' => $count]);
  }

  /**
   * {@inheritdoc}
   */
  public function getCacheTags() {
    // Invalidate these tags when number of points is changed.
    return ['example.points_count'];
  }

}

A continuación, debe colocar la definición del enlace en el archivo example.links.menu.yml .

example.user_points:
  route_name: <front>
  menu_name: main
  class: Drupal\example\Plugin\Menu\ExampleMenuLink
  weight: 30

El problema de almacenamiento en caché

Cada vez que se cambia el número de puntos, la caché de enlaces del menú debe invalidarse de la siguiente manera.

 \Drupal::service('cache_tags.invalidator')->invalidateTags(['example.points_count']);

Necesitas encontrar el lugar correcto para esto. Si los puntos gestionados por el módulo contribuido verifique la API del módulo y seleccione un gancho apropiado ( hook_points_insert () , hook_points_delete () y así sucesivamente).

Dado que la cantidad de puntos se calcula para cada cuenta de usuario individualmente, puede considerar usar etiquetas de caché por cuenta (algo así como ['example.points_count.' . $uid]). Por lo tanto, la memoria caché se conservará para los usuarios con puntos sin cambios.


Para generar código para el complemento de enlace de menú, utilicé Drupal Code Generator .

ya.teck
fuente
Esta respuesta es acertada (y más útil que la documentación oficial actual . Sin embargo, el archivo yaml debe llamarse example.links.menu.yml, no example.menu-links.yml . Después de eso, borre el caché y su elemento de menú debe aparecer.
Sut3kh
¿Es posible anular también el método getRouteParameters ()? Si no, ¿cómo se pueden alterar los route_parameters para que sean dinámicos? En mi caso, tengo {usuario} en el enrutamiento y el enlace del menú debe proporcionar la ID de usuario dinámicamente como ID de usuario del usuario actual.
Igal
@Igal piensa que es posible.
ya.teck
2

Me enfrenté al mismo problema. Los elementos del menú se almacenan en caché, por lo que siempre muestra el valor anterior hasta que borra la memoria caché. Una forma alternativa es usar hook_page_attachments(), adjuntar puntos a drupalSettings.YOUR_MODULE_OR_THEME.YOUR_VARIABLE, acceder a ellos en JavaScript y renderizar en el navegador.

La forma normal es deshabilitar el caché para las páginas cada vez que se muestra el menú "perfil" en el rendimiento del sitio.

adal
fuente
0

Inhabilite el caché para ese menú hook_preprocess_menu()estableciendo $variables['#cache']['max-age']en 0.

Roman Kuntyi
fuente