Same name in this branch
  1. 10 core/modules/config_translation/src/Routing/RouteSubscriber.php \Drupal\config_translation\Routing\RouteSubscriber
  2. 10 core/modules/field_ui/src/Routing/RouteSubscriber.php \Drupal\field_ui\Routing\RouteSubscriber
  3. 10 core/modules/media_library/src/Routing/RouteSubscriber.php \Drupal\media_library\Routing\RouteSubscriber
  4. 10 core/modules/node/src/Routing/RouteSubscriber.php \Drupal\node\Routing\RouteSubscriber
  5. 10 core/modules/views/src/EventSubscriber/RouteSubscriber.php \Drupal\views\EventSubscriber\RouteSubscriber
  6. 10 core/modules/media/tests/modules/media_test_embed/src/Routing/RouteSubscriber.php \Drupal\media_test_embed\Routing\RouteSubscriber
  7. 10 core/modules/block_content/src/Routing/RouteSubscriber.php \Drupal\block_content\Routing\RouteSubscriber
Same name and namespace in other branches
  1. 8.9.x core/modules/views/src/EventSubscriber/RouteSubscriber.php \Drupal\views\EventSubscriber\RouteSubscriber
  2. 9 core/modules/views/src/EventSubscriber/RouteSubscriber.php \Drupal\views\EventSubscriber\RouteSubscriber

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.

Hierarchy

Expanded class hierarchy of RouteSubscriber

See also

\Drupal\views\Plugin\views\display\PathPluginBase

1 file declares its use of RouteSubscriber
RouteSubscriberTest.php in core/modules/views/tests/src/Unit/EventSubscriber/RouteSubscriberTest.php
1 string reference to 'RouteSubscriber'
views.services.yml in core/modules/views/views.services.yml
core/modules/views/views.services.yml
1 service uses RouteSubscriber
views.route_subscriber in core/modules/views/views.services.yml
Drupal\views\EventSubscriber\RouteSubscriber

File

core/modules/views/src/EventSubscriber/RouteSubscriber.php, line 24

Namespace

Drupal\views\EventSubscriber
View source
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\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager service.
   * @param \Drupal\Core\State\StateInterface $state
   *   The state key value store.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, StateInterface $state) {
    $this->viewStorage = $entity_type_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() : array {
    $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) {
        [
          $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) {
      [
        $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) {
      [
        $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');
  }

}

Members

Namesort descending Modifiers Type Description Overrides
RouteSubscriber::$state protected property The state key value store.
RouteSubscriber::$viewRouteNames protected property Stores an array of route names keyed by view_id.display_id.
RouteSubscriber::$viewsDisplayPairs protected property Stores a list of view,display IDs which haven't be used in the alter event.
RouteSubscriber::$viewStorage protected property The view storage.
RouteSubscriber::alterRoutes protected function Alters existing routes for a specific collection. Overrides RouteSubscriberBase::alterRoutes
RouteSubscriber::getApplicableViews protected function Returns all views/display combinations with routes. 1
RouteSubscriber::getSubscribedEvents public static function Overrides RouteSubscriberBase::getSubscribedEvents
RouteSubscriber::getViewsDisplayIDsWithRoute protected function Gets all the views and display IDs using a route.
RouteSubscriber::reset public function Resets the internal state of the route subscriber.
RouteSubscriber::routeRebuildFinished public function Stores the new route names after they have been rebuilt.
RouteSubscriber::routes public function Returns a set of route objects.
RouteSubscriber::__construct public function Constructs a \Drupal\views\EventSubscriber\RouteSubscriber instance.
RouteSubscriberBase::onAlterRoutes public function Delegates the route altering to self::alterRoutes(). 1