Upgraded drupal core with security updates
[yaffs-website] / web / core / modules / views / src / EventSubscriber / RouteSubscriber.php
1 <?php
2
3 namespace Drupal\views\EventSubscriber;
4
5 use Drupal\Core\Entity\EntityManagerInterface;
6 use Drupal\Core\State\StateInterface;
7 use Drupal\Core\Routing\RouteSubscriberBase;
8 use Drupal\Core\Routing\RoutingEvents;
9 use Drupal\views\Plugin\views\display\DisplayRouterInterface;
10 use Drupal\views\ViewExecutable;
11 use Drupal\views\Views;
12 use Symfony\Component\Routing\RouteCollection;
13
14 /**
15  * Builds up the routes of all views.
16  *
17  * The general idea is to execute first all alter hooks to determine which
18  * routes are overridden by views. This information is used to determine which
19  * views have to be added by views in the dynamic event.
20  *
21  *
22  * @see \Drupal\views\Plugin\views\display\PathPluginBase
23  */
24 class RouteSubscriber extends RouteSubscriberBase {
25
26   /**
27    * Stores a list of view,display IDs which haven't be used in the alter event.
28    *
29    * @var array
30    */
31   protected $viewsDisplayPairs;
32
33   /**
34    * The view storage.
35    *
36    * @var \Drupal\Core\Entity\EntityStorageInterface
37    */
38   protected $viewStorage;
39
40   /**
41    * The state key value store.
42    *
43    * @var \Drupal\Core\State\StateInterface
44    */
45   protected $state;
46
47   /**
48    * Stores an array of route names keyed by view_id.display_id.
49    *
50    * @var array
51    */
52   protected $viewRouteNames = [];
53
54   /**
55    * Constructs a \Drupal\views\EventSubscriber\RouteSubscriber instance.
56    *
57    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
58    *   The entity manager.
59    * @param \Drupal\Core\State\StateInterface $state
60    *   The state key value store.
61    */
62   public function __construct(EntityManagerInterface $entity_manager, StateInterface $state) {
63     $this->viewStorage = $entity_manager->getStorage('view');
64     $this->state = $state;
65   }
66
67   /**
68    * Resets the internal state of the route subscriber.
69    */
70   public function reset() {
71     $this->viewsDisplayPairs = NULL;
72   }
73
74   /**
75    * {@inheritdoc}
76    */
77   public static function getSubscribedEvents() {
78     $events = parent::getSubscribedEvents();
79     $events[RoutingEvents::FINISHED] = ['routeRebuildFinished'];
80     // Ensure to run after the entity resolver subscriber
81     // @see \Drupal\Core\EventSubscriber\EntityRouteAlterSubscriber
82     $events[RoutingEvents::ALTER] = ['onAlterRoutes', -175];
83
84     return $events;
85   }
86
87   /**
88    * Gets all the views and display IDs using a route.
89    */
90   protected function getViewsDisplayIDsWithRoute() {
91     if (!isset($this->viewsDisplayPairs)) {
92       $this->viewsDisplayPairs = [];
93
94       // @todo Convert this method to some service.
95       $views = $this->getApplicableViews();
96       foreach ($views as $data) {
97         list($view_id, $display_id) = $data;
98         $this->viewsDisplayPairs[] = $view_id . '.' . $display_id;
99       }
100       $this->viewsDisplayPairs = array_combine($this->viewsDisplayPairs, $this->viewsDisplayPairs);
101     }
102     return $this->viewsDisplayPairs;
103   }
104
105   /**
106    * Returns a set of route objects.
107    *
108    * @return \Symfony\Component\Routing\RouteCollection
109    *   A route collection.
110    */
111   public function routes() {
112     $collection = new RouteCollection();
113     foreach ($this->getViewsDisplayIDsWithRoute() as $pair) {
114       list($view_id, $display_id) = explode('.', $pair);
115       $view = $this->viewStorage->load($view_id);
116       // @todo This should have an executable factory injected.
117       if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) {
118         if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) {
119           if ($display instanceof DisplayRouterInterface) {
120             $this->viewRouteNames += (array) $display->collectRoutes($collection);
121           }
122         }
123         $view->destroy();
124       }
125     }
126
127     $this->state->set('views.view_route_names', $this->viewRouteNames);
128     return $collection;
129   }
130
131   /**
132    * {@inheritdoc}
133    */
134   protected function alterRoutes(RouteCollection $collection) {
135     foreach ($this->getViewsDisplayIDsWithRoute() as $pair) {
136       list($view_id, $display_id) = explode('.', $pair);
137       $view = $this->viewStorage->load($view_id);
138       // @todo This should have an executable factory injected.
139       if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) {
140         if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) {
141           if ($display instanceof DisplayRouterInterface) {
142             // If the display returns TRUE a route item was found, so it does not
143             // have to be added.
144             $view_route_names = $display->alterRoutes($collection);
145             $this->viewRouteNames = $view_route_names + $this->viewRouteNames;
146             foreach ($view_route_names as $id_display => $route_name) {
147               $view_route_name = $this->viewsDisplayPairs[$id_display];
148               unset($this->viewsDisplayPairs[$id_display]);
149               $collection->remove("views.$view_route_name");
150             }
151           }
152         }
153         $view->destroy();
154       }
155     }
156   }
157
158   /**
159    * Stores the new route names after they have been rebuilt.
160    *
161    * Callback for the RoutingEvents::FINISHED event.
162    *
163    * @see \Drupal\views\EventSubscriber::getSubscribedEvents()
164    */
165   public function routeRebuildFinished() {
166     $this->reset();
167     $this->state->set('views.view_route_names', $this->viewRouteNames);
168   }
169
170   /**
171    * Returns all views/display combinations with routes.
172    *
173    * @see \Drupal\views\Views::getApplicableViews()
174    */
175   protected function getApplicableViews() {
176     return Views::getApplicableViews('uses_route');
177   }
178
179 }