Upgraded drupal core with security updates
[yaffs-website] / web / core / lib / Drupal / Core / Routing / RoutePreloader.php
1 <?php
2
3 namespace Drupal\Core\Routing;
4
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Cache\CacheBackendInterface;
7 use Drupal\Core\State\StateInterface;
8 use Symfony\Component\EventDispatcher\Event;
9 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
10 use Symfony\Component\HttpKernel\Event\KernelEvent;
11 use Symfony\Component\HttpKernel\KernelEvents;
12
13 /**
14  * Defines a class which preloads non-admin routes.
15  *
16  * On an actual site we want to avoid too many database queries so we build a
17  * list of all routes which most likely appear on the actual site, which are all
18  * HTML routes not starting with "/admin".
19  */
20 class RoutePreloader implements EventSubscriberInterface {
21
22   /**
23    * The route provider.
24    *
25    * @var \Drupal\Core\Routing\RouteProviderInterface|\Drupal\Core\Routing\PreloadableRouteProviderInterface
26    */
27   protected $routeProvider;
28
29   /**
30    * The state key value store.
31    *
32    * @var \Drupal\Core\State\StateInterface
33    */
34   protected $state;
35
36   /**
37    * Contains the non-admin routes while rebuilding the routes.
38    *
39    * @var array
40    */
41   protected $nonAdminRoutesOnRebuild = [];
42
43   /**
44    * The cache backend used to skip the state loading.
45    *
46    * @var \Drupal\Core\Cache\CacheBackendInterface
47    */
48   protected $cache;
49
50   /**
51    * Constructs a new RoutePreloader.
52    *
53    * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
54    *   The route provider.
55    * @param \Drupal\Core\State\StateInterface $state
56    *   The state key value store.
57    * @param \Drupal\Core\Cache\CacheBackendInterface $cache
58    */
59   public function __construct(RouteProviderInterface $route_provider, StateInterface $state, CacheBackendInterface $cache) {
60     $this->routeProvider = $route_provider;
61     $this->state = $state;
62     $this->cache = $cache;
63   }
64
65   /**
66    * Loads all non-admin routes right before the actual page is rendered.
67    *
68    * @param \Symfony\Component\HttpKernel\Event\KernelEvent $event
69    *   The event to process.
70    */
71   public function onRequest(KernelEvent $event) {
72     // Only preload on normal HTML pages, as they will display menu links.
73     if ($this->routeProvider instanceof PreloadableRouteProviderInterface && $event->getRequest()->getRequestFormat() == 'html') {
74
75       // Ensure that the state query is cached to skip the database query, if
76       // possible.
77       $key = 'routing.non_admin_routes';
78       if ($cache = $this->cache->get($key)) {
79         $routes = $cache->data;
80       }
81       else {
82         $routes = $this->state->get($key, []);
83         $this->cache->set($key, $routes, Cache::PERMANENT, ['routes']);
84       }
85
86       if ($routes) {
87         // Preload all the non-admin routes at once.
88         $this->routeProvider->preLoadRoutes($routes);
89       }
90     }
91   }
92
93   /**
94    * Alters existing routes for a specific collection.
95    *
96    * @param \Drupal\Core\Routing\RouteBuildEvent $event
97    *   The route build event.
98    */
99   public function onAlterRoutes(RouteBuildEvent $event) {
100     $collection = $event->getRouteCollection();
101     foreach ($collection->all() as $name => $route) {
102       if (strpos($route->getPath(), '/admin/') !== 0 && $route->getPath() != '/admin') {
103         $this->nonAdminRoutesOnRebuild[] = $name;
104       }
105     }
106     $this->nonAdminRoutesOnRebuild = array_unique($this->nonAdminRoutesOnRebuild);
107   }
108
109   /**
110    * Store the non admin routes in state when the route building is finished.
111    *
112    * @param \Symfony\Component\EventDispatcher\Event $event
113    *   The route finish event.
114    */
115   public function onFinishedRoutes(Event $event) {
116     $this->state->set('routing.non_admin_routes', $this->nonAdminRoutesOnRebuild);
117     $this->nonAdminRoutesOnRebuild = [];
118   }
119
120   /**
121    * {@inheritdoc}
122    */
123   public static function getSubscribedEvents() {
124     // Set a really low priority to catch as many as possible routes.
125     $events[RoutingEvents::ALTER] = ['onAlterRoutes', -1024];
126     $events[RoutingEvents::FINISHED] = ['onFinishedRoutes'];
127     // Load the routes before the controller is executed (which happens after
128     // the kernel request event).
129     $events[KernelEvents::REQUEST][] = ['onRequest'];
130     return $events;
131   }
132
133 }