From 1e08b50f421bdbcb5c5f0bb83ebaff5d3843c3ac Mon Sep 17 00:00:00 2001
From: Alex Pott <alex.a.pott@googlemail.com>
Date: Fri, 9 Jan 2015 15:14:23 +0000
Subject: [PATCH] Issue #2281619 by dawehner, tim.plunkett: Convert most direct
 usages within module code of routing related request attributes to use
 RouteMatchInterface instead

---
 core/core.services.yml                        |  2 +-
 .../Core/Controller/ControllerResolver.php    | 19 ++-----
 core/lib/Drupal/Core/Form/FormBase.php        | 19 +++++++
 core/lib/Drupal/Core/Routing/AdminContext.php | 31 +++---------
 .../Drupal/Core/Routing/CurrentRouteMatch.php |  7 +++
 .../Routing/StackedRouteMatchInterface.php    | 14 +++++-
 core/modules/comment/comment.module           | 18 +++----
 .../src/ConfigEntityMapper.php                |  1 +
 .../src/ConfigMapperInterface.php             |  2 +
 .../ContentTranslationController.php          | 31 ++++++------
 .../src/Form/ContentTranslationDeleteForm.php |  7 +--
 .../Controller/FieldConfigListController.php  | 11 +++--
 .../field_ui/src/Form/FieldStorageAddForm.php |  2 +-
 .../Plugin/views/argument_default/Node.php    | 42 +++++++++++++++-
 core/modules/rest/src/RequestHandler.php      |  6 ++-
 core/modules/system/entity.api.php            |  8 +--
 .../system/src/PathBasedBreadcrumbBuilder.php | 10 ++--
 .../src/Controller/EntityTestController.php   | 10 ++--
 .../src/FormTestControllerObject.php          |  5 +-
 .../src/TestControllers.php                   |  4 +-
 .../PathBasedBreadcrumbBuilderTest.php        |  4 +-
 .../src/Plugin/views/argument_default/Tid.php | 43 +++++++++++++++-
 core/modules/update/update.module             |  3 +-
 .../user/src/Plugin/Block/UserLoginBlock.php  | 49 +++++++++++++++++--
 .../LanguageNegotiationUserAdmin.php          | 20 ++++++--
 .../Plugin/views/argument_default/User.php    | 45 +++++++++++++++--
 .../views/src/Plugin/views/argument/Date.php  | 44 ++++++++++++++++-
 .../views/display/DisplayPluginBase.php       |  2 +-
 .../Controller/ControllerResolverTest.php     |  4 +-
 .../Core/Routing/CurrentRouteMatchTest.php    | 34 +++++++++++++
 30 files changed, 383 insertions(+), 114 deletions(-)

diff --git a/core/core.services.yml b/core/core.services.yml
index 9ab7af7e022c..8a5a126e5440 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -505,7 +505,7 @@ services:
       - [fromRequestStack, ['@request_stack']]
   router.admin_context:
     class: Drupal\Core\Routing\AdminContext
-    arguments: ['@request_stack']
+    arguments: ['@current_route_match']
   router.route_provider:
     class: Drupal\Core\Routing\RouteProvider
     arguments: ['@database', '@router.builder', '@state']
diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php
index d5193e76541f..febffd906ed3 100644
--- a/core/lib/Drupal/Core/Controller/ControllerResolver.php
+++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php
@@ -138,11 +138,15 @@ protected function createController($controller) {
    */
   protected function doGetArguments(Request $request, $controller, array $parameters) {
     $attributes = $request->attributes->all();
+    $raw_parameters = $request->attributes->has('_raw_variables') ? $request->attributes->get('_raw_variables') : [];
     $arguments = array();
     foreach ($parameters as $param) {
       if (array_key_exists($param->name, $attributes)) {
         $arguments[] = $attributes[$param->name];
       }
+      elseif (array_key_exists($param->name, $raw_parameters)) {
+        $arguments[] = $attributes[$param->name];
+      }
       elseif ($param->getClass() && $param->getClass()->isInstance($request)) {
         $arguments[] = $request;
       }
@@ -166,21 +170,6 @@ protected function doGetArguments(Request $request, $controller, array $paramete
         throw new \RuntimeException(sprintf('Controller "%s" requires that you provide a value for the "$%s" argument (because there is no default value or because there is a non optional argument after this one).', $repr, $param->name));
       }
     }
-
-    // The parameter converter overrides the raw request attributes with the
-    // upcasted objects. However, it keeps a backup copy of the original, raw
-    // values in a special request attribute ('_raw_variables'). If a controller
-    // argument has a type hint, we pass it the upcasted object, otherwise we
-    // pass it the original, raw value.
-    if ($request->attributes->has('_raw_variables') && $raw = $request->attributes->get('_raw_variables')->all()) {
-      foreach ($parameters as $parameter) {
-        // Use the raw value if a parameter has no typehint.
-        if (!$parameter->getClass() && isset($raw[$parameter->name])) {
-          $position = $parameter->getPosition();
-          $arguments[$position] = $raw[$parameter->name];
-        }
-      }
-    }
     return $arguments;
   }
 
diff --git a/core/lib/Drupal/Core/Form/FormBase.php b/core/lib/Drupal/Core/Form/FormBase.php
index 3a146127930b..b60e9ed32cc6 100644
--- a/core/lib/Drupal/Core/Form/FormBase.php
+++ b/core/lib/Drupal/Core/Form/FormBase.php
@@ -53,6 +53,13 @@ abstract class FormBase implements FormInterface, ContainerInjectionInterface {
    */
   protected $loggerFactory;
 
+  /**
+   * The route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
   /**
    * {@inheritdoc}
    */
@@ -135,6 +142,18 @@ protected function getRequest() {
     return $this->requestStack->getCurrentRequest();
   }
 
+  /**
+   * Gets the route match.
+   *
+   * @return \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected function getRouteMatch() {
+    if (!$this->routeMatch) {
+      $this->routeMatch = \Drupal::routeMatch();
+    }
+    return $this->routeMatch;
+  }
+
   /**
    * Sets the request stack object to use.
    *
diff --git a/core/lib/Drupal/Core/Routing/AdminContext.php b/core/lib/Drupal/Core/Routing/AdminContext.php
index dac583915522..5ea7c9cce51e 100644
--- a/core/lib/Drupal/Core/Routing/AdminContext.php
+++ b/core/lib/Drupal/Core/Routing/AdminContext.php
@@ -7,8 +7,6 @@
 
 namespace Drupal\Core\Routing;
 
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -17,20 +15,20 @@
 class AdminContext {
 
   /**
-   * The request stack
+   * The route match.
    *
-   * @var \Symfony\Component\HttpFoundation\RequestStack
+   * @var \Drupal\Core\Routing\RouteMatchInterface
    */
-  protected $requestStack;
+  protected $routeMatch;
 
   /**
    * Construct a new admin context helper instance.
    *
-   * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
-   *   The request stack used to determine the current request.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
    */
-  public function __construct(RequestStack $request_stack) {
-    $this->requestStack = $request_stack;
+  public function __construct(RouteMatchInterface $route_match) {
+    $this->routeMatch = $route_match;
   }
 
   /**
@@ -45,7 +43,7 @@ public function __construct(RequestStack $request_stack) {
    */
   public function isAdminRoute(Route $route = NULL) {
     if (!$route) {
-      $route = $this->getRouteFromRequest();
+      $route = $this->routeMatch->getRouteObject();
       if (!$route) {
         return FALSE;
       }
@@ -53,17 +51,4 @@ public function isAdminRoute(Route $route = NULL) {
     return (bool) $route->getOption('_admin_route');
   }
 
-  /**
-   * Extract the route object from the request if one is available.
-   *
-   * @return \Symfony\Component\Routing\Route
-   *   The route object extracted from the current request.
-   */
-  protected function getRouteFromRequest() {
-    $request = $this->requestStack->getCurrentRequest();
-    if ($request) {
-      return $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT);
-    }
-  }
-
 }
diff --git a/core/lib/Drupal/Core/Routing/CurrentRouteMatch.php b/core/lib/Drupal/Core/Routing/CurrentRouteMatch.php
index 4b482eaf6b6a..979c1891d0fb 100644
--- a/core/lib/Drupal/Core/Routing/CurrentRouteMatch.php
+++ b/core/lib/Drupal/Core/Routing/CurrentRouteMatch.php
@@ -132,4 +132,11 @@ public function getParentRouteMatch() {
     return $this->getRouteMatch($this->requestStack->getParentRequest());
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getRouteMatchFromRequest(Request $request) {
+    return $this->getRouteMatch($request);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Routing/StackedRouteMatchInterface.php b/core/lib/Drupal/Core/Routing/StackedRouteMatchInterface.php
index fde003596ad9..e5eb80929067 100644
--- a/core/lib/Drupal/Core/Routing/StackedRouteMatchInterface.php
+++ b/core/lib/Drupal/Core/Routing/StackedRouteMatchInterface.php
@@ -7,6 +7,8 @@
 
 namespace Drupal\Core\Routing;
 
+use Symfony\Component\HttpFoundation\Request;
+
 /**
  * Defines an interface for a stack of route matches.
  *
@@ -36,5 +38,15 @@ public function getMasterRouteMatch();
    */
   public function getParentRouteMatch();
 
-}
+  /**
+   * Returns a route match from a given request, if possible.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request
+   *   The request.
+   *
+   * @return \Drupal\Core\Routing\RouteMatchInterface|NULL
+   *   THe matching route match, or NULL if there is no matching one.
+   */
+  public function getRouteMatchFromRequest(Request $request);
 
+}
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 497855178505..79f0d3860a87 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -314,9 +314,9 @@ function comment_view_multiple($comments, $view_mode = 'full', $langcode = NULL)
  * Implements hook_form_FORM_ID_alter() for field_ui_field_storage_add_form.
  */
 function comment_form_field_ui_field_storage_add_form_alter(&$form, FormStateInterface $form_state) {
-  $request = \Drupal::request();
-  if ($form_state->get('entity_type_id') == 'comment' && $request->attributes->has('commented_entity_type')) {
-    $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($request->attributes->get('commented_entity_type'), $request->attributes->get('field_name'));
+  $route_match = \Drupal::routeMatch();
+  if ($form_state->get('entity_type_id') == 'comment' && $route_match->getParameter('commented_entity_type')) {
+    $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($route_match->getParameter('commented_entity_type'), $route_match->getParameter('field_name'));
   }
   if (!_comment_entity_uses_integer_id($form_state->get('entity_type_id'))) {
     // You cannot use comment fields on entity types with non-integer IDs.
@@ -328,9 +328,9 @@ function comment_form_field_ui_field_storage_add_form_alter(&$form, FormStateInt
  * Implements hook_form_FORM_ID_alter().
  */
 function comment_form_field_ui_form_display_overview_form_alter(&$form, FormStateInterface $form_state) {
-  $request = \Drupal::request();
-  if ($form['#entity_type'] == 'comment' && $request->attributes->has('commented_entity_type')) {
-    $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($request->attributes->get('commented_entity_type'), $request->attributes->get('field_name'));
+  $route_match = \Drupal::routeMatch();
+  if ($form['#entity_type'] == 'comment' && $route_match->getParameter('commented_entity_type')) {
+    $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($route_match->getParameter('commented_entity_type'), $route_match->getParameter('field_name'));
   }
 }
 
@@ -338,9 +338,9 @@ function comment_form_field_ui_form_display_overview_form_alter(&$form, FormStat
  * Implements hook_form_FORM_ID_alter().
  */
 function comment_form_field_ui_display_overview_form_alter(&$form, FormStateInterface $form_state) {
-  $request = \Drupal::request();
-  if ($form['#entity_type'] == 'comment' && $request->attributes->has('commented_entity_type')) {
-    $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($request->attributes->get('commented_entity_type'), $request->attributes->get('field_name'));
+  $route_match = \Drupal::routeMatch();
+  if ($form['#entity_type'] == 'comment' && $route_match->getParameter('commented_entity_type')) {
+    $form['#title'] = \Drupal::service('comment.manager')->getFieldUIPageTitle($route_match->getParameter('commented_entity_type'), $route_match->getParameter('field_name'));
   }
 }
 
diff --git a/core/modules/config_translation/src/ConfigEntityMapper.php b/core/modules/config_translation/src/ConfigEntityMapper.php
index 2cbc78e38edc..848a6ce2cf68 100644
--- a/core/modules/config_translation/src/ConfigEntityMapper.php
+++ b/core/modules/config_translation/src/ConfigEntityMapper.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Config\TypedConfigManagerInterface;
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\Core\Entity\EntityManagerInterface;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\StringTranslation\TranslationInterface;
 use Drupal\Core\Url;
diff --git a/core/modules/config_translation/src/ConfigMapperInterface.php b/core/modules/config_translation/src/ConfigMapperInterface.php
index ba75aa2b6298..ac3d531a2aba 100644
--- a/core/modules/config_translation/src/ConfigMapperInterface.php
+++ b/core/modules/config_translation/src/ConfigMapperInterface.php
@@ -281,6 +281,8 @@ public function hasTranslation(LanguageInterface $language);
   /**
    * Populate the config mapper with request data.
    *
+   * @todo Replace $request with RouteMatch https://www.drupal.org/node/2295255.
+   *
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   Page request object.
    */
diff --git a/core/modules/content_translation/src/Controller/ContentTranslationController.php b/core/modules/content_translation/src/Controller/ContentTranslationController.php
index e3622dc9ddf3..dc74210738fa 100644
--- a/core/modules/content_translation/src/Controller/ContentTranslationController.php
+++ b/core/modules/content_translation/src/Controller/ContentTranslationController.php
@@ -10,8 +10,8 @@
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Entity\ContentEntityInterface;
 use Drupal\Core\Language\LanguageInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Url;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Base class for entity translation controllers.
@@ -37,16 +37,15 @@ public function prepareTranslation(ContentEntityInterface $entity, LanguageInter
   /**
    * Builds the translations overview page.
    *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The request object from which to extract the entity type.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
    * @param string $entity_type_id
    *   (optional) The entity type ID.
-   *
-   * @return array
-   *   Array of page elements to render.
+   * @return array Array of page elements to render.
+   * Array of page elements to render.
    */
-  public function overview(Request $request, $entity_type_id = NULL) {
-    $entity = $request->attributes->get($entity_type_id);
+  public function overview(RouteMatchInterface $route_match, $entity_type_id = NULL) {
+    $entity = $route_match->getParameter($entity_type_id);
     $account = $this->currentUser();
     $handler = $this->entityManager()->getHandler($entity_type_id, 'translation');
 
@@ -252,16 +251,16 @@ public function overview(Request $request, $entity_type_id = NULL) {
    * @param \Drupal\Core\Language\LanguageInterface $target
    *   The language of the translated values. Defaults to the current content
    *   language.
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The request object from which to extract the entity type.
+   * @param \Drupal\Core\Routing\RouteMatchInterface
+   *   The route match object from which to extract the entity type.
    * @param string $entity_type_id
    *   (optional) The entity type ID.
    *
    * @return array
    *   A processed form array ready to be rendered.
    */
-  public function add(LanguageInterface $source, LanguageInterface $target, Request $request, $entity_type_id = NULL) {
-    $entity = $request->attributes->get($entity_type_id);
+  public function add(LanguageInterface $source, LanguageInterface $target, RouteMatchInterface $route_match, $entity_type_id = NULL) {
+    $entity = $route_match->getParameter($entity_type_id);
 
     // @todo Exploit the upcoming hook_entity_prepare() when available.
     // See https://www.drupal.org/node/1810394.
@@ -287,16 +286,16 @@ public function add(LanguageInterface $source, LanguageInterface $target, Reques
    * @param \Drupal\Core\Language\LanguageInterface $language
    *   The language of the translated values. Defaults to the current content
    *   language.
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The request object from which to extract the entity type.
+   * @param \Drupal\Core\Routing\RouteMatchInterface
+   *   The route match object from which to extract the entity type.
    * @param string $entity_type_id
    *   (optional) The entity type ID.
    *
    * @return array
    *   A processed form array ready to be rendered.
    */
-  public function edit(LanguageInterface $language, Request $request, $entity_type_id = NULL) {
-    $entity = $request->attributes->get($entity_type_id);
+  public function edit(LanguageInterface $language, RouteMatchInterface $route_match, $entity_type_id = NULL) {
+    $entity = $route_match->getParameter($entity_type_id);
 
     // @todo Provide a way to figure out the default form operation. Maybe like
     //   $operation = isset($info['default_operation']) ? $info['default_operation'] : 'default';
diff --git a/core/modules/content_translation/src/Form/ContentTranslationDeleteForm.php b/core/modules/content_translation/src/Form/ContentTranslationDeleteForm.php
index b6b16e62bfd9..015ae960de86 100644
--- a/core/modules/content_translation/src/Form/ContentTranslationDeleteForm.php
+++ b/core/modules/content_translation/src/Form/ContentTranslationDeleteForm.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Form\ConfirmFormBase;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Language\LanguageInterface;
 use Drupal\Core\Url;
 
 /**
@@ -40,9 +41,9 @@ public function getFormId() {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, $language = NULL) {
-    $this->entity = $this->getRequest()->attributes->get($entity_type_id);
-    $this->language = language_load($language);
+  public function buildForm(array $form, FormStateInterface $form_state, $entity_type_id = NULL, LanguageInterface $language = NULL) {
+    $this->entity = $this->getRouteMatch()->getParameter($entity_type_id);
+    $this->language = $language;
     return parent::buildForm($form, $form_state);
   }
 
diff --git a/core/modules/field_ui/src/Controller/FieldConfigListController.php b/core/modules/field_ui/src/Controller/FieldConfigListController.php
index 8ed9be080c1e..4f1a3f0d397f 100644
--- a/core/modules/field_ui/src/Controller/FieldConfigListController.php
+++ b/core/modules/field_ui/src/Controller/FieldConfigListController.php
@@ -8,6 +8,7 @@
 namespace Drupal\field_ui\Controller;
 
 use Drupal\Core\Entity\Controller\EntityListController;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -22,18 +23,18 @@ class FieldConfigListController extends EntityListController {
    *   The entity type.
    * @param string $bundle
    *   The entity bundle.
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The current request.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    *
    * @return array
    *   A render array as expected by drupal_render().
    */
-  public function listing($entity_type_id = NULL, $bundle = NULL, Request $request = NULL) {
+  public function listing($entity_type_id = NULL, $bundle = NULL, RouteMatchInterface $route_match = NULL) {
     if (!$bundle) {
       $entity_info = $this->entityManager()->getDefinition($entity_type_id);
-      $bundle = $request->attributes->get('_raw_variables')->get($entity_info->getBundleEntityType());
+      $bundle = $route_match->getRawParameter($entity_info->getBundleEntityType());
     }
-    return $this->entityManager()->getListBuilder('field_config')->render($entity_type_id, $bundle, $request);
+    return $this->entityManager()->getListBuilder('field_config')->render($entity_type_id, $bundle);
   }
 
 }
diff --git a/core/modules/field_ui/src/Form/FieldStorageAddForm.php b/core/modules/field_ui/src/Form/FieldStorageAddForm.php
index e9f15a7cfe88..f4f2358b4f07 100644
--- a/core/modules/field_ui/src/Form/FieldStorageAddForm.php
+++ b/core/modules/field_ui/src/Form/FieldStorageAddForm.php
@@ -122,7 +122,7 @@ public function buildForm(array $form, FormStateInterface $form_state, $entity_t
       $form_state->set('entity_type_id', $entity_type_id);
     }
     if (!$form_state->get('bundle')) {
-      $bundle = $bundle ?: $this->getRequest()->attributes->get('_raw_variables')->get($this->bundleEntityTypeId);
+      $bundle = $bundle ?: $this->getRouteMatch()->getRawParameter($this->bundleEntityTypeId);
       $form_state->set('bundle', $bundle);
     }
 
diff --git a/core/modules/node/src/Plugin/views/argument_default/Node.php b/core/modules/node/src/Plugin/views/argument_default/Node.php
index f1be8d69b64b..3df56fb4e8a9 100644
--- a/core/modules/node/src/Plugin/views/argument_default/Node.php
+++ b/core/modules/node/src/Plugin/views/argument_default/Node.php
@@ -7,9 +7,11 @@
 
 namespace Drupal\node\Plugin\views\argument_default;
 
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 use Drupal\node\NodeInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Default argument plugin to extract a node.
@@ -23,11 +25,49 @@
  */
 class Node extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
 
+  /**
+   * The route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
+  /**
+   * Constructs a new Date instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   *
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->routeMatch = $route_match;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('current_route_match')
+    );
+  }
+
   /**
    * {@inheritdoc}
    */
   public function getArgument() {
-    if (($node = $this->view->getRequest()->attributes->get('node')) && $node instanceof NodeInterface) {
+    if (($node = $this->routeMatch->getParameter('node')) && $node instanceof NodeInterface) {
       return $node->id();
     }
   }
diff --git a/core/modules/rest/src/RequestHandler.php b/core/modules/rest/src/RequestHandler.php
index c31600d0c8ff..0ddfdd729772 100644
--- a/core/modules/rest/src/RequestHandler.php
+++ b/core/modules/rest/src/RequestHandler.php
@@ -31,11 +31,13 @@ class RequestHandler implements ContainerAwareInterface {
    *   The route match.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The HTTP request object.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
    *
    * @return \Symfony\Component\HttpFoundation\Response
    *   The response object.
    */
-  public function handle(RouteMatchInterface $route_match, Request $request) {
+  public function handle(RouteMatchInterface $route_match, Request $request, RouteMatchInterface $route_match) {
 
     $plugin = $route_match->getRouteObject()->getDefault('_plugin');
     $method = strtolower($request->getMethod());
@@ -76,7 +78,7 @@ public function handle(RouteMatchInterface $route_match, Request $request) {
 
     // Determine the request parameters that should be passed to the resource
     // plugin.
-    $route_parameters = $request->attributes->get('_route_params');
+    $route_parameters = $route_match->getParameters();
     $parameters = array();
     // Filter out all internal parameters starting with "_".
     foreach ($route_parameters as $key => $parameter) {
diff --git a/core/modules/system/entity.api.php b/core/modules/system/entity.api.php
index 189e8a2c82e3..6a970602fc01 100644
--- a/core/modules/system/entity.api.php
+++ b/core/modules/system/entity.api.php
@@ -893,8 +893,8 @@ function hook_ENTITY_TYPE_storage_load(array $entities) {
  */
 function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  if ($entity instanceof ContentEntityInterface && $entity->isTranslatable()) {
-   $attributes = \Drupal::request()->attributes;
-   \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $attributes->get('source_langcode'));
+   $route_match = \Drupal::routeMatch();
+   \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
   }
 }
 
@@ -909,8 +909,8 @@ function hook_entity_presave(Drupal\Core\Entity\EntityInterface $entity) {
  */
 function hook_ENTITY_TYPE_presave(Drupal\Core\Entity\EntityInterface $entity) {
   if ($entity->isTranslatable()) {
-    $attributes = \Drupal::request()->attributes;
-    \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $attributes->get('source_langcode'));
+    $route_match = \Drupal::routeMatch();
+    \Drupal::service('content_translation.synchronizer')->synchronizeFields($entity, $entity->language()->getId(), $route_match->getParameter('source_langcode'));
   }
 }
 
diff --git a/core/modules/system/src/PathBasedBreadcrumbBuilder.php b/core/modules/system/src/PathBasedBreadcrumbBuilder.php
index 1075ee7cad82..05693312e109 100644
--- a/core/modules/system/src/PathBasedBreadcrumbBuilder.php
+++ b/core/modules/system/src/PathBasedBreadcrumbBuilder.php
@@ -14,10 +14,12 @@
 use Drupal\Core\Link;
 use Drupal\Core\ParamConverter\ParamNotConvertedException;
 use Drupal\Core\PathProcessor\InboundPathProcessorInterface;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Drupal\Component\Utility\Unicode;
+use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
@@ -139,9 +141,10 @@ public function build(RouteMatchInterface $route_match) {
       // Copy the path elements for up-casting.
       $route_request = $this->getRequestForPath(implode('/', $path_elements), $exclude);
       if ($route_request) {
-        $access = $this->accessManager->checkRequest($route_request, $this->currentUser);
+        $route_match = RouteMatch::createFromRequest($route_request);
+        $access = $this->accessManager->check($route_match, $this->currentUser);
         if ($access) {
-          $title = $this->titleResolver->getTitle($route_request, $route_request->attributes->get(RouteObjectInterface::ROUTE_OBJECT));
+          $title = $this->titleResolver->getTitle($route_request, $route_match->getRouteObject());
         }
         if ($access) {
           if (!isset($title)) {
@@ -149,7 +152,8 @@ public function build(RouteMatchInterface $route_match) {
             // route is missing a _title or _title_callback attribute.
             $title = str_replace(array('-', '_'), ' ', Unicode::ucfirst(end($path_elements)));
           }
-          $links[] = Link::createFromRoute($title, $route_request->attributes->get(RouteObjectInterface::ROUTE_NAME), $route_request->attributes->get('_raw_variables')->all());
+          $url = Url::fromRouteMatch($route_match);
+          $links[] = new Link($title, $url);
         }
       }
 
diff --git a/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php b/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php
index 00619ef25f44..bf5fa29053a4 100644
--- a/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php
+++ b/core/modules/system/tests/modules/entity_test/src/Controller/EntityTestController.php
@@ -10,8 +10,8 @@
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Controller\ControllerBase;
 use Drupal\Core\Entity\Query\QueryFactory;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Controller routines for entity_test routes.
@@ -65,8 +65,8 @@ public function testAdd($entity_type_id) {
   /**
    * Displays the 'Edit existing entity_test' form.
    *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The request object to get entity type from.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match object to get entity type from.
    * @param string $entity_type_id
    *   The entity type ID.
    *
@@ -75,8 +75,8 @@ public function testAdd($entity_type_id) {
    *
    * @see \Drupal\entity_test\Routing\EntityTestRoutes::routes()
    */
-  public function testEdit(Request $request, $entity_type_id) {
-    $entity = $request->attributes->get($entity_type_id);
+  public function testEdit(RouteMatchInterface $route_match, $entity_type_id) {
+    $entity = $route_match->getParameter($entity_type_id);
     $form = $this->entityFormBuilder()->getForm($entity);
     $form['#title'] = $entity->label();
     return $form;
diff --git a/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php b/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
index a3e506434287..1b96b3da093d 100644
--- a/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
+++ b/core/modules/system/tests/modules/form_test/src/FormTestControllerObject.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Provides a test form object.
@@ -34,11 +35,11 @@ public static function create(ContainerInterface $container) {
   /**
    * {@inheritdoc}
    */
-  public function buildForm(array $form, FormStateInterface $form_state, $custom_attributes = NULL) {
+  public function buildForm(array $form, FormStateInterface $form_state, Request $request = NULL, $custom_attributes = NULL) {
     $form['element'] = array('#markup' => 'The FormTestControllerObject::buildForm() method was used for this form.');
 
     $form['custom_attribute']['#markup'] = $custom_attributes;
-    $form['request_attribute']['#markup'] = $this->getRequest()->attributes->get('request_attribute');
+    $form['request_attribute']['#markup'] = $request->attributes->get('request_attribute');
 
     $form['bananas'] = array(
       '#type' => 'textfield',
diff --git a/core/modules/system/tests/modules/paramconverter_test/src/TestControllers.php b/core/modules/system/tests/modules/paramconverter_test/src/TestControllers.php
index 33f52fcfad9b..282261232fcd 100644
--- a/core/modules/system/tests/modules/paramconverter_test/src/TestControllers.php
+++ b/core/modules/system/tests/modules/paramconverter_test/src/TestControllers.php
@@ -9,15 +9,13 @@
 
 use Drupal\Core\Entity\EntityInterface;
 use Drupal\node\NodeInterface;
-use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Controller routine for testing the paramconverter.
  */
 class TestControllers {
 
-  public function testUserNodeFoo(EntityInterface $user, NodeInterface $node, Request $request) {
-    $foo = $request->attributes->get('foo');
+  public function testUserNodeFoo(EntityInterface $user, NodeInterface $node, $foo) {
     $foo = is_object($foo) ? $foo->label() : $foo;
     return ['#markup' => "user: {$user->label()}, node: {$node->label()}, foo: $foo"];
   }
diff --git a/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php b/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
index 8ceea8ac9ea6..7daf8c2fa9c2 100644
--- a/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
+++ b/core/modules/system/tests/src/Unit/Breadcrumbs/PathBasedBreadcrumbBuilderTest.php
@@ -326,8 +326,8 @@ public function testBuildWithUserPath() {
    */
   public function setupAccessManagerToAllow() {
     $this->accessManager->expects($this->any())
-      ->method('checkRequest')
-      ->will($this->returnValue(AccessResult::allowed()));
+      ->method('check')
+      ->willReturn(TRUE);
   }
 
   protected function setupStubPathProcessor() {
diff --git a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
index 2cd7a13430f1..a90b5e193054 100644
--- a/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
+++ b/core/modules/taxonomy/src/Plugin/views/argument_default/Tid.php
@@ -8,6 +8,7 @@
 namespace Drupal\taxonomy\Plugin\views\argument_default;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\taxonomy\TermInterface;
 use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\ViewExecutable;
@@ -27,6 +28,44 @@
  */
 class Tid extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
 
+  /**
+   * The route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
+  /**
+   * Constructs a new Date instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   *
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->routeMatch = $route_match;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('current_route_match')
+    );
+  }
+
   /**
    * Overrides \Drupal\views\Plugin\views\Plugin\views\PluginBase::init().
    */
@@ -126,14 +165,14 @@ public function submitOptionsForm(&$form, FormStateInterface $form_state, &$opti
   public function getArgument() {
     // Load default argument from taxonomy page.
     if (!empty($this->options['term_page'])) {
-      if (($taxonomy_term = $this->view->getRequest()->attributes->get('taxonomy_term')) && $taxonomy_term instanceof TermInterface) {
+      if (($taxonomy_term = $this->routeMatch->getParameter('taxonomy_term')) && $taxonomy_term instanceof TermInterface) {
         return $taxonomy_term->id();
       }
     }
     // Load default argument from node.
     if (!empty($this->options['node'])) {
       // Just check, if a node could be detected.
-      if (($node = $this->view->getRequest()->attributes->get('node')) && $node instanceof NodeInterface) {
+      if (($node = $this->routeMatch->getParameter('node')) && $node instanceof NodeInterface) {
         $taxonomy = array();
         foreach ($node->getFieldDefinitions() as $field) {
           if ($field->getType() == 'taxonomy_term_reference') {
diff --git a/core/modules/update/update.module b/core/modules/update/update.module
index a3d92f517725..c44598661962 100644
--- a/core/modules/update/update.module
+++ b/core/modules/update/update.module
@@ -119,7 +119,8 @@ function update_help($route_name, RouteMatchInterface $route_match) {
 function update_page_top() {
   /** @var \Drupal\Core\Routing\AdminContext $admin_context */
   $admin_context = \Drupal::service('router.admin_context');
-  if ($admin_context->isAdminRoute(\Drupal::request()->attributes->get(RouteObjectInterface::ROUTE_OBJECT)) && \Drupal::currentUser()->hasPermission('administer site configuration')) {
+  $route_match = \Drupal::routeMatch();
+  if ($admin_context->isAdminRoute($route_match->getRouteObject()) && \Drupal::currentUser()->hasPermission('administer site configuration')) {
     $route_name = \Drupal::routeMatch()->getRouteName();
     switch ($route_name) {
       // These pages don't need additional nagging.
diff --git a/core/modules/user/src/Plugin/Block/UserLoginBlock.php b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
index 47177a52f4b1..9e666768c1f2 100644
--- a/core/modules/user/src/Plugin/Block/UserLoginBlock.php
+++ b/core/modules/user/src/Plugin/Block/UserLoginBlock.php
@@ -7,11 +7,13 @@
 
 namespace Drupal\user\Plugin\Block;
 
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\UrlGeneratorTrait;
 use Drupal\Core\Url;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Block\BlockBase;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Provides a 'User login' block.
@@ -22,15 +24,56 @@
  *   category = @Translation("Forms")
  * )
  */
-class UserLoginBlock extends BlockBase {
+class UserLoginBlock extends BlockBase implements ContainerFactoryPluginInterface {
 
   use UrlGeneratorTrait;
 
+  /**
+   * The route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
+  /**
+   * Constructs a new UserLoginBlock instance.
+   *
+   * @param array $configuration
+   *   The plugin configuration, i.e. an array with configuration values keyed
+   *   by configuration option name. The special key 'context' may be used to
+   *   initialize the defined contexts by setting it to an array of context
+   *   values keyed by context names.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->routeMatch = $route_match;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('current_route_match')
+    );
+  }
+
+
   /**
    * {@inheritdoc}
    */
   protected function blockAccess(AccountInterface $account) {
-    $route_name = \Drupal::request()->attributes->get(RouteObjectInterface::ROUTE_NAME);
+    $route_name = $this->routeMatch->getRouteName();
     return ($account->isAnonymous() && !in_array($route_name, array('user.register', 'user.login', 'user.logout')));
   }
 
diff --git a/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php b/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
index 7e1783207743..17b3cd69fabd 100644
--- a/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
+++ b/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
@@ -10,6 +10,8 @@
 use Drupal\Core\PathProcessor\PathProcessorManager;
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Routing\AdminContext;
+use Drupal\Core\Routing\RouteMatch;
+use Drupal\Core\Routing\StackedRouteMatchInterface;
 use Drupal\language\LanguageNegotiationMethodBase;
 use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -60,6 +62,13 @@ class LanguageNegotiationUserAdmin extends LanguageNegotiationMethodBase impleme
    */
   protected $pathProcessorManager;
 
+  /**
+   * The stacked route match.
+   *
+   * @var \Drupal\Core\Routing\StackedRouteMatchInterface
+   */
+  protected $stackedRouteMatch;
+
   /**
    * Constructs a new LanguageNegotiationUserAdmin instance.
    *
@@ -69,11 +78,14 @@ class LanguageNegotiationUserAdmin extends LanguageNegotiationMethodBase impleme
    *   The router.
    * @param \Drupal\Core\PathProcessor\PathProcessorManager $path_processor_manager
    *   The path processor manager.
+   * @param \Drupal\Core\Routing\StackedRouteMatchInterface $stacked_route_match
+   *   The stacked route match.
    */
-  public function __construct(AdminContext $admin_context, UrlMatcherInterface $router, PathProcessorManager $path_processor_manager) {
+  public function __construct(AdminContext $admin_context, UrlMatcherInterface $router, PathProcessorManager $path_processor_manager, StackedRouteMatchInterface $stacked_route_match) {
     $this->adminContext = $admin_context;
     $this->router = $router;
     $this->pathProcessorManager = $path_processor_manager;
+    $this->stackedRouteMatch = $stacked_route_match;
   }
 
   /**
@@ -83,7 +95,8 @@ public static function create(ContainerInterface $container, array $configuratio
     return new static(
       $container->get('router.admin_context'),
       $container->get('router'),
-      $container->get('path_processor_manager')
+      $container->get('path_processor_manager'),
+      $container->get('current_route_match')
     );
   }
 
@@ -117,7 +130,8 @@ protected function isAdminPath(Request $request) {
       // If called from an event subscriber, the request may not have the route
       // object yet (it is still being built), so use the router to look up
       // based on the path.
-      if (!$route_object = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT)) {
+      $route_match = $this->stackedRouteMatch->getRouteMatchFromRequest($request);
+      if ($route_match && !$route_object = $route_match->getRouteObject()) {
         try {
           // Process the path as an inbound path. This will remove any language
           // prefixes and other path components that inbound processing would
diff --git a/core/modules/user/src/Plugin/views/argument_default/User.php b/core/modules/user/src/Plugin/views/argument_default/User.php
index 850ee2ff77f2..77fa69f83841 100644
--- a/core/modules/user/src/Plugin/views/argument_default/User.php
+++ b/core/modules/user/src/Plugin/views/argument_default/User.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Plugin\views\argument_default;
 
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\views\Plugin\CacheablePluginInterface;
 use Drupal\views\Plugin\views\argument_default\ArgumentDefaultPluginBase;
 use Symfony\Component\DependencyInjection\ContainerInterface;
@@ -25,6 +26,44 @@
  */
 class User extends ArgumentDefaultPluginBase implements CacheablePluginInterface {
 
+  /**
+   * The route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
+  /**
+   * Constructs a new Date instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   *
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->routeMatch = $route_match;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('current_route_match')
+    );
+  }
+
   /**
    * {@inheritdoc}
    */
@@ -52,16 +91,14 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
   public function getArgument() {
 
     // If there is a user object in the current route.
-    if ($this->view->getRequest()->attributes->has('user')) {
-      $user = $this->view->getRequest()->attributes->get('user');
+    if ($user = $this->routeMatch->getParameter('user')) {
       if ($user instanceof UserInterface) {
         return $user->id();
       }
     }
 
     // If option to use node author; and node in current route.
-    if (!empty($this->options['user']) && $this->view->getRequest()->attributes->has('node')) {
-      $node = $this->view->getRequest()->attributes->get('node');
+    if (!empty($this->options['user']) && $node = $this->routeMatch->getParameter('node')) {
       if ($node instanceof NodeInterface) {
         return $node->getOwnerId();
       }
diff --git a/core/modules/views/src/Plugin/views/argument/Date.php b/core/modules/views/src/Plugin/views/argument/Date.php
index 3a3db7f01e34..457a0dff957f 100644
--- a/core/modules/views/src/Plugin/views/argument/Date.php
+++ b/core/modules/views/src/Plugin/views/argument/Date.php
@@ -9,6 +9,8 @@
 
 use Drupal\Core\Database\Database;
 use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -29,7 +31,7 @@
  *
  * @ViewsArgument("date")
  */
-class Date extends Formula {
+class Date extends Formula implements ContainerFactoryPluginInterface {
 
   /**
    * The date format used in the title.
@@ -47,6 +49,44 @@ class Date extends Formula {
 
   var $option_name = 'default_argument_date';
 
+  /**
+   * The route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
+  /**
+   * Constructs a new Date instance.
+   *
+   * @param array $configuration
+   *   A configuration array containing information about the plugin instance.
+   * @param string $plugin_id
+   *   The plugin_id for the plugin instance.
+   * @param mixed $plugin_definition
+   *   The plugin implementation definition.
+   *
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The route match.
+   */
+  public function __construct(array $configuration, $plugin_id, $plugin_definition, RouteMatchInterface $route_match) {
+    parent::__construct($configuration, $plugin_id, $plugin_definition);
+
+    $this->routeMatch = $route_match;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+    return new static(
+      $configuration,
+      $plugin_id,
+      $plugin_definition,
+      $container->get('current_route_match')
+    );
+  }
+
   /**
    * Add an option to set the default value to the current date.
    */
@@ -66,7 +106,7 @@ public function getDefaultArgument($raw = FALSE) {
       return date($this->argFormat, REQUEST_TIME);
     }
     elseif (!$raw && in_array($this->options['default_argument_type'], array('node_created', 'node_changed'))) {
-      $node = $this->view->getRequest()->attributes->get('node');
+      $node = $this->routeMatch->getParameter('node');
 
       if (!($node instanceof NodeInterface)) {
         return parent::getDefaultArgument();
diff --git a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
index a49740df347a..ce4c25b00631 100644
--- a/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
+++ b/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php
@@ -2582,7 +2582,7 @@ public function getSpecialBlocks() {
    */
   public function viewExposedFormBlocks() {
     // Avoid interfering with the admin forms.
-    $route_name = \Drupal::request()->attributes->get(RouteObjectInterface::ROUTE_NAME);
+    $route_name = \Drupal::routeMatch()->getRouteName();
     if (strpos($route_name, 'views_ui.') === 0) {
       return;
     }
diff --git a/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php b/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
index 91491c8cccb1..d015a31c06f2 100644
--- a/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
+++ b/core/tests/Drupal/Tests/Core/Controller/ControllerResolverTest.php
@@ -74,8 +74,8 @@ public function testGetArguments() {
     ));
     $arguments = $this->controllerResolver->getArguments($request, $controller);
 
-    $this->assertEquals($mock_entity, $arguments[0], 'Type hinted variables should use upcasted values.');
-    $this->assertEquals(1, $arguments[1], 'Not type hinted variables should use not upcasted values.');
+    $this->assertEquals($mock_entity, $arguments[0]);
+    $this->assertEquals($mock_account, $arguments[1]);
     $this->assertEquals(RouteMatch::createFromRequest($request), $arguments[2], 'Ensure that the route match object is passed along as well');
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Routing/CurrentRouteMatchTest.php b/core/tests/Drupal/Tests/Core/Routing/CurrentRouteMatchTest.php
index 3293b84cc172..1d2942d48e5d 100644
--- a/core/tests/Drupal/Tests/Core/Routing/CurrentRouteMatchTest.php
+++ b/core/tests/Drupal/Tests/Core/Routing/CurrentRouteMatchTest.php
@@ -78,4 +78,38 @@ public function testGetCurrentRouteObject() {
     $this->assertSame('1', $current_route_match->getParameter('foo'));
   }
 
+  /**
+   * @covers ::getRouteMatchFromRequest
+   */
+  public function testGetRouteMatchFromRequestWithRouting() {
+    $request_stack = new RequestStack();
+    $request = new Request();
+    $request_stack->push($request);
+    $current_route_match = new CurrentRouteMatch($request_stack);
+
+    $route_match = $current_route_match->getRouteMatchFromRequest($request);
+
+    $this->assertNull($route_match->getRouteName());
+    $this->assertNull($route_match->getRouteObject());
+  }
+
+  /**
+   * @covers ::getRouteMatchFromRequest
+   */
+  public function testGetRouteMatchFromRequest() {
+    $request_stack = new RequestStack();
+    $request = new Request();
+    $request_stack->push($request);
+    $route = new Route('/test-route/{foo}');
+
+    $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'test_route');
+    $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, $route);
+    $request->attributes->set('foo', '1');
+    $current_route_match = new CurrentRouteMatch($request_stack);
+
+    $route_match = $current_route_match->getRouteMatchFromRequest($request);
+    $this->assertEquals('test_route', $route_match->getRouteName());
+    $this->assertEquals($route, $route_match->getRouteObject());
+  }
+
 }
-- 
GitLab