You are here

class RouteSubscriber in Drupal 10

Same name in this branch
  1. 10 core/modules/views/src/EventSubscriber/RouteSubscriber.php \Drupal\views\EventSubscriber\RouteSubscriber
  2. 10 core/modules/node/src/Routing/RouteSubscriber.php \Drupal\node\Routing\RouteSubscriber
  3. 10 core/modules/media_library/src/Routing/RouteSubscriber.php \Drupal\media_library\Routing\RouteSubscriber
  4. 10 core/modules/config_translation/src/Routing/RouteSubscriber.php \Drupal\config_translation\Routing\RouteSubscriber
  5. 10 core/modules/field_ui/src/Routing/RouteSubscriber.php \Drupal\field_ui\Routing\RouteSubscriber
  6. 10 core/modules/media/tests/modules/media_test_embed/src/Routing/RouteSubscriber.php \Drupal\media_test_embed\Routing\RouteSubscriber
Same name and namespace in other branches
  1. 8 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

  • class \Drupal\views\EventSubscriber\RouteSubscriber extends \Drupal\Core\Routing\RouteSubscriberBase

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
Contains \Drupal\Tests\views\Unit\EventSubscriber\RouteSubscriberTest.
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