MenuRouterRebuildSubscriber.php 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. <?php
  2. namespace Drupal\Core\EventSubscriber;
  3. use Drupal\Core\Cache\Cache;
  4. use Drupal\Core\Lock\LockBackendInterface;
  5. use Drupal\Core\Menu\MenuLinkManagerInterface;
  6. use Drupal\Core\Routing\RoutingEvents;
  7. use Symfony\Component\EventDispatcher\Event;
  8. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  9. /**
  10. * Rebuilds the default menu links and runs menu-specific code if necessary.
  11. */
  12. class MenuRouterRebuildSubscriber implements EventSubscriberInterface {
  13. /**
  14. * @var \Drupal\Core\Lock\LockBackendInterface
  15. */
  16. protected $lock;
  17. /**
  18. * The menu link plugin manager.
  19. *
  20. * @var \Drupal\Core\Menu\MenuLinkManagerInterface
  21. */
  22. protected $menuLinkManager;
  23. /**
  24. * Constructs the MenuRouterRebuildSubscriber object.
  25. *
  26. * @param \Drupal\Core\Lock\LockBackendInterface $lock
  27. * The lock backend.
  28. * @param \Drupal\Core\Menu\MenuLinkManagerInterface $menu_link_manager
  29. * The menu link plugin manager.
  30. */
  31. public function __construct(LockBackendInterface $lock, MenuLinkManagerInterface $menu_link_manager) {
  32. $this->lock = $lock;
  33. $this->menuLinkManager = $menu_link_manager;
  34. }
  35. /**
  36. * Rebuilds the menu links and deletes the local_task cache tag.
  37. *
  38. * @param \Symfony\Component\EventDispatcher\Event $event
  39. * The event object.
  40. */
  41. public function onRouterRebuild(Event $event) {
  42. $this->menuLinksRebuild();
  43. Cache::invalidateTags(['local_task']);
  44. }
  45. /**
  46. * Perform menu-specific rebuilding.
  47. */
  48. protected function menuLinksRebuild() {
  49. if ($this->lock->acquire(__FUNCTION__)) {
  50. $transaction = db_transaction();
  51. try {
  52. // Ensure the menu links are up to date.
  53. $this->menuLinkManager->rebuild();
  54. // Ignore any database replicas temporarily.
  55. db_ignore_replica();
  56. }
  57. catch (\Exception $e) {
  58. $transaction->rollBack();
  59. watchdog_exception('menu', $e);
  60. }
  61. $this->lock->release(__FUNCTION__);
  62. }
  63. else {
  64. // Wait for another request that is already doing this work.
  65. // We choose to block here since otherwise the router item may not
  66. // be available during routing resulting in a 404.
  67. $this->lock->wait(__FUNCTION__);
  68. }
  69. }
  70. /**
  71. * {@inheritdoc}
  72. */
  73. public static function getSubscribedEvents() {
  74. // Run after CachedRouteRebuildSubscriber.
  75. $events[RoutingEvents::FINISHED][] = ['onRouterRebuild', 100];
  76. return $events;
  77. }
  78. }