123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133 |
- <?php
- namespace Drupal\Core\Routing;
- use Drupal\Core\Cache\Cache;
- use Drupal\Core\Cache\CacheBackendInterface;
- use Drupal\Core\State\StateInterface;
- use Symfony\Component\EventDispatcher\Event;
- use Symfony\Component\EventDispatcher\EventSubscriberInterface;
- use Symfony\Component\HttpKernel\Event\KernelEvent;
- use Symfony\Component\HttpKernel\KernelEvents;
- /**
- * Defines a class which preloads non-admin routes.
- *
- * On an actual site we want to avoid too many database queries so we build a
- * list of all routes which most likely appear on the actual site, which are all
- * HTML routes not starting with "/admin".
- */
- class RoutePreloader implements EventSubscriberInterface {
- /**
- * The route provider.
- *
- * @var \Drupal\Core\Routing\RouteProviderInterface|\Drupal\Core\Routing\PreloadableRouteProviderInterface
- */
- protected $routeProvider;
- /**
- * The state key value store.
- *
- * @var \Drupal\Core\State\StateInterface
- */
- protected $state;
- /**
- * Contains the non-admin routes while rebuilding the routes.
- *
- * @var array
- */
- protected $nonAdminRoutesOnRebuild = [];
- /**
- * The cache backend used to skip the state loading.
- *
- * @var \Drupal\Core\Cache\CacheBackendInterface
- */
- protected $cache;
- /**
- * Constructs a new RoutePreloader.
- *
- * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
- * The route provider.
- * @param \Drupal\Core\State\StateInterface $state
- * The state key value store.
- * @param \Drupal\Core\Cache\CacheBackendInterface $cache
- */
- public function __construct(RouteProviderInterface $route_provider, StateInterface $state, CacheBackendInterface $cache) {
- $this->routeProvider = $route_provider;
- $this->state = $state;
- $this->cache = $cache;
- }
- /**
- * Loads all non-admin routes right before the actual page is rendered.
- *
- * @param \Symfony\Component\HttpKernel\Event\KernelEvent $event
- * The event to process.
- */
- public function onRequest(KernelEvent $event) {
- // Only preload on normal HTML pages, as they will display menu links.
- if ($this->routeProvider instanceof PreloadableRouteProviderInterface && $event->getRequest()->getRequestFormat() == 'html') {
- // Ensure that the state query is cached to skip the database query, if
- // possible.
- $key = 'routing.non_admin_routes';
- if ($cache = $this->cache->get($key)) {
- $routes = $cache->data;
- }
- else {
- $routes = $this->state->get($key, []);
- $this->cache->set($key, $routes, Cache::PERMANENT, ['routes']);
- }
- if ($routes) {
- // Preload all the non-admin routes at once.
- $this->routeProvider->preLoadRoutes($routes);
- }
- }
- }
- /**
- * Alters existing routes for a specific collection.
- *
- * @param \Drupal\Core\Routing\RouteBuildEvent $event
- * The route build event.
- */
- public function onAlterRoutes(RouteBuildEvent $event) {
- $collection = $event->getRouteCollection();
- foreach ($collection->all() as $name => $route) {
- if (strpos($route->getPath(), '/admin/') !== 0 && $route->getPath() != '/admin') {
- $this->nonAdminRoutesOnRebuild[] = $name;
- }
- }
- $this->nonAdminRoutesOnRebuild = array_unique($this->nonAdminRoutesOnRebuild);
- }
- /**
- * Store the non admin routes in state when the route building is finished.
- *
- * @param \Symfony\Component\EventDispatcher\Event $event
- * The route finish event.
- */
- public function onFinishedRoutes(Event $event) {
- $this->state->set('routing.non_admin_routes', $this->nonAdminRoutesOnRebuild);
- $this->nonAdminRoutesOnRebuild = [];
- }
- /**
- * {@inheritdoc}
- */
- public static function getSubscribedEvents() {
- // Set a really low priority to catch as many as possible routes.
- $events[RoutingEvents::ALTER] = ['onAlterRoutes', -1024];
- $events[RoutingEvents::FINISHED] = ['onFinishedRoutes'];
- // Load the routes before the controller is executed (which happens after
- // the kernel request event).
- $events[KernelEvents::REQUEST][] = ['onRequest'];
- return $events;
- }
- }
|