Je suggère d'implémenter un plugin de lien de menu personnalisé. Le code ci-dessous suppose que le nom de votre module est un exemple .
<?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 vous ne voulez pas injecter le service de base de données, la classe deviendrait beaucoup plus 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'];
}
}
Ensuite, vous devez mettre la définition du lien dans le fichier example.links.menu.yml .
example.user_points:
route_name: <front>
menu_name: main
class: Drupal\example\Plugin\Menu\ExampleMenuLink
weight: 30
Le problème de mise en cache
Chaque fois que le nombre de points est modifié, le cache des liens de menu doit être invalidé comme suit.
\Drupal::service('cache_tags.invalidator')->invalidateTags(['example.points_count']);
Vous devez trouver le bon endroit pour cela. Si les points gérés par le module contribué vérifient l'API du module et prennent un hook approprié ( hook_points_insert () , hook_points_delete () et ainsi de suite).
Étant donné que le nombre de points est calculé pour chaque compte d'utilisateur individuellement, vous pouvez envisager d'utiliser des balises de cache par compte (quelque chose comme ['example.points_count.' . $uid]
). Par conséquent, le cache sera conservé pour les utilisateurs avec des points inchangés.
Pour générer du code pour le plugin de lien Menu, j'ai utilisé Drupal Code Generator .