Mercurial > hg > isophonics-drupal-site
diff core/modules/views/src/EventSubscriber/RouteSubscriber.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | af1871eacc83 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/modules/views/src/EventSubscriber/RouteSubscriber.php Wed Nov 29 16:09:58 2017 +0000 @@ -0,0 +1,179 @@ +<?php + +namespace Drupal\views\EventSubscriber; + +use Drupal\Core\Entity\EntityManagerInterface; +use Drupal\Core\State\StateInterface; +use Drupal\Core\Routing\RouteSubscriberBase; +use Drupal\Core\Routing\RoutingEvents; +use Drupal\views\Plugin\views\display\DisplayRouterInterface; +use Drupal\views\ViewExecutable; +use Drupal\views\Views; +use Symfony\Component\Routing\RouteCollection; + +/** + * Builds up the routes of all views. + * + * The general idea is to execute first all alter hooks to determine which + * routes are overridden by views. This information is used to determine which + * views have to be added by views in the dynamic event. + * + * + * @see \Drupal\views\Plugin\views\display\PathPluginBase + */ +class RouteSubscriber extends RouteSubscriberBase { + + /** + * Stores a list of view,display IDs which haven't be used in the alter event. + * + * @var array + */ + protected $viewsDisplayPairs; + + /** + * The view storage. + * + * @var \Drupal\Core\Entity\EntityStorageInterface + */ + protected $viewStorage; + + /** + * The state key value store. + * + * @var \Drupal\Core\State\StateInterface + */ + protected $state; + + /** + * Stores an array of route names keyed by view_id.display_id. + * + * @var array + */ + protected $viewRouteNames = []; + + /** + * Constructs a \Drupal\views\EventSubscriber\RouteSubscriber instance. + * + * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager + * The entity manager. + * @param \Drupal\Core\State\StateInterface $state + * The state key value store. + */ + public function __construct(EntityManagerInterface $entity_manager, StateInterface $state) { + $this->viewStorage = $entity_manager->getStorage('view'); + $this->state = $state; + } + + /** + * Resets the internal state of the route subscriber. + */ + public function reset() { + $this->viewsDisplayPairs = NULL; + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents() { + $events = parent::getSubscribedEvents(); + $events[RoutingEvents::FINISHED] = ['routeRebuildFinished']; + // Ensure to run after the entity resolver subscriber + // @see \Drupal\Core\EventSubscriber\EntityRouteAlterSubscriber + $events[RoutingEvents::ALTER] = ['onAlterRoutes', -175]; + + return $events; + } + + /** + * Gets all the views and display IDs using a route. + */ + protected function getViewsDisplayIDsWithRoute() { + if (!isset($this->viewsDisplayPairs)) { + $this->viewsDisplayPairs = []; + + // @todo Convert this method to some service. + $views = $this->getApplicableViews(); + foreach ($views as $data) { + list($view_id, $display_id) = $data; + $this->viewsDisplayPairs[] = $view_id . '.' . $display_id; + } + $this->viewsDisplayPairs = array_combine($this->viewsDisplayPairs, $this->viewsDisplayPairs); + } + return $this->viewsDisplayPairs; + } + + /** + * Returns a set of route objects. + * + * @return \Symfony\Component\Routing\RouteCollection + * A route collection. + */ + public function routes() { + $collection = new RouteCollection(); + foreach ($this->getViewsDisplayIDsWithRoute() as $pair) { + list($view_id, $display_id) = explode('.', $pair); + $view = $this->viewStorage->load($view_id); + // @todo This should have an executable factory injected. + if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) { + if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) { + if ($display instanceof DisplayRouterInterface) { + $this->viewRouteNames += (array) $display->collectRoutes($collection); + } + } + $view->destroy(); + } + } + + $this->state->set('views.view_route_names', $this->viewRouteNames); + return $collection; + } + + /** + * {@inheritdoc} + */ + protected function alterRoutes(RouteCollection $collection) { + foreach ($this->getViewsDisplayIDsWithRoute() as $pair) { + list($view_id, $display_id) = explode('.', $pair); + $view = $this->viewStorage->load($view_id); + // @todo This should have an executable factory injected. + if (($view = $view->getExecutable()) && $view instanceof ViewExecutable) { + if ($view->setDisplay($display_id) && $display = $view->displayHandlers->get($display_id)) { + if ($display instanceof DisplayRouterInterface) { + // If the display returns TRUE a route item was found, so it does not + // have to be added. + $view_route_names = $display->alterRoutes($collection); + $this->viewRouteNames = $view_route_names + $this->viewRouteNames; + foreach ($view_route_names as $id_display => $route_name) { + $view_route_name = $this->viewsDisplayPairs[$id_display]; + unset($this->viewsDisplayPairs[$id_display]); + $collection->remove("views.$view_route_name"); + } + } + } + $view->destroy(); + } + } + } + + /** + * Stores the new route names after they have been rebuilt. + * + * Callback for the RoutingEvents::FINISHED event. + * + * @see \Drupal\views\EventSubscriber::getSubscribedEvents() + */ + public function routeRebuildFinished() { + $this->reset(); + $this->state->set('views.view_route_names', $this->viewRouteNames); + } + + /** + * Returns all views/display combinations with routes. + * + * @see \Drupal\views\Views::getApplicableViews() + */ + protected function getApplicableViews() { + return Views::getApplicableViews('uses_route'); + } + +}