Как изменить заголовок ссылки в меню?

8

На моем веб-сайте пользователи могут собирать «баллы» с течением времени. У меня есть меню верхней панели с некоторыми ссылками (например, «дом», «профиль», «выход»). Я хочу изменить пункт меню «профиль» и добавить количество точек, принадлежащих текущему подключенному пользователю.

Я попробовал несколько крючков, и мне почти удалось получить то, что я хотел с hook_link_alter().

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

Я очистил кеш (с drush cr), и пункт меню показывает значение, которое я хочу. Но если значение изменяется по какой-либо причине, оно показывает старое значение. Я должен очистить кэш все время, чтобы обновить его значение.

Как я могу избежать очистки кеша, чтобы обновлять заголовок меню каждый раз, когда меняются баллы, полученные от пользователя?

Матье Лопес
источник
Похоже, вам нужен специальный плагин для этого. Интересный вопрос Как правило, вы должны избегать использования каких-либо хуков старой школы в D8. Вопрос в том, как изменить заголовок меню через пользовательский плагин.
Codium
Ваше меню в блоке? Если это так, возможно, попробуйте установить кэш 0 для этого блока
pbonnefoi
это блок, созданный из интерфейса администрирования. У меня не было доступа к конфигурации кэша :)
Матье Лопес
Я предлагаю вам начать с drupal.org/docs/8/api/menu-api , '#cache' => ['max-age' => 0], это не решение проблемы. вам нужно создать динамическую ссылку меню.
Арнольд Петер
"пункт меню показывает значение, которое я хочу" Вы проверили меню с другой учетной записью пользователя? Я подозреваю, что он показывает одинаковое количество баллов для всех пользователей.
я.тек

Ответы:

7

Я предлагаю реализовать пользовательский плагин ссылки меню. Код ниже предполагает, что ваше имя модуля является примером .

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

}

Если вы не хотите внедрять службу базы данных, класс станет намного проще.

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

}

Далее вам нужно поместить определение ссылки в файл example.links.menu.yml .

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

Проблема кеширования

Всякий раз, когда количество пунктов изменяется, кэш ссылок меню должен быть аннулирован следующим образом.

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

Вам нужно найти правильное место для этого. Если точки, управляемые добавленным модулем, проверяют API модуля и выбирают соответствующий хук ( hook_points_insert () , hook_points_delete () и т. Д.).

Поскольку количество баллов рассчитывается для каждой учетной записи индивидуально, вы можете рассмотреть возможность использования тегов кэша для каждой учетной записи (что-то вроде ['example.points_count.' . $uid]). Поэтому кеш будет сохранен для пользователей с неизменными баллами.


Для генерации кода для плагина «Меню» я использовал Drupal Code Generator .

ya.teck
источник
Этот ответ полезен (и более полезен, чем текущая официальная документация . Однако файл yaml должен называться example.links.menu.yml, а не example.menu-links.yml . После этого очистите кэш и ваш пункт меню. должен появиться.
Сут3х
Можно ли переопределить также метод getRouteParameters ()? Если нет, то как изменить параметры route_parameters на динамические? В моем случае у меня есть {user} в маршрутизации, и ссылка меню должна предоставлять идентификатор пользователя динамически как идентификатор текущего пользователя.
Игал
@ Думаю, это возможно.
я.тек
2

Я столкнулся с той же проблемой. Элементы меню кэшируются, поэтому всегда отображается старое значение, пока вы не очистите кэш. Альтернативным способом является использование hook_page_attachments(), прикрепление точек к drupalSettings.YOUR_MODULE_OR_THEME.YOUR_VARIABLE, доступ к ним в JavaScript и рендеринг в браузере.

Обычным способом является отключение кэша для страниц всякий раз, когда отображается меню «Профиль» при производительности сайта.

Адал
источник
0

Отключите кэш для этого меню hook_preprocess_menu(), установив $variables['#cache']['max-age']в 0.

Роман Кунти
источник