Como altero o título de um link de menu?

8

No meu site, os usuários podem coletar alguns 'pontos' ao longo do tempo. Eu tenho um menu da barra superior com alguns links (por exemplo, "home", "profile", "logout"). Desejo alterar o item de menu "perfil" e adicionar os pontos numéricos pertencentes ao usuário conectado atual.

Tentei vários ganchos e quase consegui o que queria hook_link_alter().

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

Limpei o cache (com drush cr) e o item de menu mostra o valor que eu quero. Mas, se o valor mudar por algum motivo, ele mostra o valor antigo. Devo limpar o cache o tempo todo para atualizar seu valor.

Como evitar a limpeza do cache para atualizar o título do menu todas as vezes que os pontos ganhos do usuário são alterados?

matthieu lopez
fonte
Parece que você precisa de um plugin personalizado para isso. Pergunta interessante. Geralmente, você deve evitar implementar quaisquer ganchos da velha escola no D8. A questão é como alterar o título do menu via plug-in personalizado.
achou
O seu menu está em um bloco? Se for esse o caso, talvez tentar definir o cache para 0 para esse bloco
pbonnefoi
é um bloco criado a partir da interface de administração. Eu não fiz o acesso a configuração do cache :)
matthieu lopez
Sugiro que você comece com drupal.org/docs/8/api/menu-api , o '#cache' => ['max-age' => 0] não é uma solução. você precisa criar um link de menu dinâmico.
Arnold PÉTER
"o item de menu mostra o valor que eu quero" Você verificou o menu com outra conta de usuário? Eu suspeito que esteja mostrando o mesmo número de pontos para todos os usuários.
Ya.teck 02/11/19

Respostas:

7

Sugiro implementar um plug-in de link de menu personalizado. O código abaixo assume que o nome do seu módulo é um exemplo .

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

}

Se você não deseja injetar o serviço de banco de dados, a classe se tornaria muito mais simples.

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

}

Em seguida, você precisa colocar a definição do link no arquivo example.links.menu.yml .

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

O problema de armazenamento em cache

Sempre que o número de pontos é alterado, o cache do link do menu deve ser invalidado da seguinte maneira.

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

Você precisa descobrir o lugar certo para isso. Se os pontos gerenciados pelo módulo contribuído, verifique a API do módulo e escolha um gancho apropriado ( hook_points_insert () , hook_points_delete () e assim por diante).

Como o número de pontos é calculado para cada conta de usuário individualmente, você pode considerar o uso de tags de cache por conta (algo como ['example.points_count.' . $uid]). Portanto, o cache será preservado para usuários com pontos inalterados.


Para gerar código para o plug-in de link de menu, usei o Drupal Code Generator .

ya.teck
fonte
Esta resposta é imediata (e mais útil que a documentação oficial atual . No entanto, o arquivo yaml deve ser nomeado exemplo.links.menu.yml, nenhum exemplo.menu-links.yml . Depois disso, limpe o cache e o item de menu deve aparecer.
Sut3kh
É possível substituir também o método getRouteParameters ()? Se não, como alterar os parâmetros de rota para serem dinâmicos? No meu caso, tenho {usuário} no roteamento e o link do menu deve fornecer o ID do usuário dinamicamente como ID do usuário atual.
Igal
@Igal acho que é possível.
usar o seguinte comando
2

Eu enfrentei o mesmo problema. Os itens de menu são armazenados em cache, portanto, ele sempre mostra o valor antigo até você limpar o cache. A maneira alternativa é usar hook_page_attachments(), anexar pontos a drupalSettings.YOUR_MODULE_OR_THEME.YOUR_VARIABLE, acessá-los em JavaScript e renderizar no navegador.

A maneira normal é desativar o cache de páginas sempre que o menu "perfil" for exibido no desempenho do site.

adal
fonte
0

Desabilite o cache desse menu hook_preprocess_menu()configurando $variables['#cache']['max-age']como 0.

Roman Kuntyi
fonte