Wie ändere ich den Titel eines Menü-Links?

8

Auf meiner Website können Benutzer im Laufe der Zeit einige "Punkte" sammeln. Ich habe ein Menü in der oberen Leiste mit einigen Links (z. B. "home", "profile", "logout"). Ich möchte den Menüpunkt "Profil" ändern und die Anzahl der Punkte hinzufügen, die dem aktuell verbundenen Benutzer gehören.

Ich habe mehrere Haken ausprobiert und es ist mir fast gelungen, das zu bekommen, was ich wollte hook_link_alter().

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

Ich habe den Cache (mit drush cr) geleert und der Menüpunkt zeigt den gewünschten Wert an. Wenn sich der Wert jedoch aus irgendeinem Grund ändert, wird der alte Wert angezeigt. Ich muss den Cache ständig leeren, um seinen Wert zu aktualisieren.

Wie kann ich vermeiden, den Cache zu bereinigen, um den Menütitel zu aktualisieren, wenn sich die vom Benutzer erzielten Punkte ändern?

matthieu lopez
quelle
Es hört sich so an, als ob Sie dafür ein benutzerdefiniertes Plugin benötigen. Interessante Frage. Im Allgemeinen sollten Sie vermeiden, Old-School-Hooks in D8 zu implementieren. Die Frage ist, wie man den Menütitel über ein benutzerdefiniertes Plugin ändert.
Codium
Ist Ihr Menü in einem Block? Wenn dies der Fall ist, versuchen Sie vielleicht, den Cache für diesen Block auf 0 zu setzen
pbonnefoi
Es ist ein Block, der über die Administrationsoberfläche erstellt wurde. Ich habe nicht auf die Cache-Konfiguration
zugegriffen
Ich schlage vor, Sie beginnen mit drupal.org/docs/8/api/menu-api , der '#cache' => ['max-age' => 0] ist keine Lösung. Sie müssen einen dynamischen Menülink erstellen.
Arnold PÉTER
"Der Menüpunkt zeigt den gewünschten Wert an." Haben Sie das Menü mit einem anderen Benutzerkonto überprüft? Ich vermute, es zeigt für alle Benutzer die gleiche Anzahl von Punkten.
ya.teck

Antworten:

7

Ich schlage vor, ein benutzerdefiniertes Menü-Link-Plugin zu implementieren. Der folgende Code setzt voraus, dass Ihr Modulname ein Beispiel ist .

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

}

Wenn Sie den Datenbankdienst nicht einfügen möchten, wird die Klasse viel einfacher.

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

}

Als nächstes müssen Sie die Linkdefinition in die Datei example.links.menu.yml einfügen.

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

Das Caching-Problem

Immer wenn die Anzahl der Punkte geändert wird, sollte der Menü-Link-Cache wie folgt ungültig gemacht werden.

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

Sie müssen den richtigen Ort dafür finden. Wenn die vom beitragenden Modul verwalteten Punkte die Modul-API überprüfen und einen geeigneten Hook ( hook_points_insert () , hook_points_delete () usw.) auswählen .

Da die Anzahl der Punkte für jedes Benutzerkonto einzeln berechnet wird, können Sie die Verwendung von Cache-Tags pro Konto in Betracht ziehen (etwa ['example.points_count.' . $uid]). Daher bleibt der Cache für Benutzer mit unveränderten Punkten erhalten.


Um Code für das Menü-Link-Plugin zu generieren, habe ich Drupal Code Generator verwendet .

ya.teck
quelle
Diese Antwort ist genau richtig (und hilfreicher als die aktuelle offizielle Dokumentation . Die yaml-Datei sollte jedoch den Namen example.links.menu.yml, no example.menu-links.yml haben . Löschen Sie anschließend den Cache und Ihren Menüpunkt sollte erscheinen.
Sut3kh
Ist es möglich, auch die Methode getRouteParameters () zu überschreiben? Wenn nein, wie kann man die route_parameters so ändern, dass sie dynamisch sind? In meinem Fall habe ich {Benutzer} im Routing und der Menülink sollte die Benutzer-ID dynamisch als Benutzer-ID des aktuellen Benutzers bereitstellen.
Igal
@Igal denke es ist möglich.
ya.teck
2

Ich hatte das gleiche Problem. Die Menüelemente werden zwischengespeichert, sodass immer der alte Wert angezeigt wird, bis Sie den Cache leeren. Alternativ können Sie hook_page_attachments()Punkte an drupalSettings.YOUR_MODULE_OR_THEME.YOUR_VARIABLE anhängen, auf diese in JavaScript zugreifen und im Browser rendern.

Normalerweise wird der Cache für Seiten deaktiviert, wenn das Menü "Profil" bei der Site-Leistung angezeigt wird.

adal
quelle
0

Deaktivieren Sie den Cache für dieses Menü, hook_preprocess_menu()indem Sie $variables['#cache']['max-age']auf 0 setzen.

Roman Kuntyi
quelle