From c42230523442af8ecebcf697cf32cd5c1634b45c Mon Sep 17 00:00:00 2001
From: Nathaniel Catchpole <catch@35733.no-reply.drupal.org>
Date: Mon, 5 Jan 2015 13:47:21 +0000
Subject: [PATCH] Issue #2294157 by tim.plunkett, dawehner: Switch getOptions()
 and getRouteParameters() within LocalActionInterface and LocalTaskInterface
 to use RouteMatch

---
 core/core.services.yml                        |  4 +--
 .../Drupal/Core/Menu/LocalActionDefault.php   | 12 ++++---
 .../Drupal/Core/Menu/LocalActionInterface.php | 14 ++++----
 .../Drupal/Core/Menu/LocalActionManager.php   | 19 +++++++---
 .../lib/Drupal/Core/Menu/LocalTaskDefault.php | 11 +++---
 .../Drupal/Core/Menu/LocalTaskInterface.php   | 14 ++++----
 .../lib/Drupal/Core/Menu/LocalTaskManager.php | 25 +++++++++----
 .../BlockContentAddLocalAction.php            | 17 ++++-----
 .../Plugin/Menu/LocalAction/MenuLinkAdd.php   | 19 ++++------
 .../src/Plugin/Menu/UserTrackerTab.php        |  4 +--
 .../Core/Menu/LocalActionManagerTest.php      |  7 ++--
 .../Tests/Core/Menu/LocalTaskDefaultTest.php  | 36 +++++++++----------
 .../Tests/Core/Menu/LocalTaskManagerTest.php  | 10 +++++-
 13 files changed, 106 insertions(+), 86 deletions(-)

diff --git a/core/core.services.yml b/core/core.services.yml
index 75198f28dd19..fca639539695 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -367,10 +367,10 @@ services:
     arguments: ['@menu.link_tree', '@entity.manager', '@string_translation']
   plugin.manager.menu.local_action:
     class: Drupal\Core\Menu\LocalActionManager
-    arguments: ['@controller_resolver', '@request_stack', '@router.route_provider', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user']
+    arguments: ['@controller_resolver', '@request_stack', '@current_route_match', '@router.route_provider', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user']
   plugin.manager.menu.local_task:
     class: Drupal\Core\Menu\LocalTaskManager
-    arguments: ['@controller_resolver', '@request_stack', '@router.route_provider', '@router.builder', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user']
+    arguments: ['@controller_resolver', '@request_stack', '@current_route_match', '@router.route_provider', '@router.builder', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user']
   plugin.manager.menu.contextual_link:
     class: Drupal\Core\Menu\ContextualLinkManager
     arguments: ['@controller_resolver', '@module_handler', '@cache.discovery', '@language_manager', '@access_manager', '@current_user', '@request_stack']
diff --git a/core/lib/Drupal/Core/Menu/LocalActionDefault.php b/core/lib/Drupal/Core/Menu/LocalActionDefault.php
index d5b722905cd2..b830a2fa105f 100644
--- a/core/lib/Drupal/Core/Menu/LocalActionDefault.php
+++ b/core/lib/Drupal/Core/Menu/LocalActionDefault.php
@@ -9,6 +9,7 @@
 
 use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
 use Drupal\Core\Plugin\PluginBase;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpFoundation\Request;
@@ -88,7 +89,7 @@ public function getWeight() {
   /**
    * {@inheritdoc}
    */
-  public function getRouteParameters(Request $request) {
+  public function getRouteParameters(RouteMatchInterface $route_match) {
     $parameters = isset($this->pluginDefinition['route_parameters']) ? $this->pluginDefinition['route_parameters'] : array();
     $route = $this->routeProvider->getRouteByName($this->getRouteName());
     $variables = $route->compile()->getVariables();
@@ -99,7 +100,7 @@ public function getRouteParameters(Request $request) {
     // slugs in the path patterns. For example, if the route's path pattern is
     // /filter/tips/{filter_format} and the path is /filter/tips/plain_text then
     // $raw_variables->get('filter_format') == 'plain_text'.
-    $raw_variables = $request->attributes->get('_raw_variables');
+    $raw_variables = $route_match->getRawParameters();
 
     foreach ($variables as $name) {
       if (isset($parameters[$name])) {
@@ -109,8 +110,8 @@ public function getRouteParameters(Request $request) {
       if ($raw_variables && $raw_variables->has($name)) {
         $parameters[$name] = $raw_variables->get($name);
       }
-      elseif ($request->attributes->has($name)) {
-        $parameters[$name] = $request->attributes->get($name);
+      elseif ($value = $route_match->getRawParameter($name)) {
+        $parameters[$name] = $value;
       }
     }
     // The UrlGenerator will throw an exception if expected parameters are
@@ -121,7 +122,8 @@ public function getRouteParameters(Request $request) {
   /**
    * {@inheritdoc}
    */
-  public function getOptions(Request $request) {
+  public function getOptions(RouteMatchInterface $route_match) {
     return (array) $this->pluginDefinition['options'];
   }
+
 }
diff --git a/core/lib/Drupal/Core/Menu/LocalActionInterface.php b/core/lib/Drupal/Core/Menu/LocalActionInterface.php
index e6b5e583c298..57d441af7b2a 100644
--- a/core/lib/Drupal/Core/Menu/LocalActionInterface.php
+++ b/core/lib/Drupal/Core/Menu/LocalActionInterface.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Menu;
 
-use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Defines an interface for menu local actions.
@@ -25,13 +25,13 @@ public function getRouteName();
   /**
    * Returns the route parameters needed to render a link for the local action.
    *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The HttpRequest object representing the current request.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    *
    * @return array
    *   An array of parameter names and values.
    */
-  public function getRouteParameters(Request $request);
+  public function getRouteParameters(RouteMatchInterface $route_match);
 
   /**
    * Returns the weight for the local action.
@@ -43,13 +43,13 @@ public function getWeight();
   /**
    * Returns options for rendering a link for the local action.
    *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The HTTP request object representing the current request.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    *
    * @return array
    *   An associative array of options.
    */
-  public function getOptions(Request $request);
+  public function getOptions(RouteMatchInterface $route_match);
 
   /**
    * Returns the localized title to be shown for this action.
diff --git a/core/lib/Drupal/Core/Menu/LocalActionManager.php b/core/lib/Drupal/Core/Menu/LocalActionManager.php
index 68550bc86992..208075c41a0c 100644
--- a/core/lib/Drupal/Core/Menu/LocalActionManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalActionManager.php
@@ -15,6 +15,7 @@
 use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
 use Drupal\Core\Plugin\Discovery\YamlDiscovery;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Url;
 use Symfony\Component\HttpFoundation\RequestStack;
@@ -64,6 +65,13 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
    */
   protected $requestStack;
 
+  /**
+   * The current route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
   /**
    * The route provider to load routes by name.
    *
@@ -99,6 +107,8 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
    *   An object to use in introspecting route methods.
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request stack.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
    *   The route provider.
    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
@@ -112,7 +122,7 @@ class LocalActionManager extends DefaultPluginManager implements LocalActionMana
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The current user.
    */
-  public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
+  public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteMatchInterface $route_match, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
     // Skip calling the parent constructor, since that assumes annotation-based
     // discovery.
     $this->discovery = new YamlDiscovery('links.action', $module_handler->getModuleDirectories());
@@ -120,6 +130,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re
     $this->factory = new ContainerFactory($this, 'Drupal\Core\Menu\LocalActionInterface');
     $this->controllerResolver = $controller_resolver;
     $this->requestStack = $request_stack;
+    $this->routeMatch = $route_match;
     $this->routeProvider = $route_provider;
     $this->accessManager = $access_manager;
     $this->moduleHandler = $module_handler;
@@ -159,16 +170,16 @@ public function getActionsForRoute($route_appears) {
       }
     }
     $links = array();
-    $request = $this->requestStack->getCurrentRequest();
+    /** @var $plugin \Drupal\Core\Menu\LocalActionInterface */
     foreach ($this->instances[$route_appears] as $plugin_id => $plugin) {
       $route_name = $plugin->getRouteName();
-      $route_parameters = $plugin->getRouteParameters($request);
+      $route_parameters = $plugin->getRouteParameters($this->routeMatch);
       $links[$plugin_id] = array(
         '#theme' => 'menu_local_action',
         '#link' => array(
           'title' => $this->getTitle($plugin),
           'url' => Url::fromRoute($route_name, $route_parameters),
-          'localized_options' => $plugin->getOptions($request),
+          'localized_options' => $plugin->getOptions($this->routeMatch),
         ),
         '#access' => $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account),
         '#weight' => $plugin->getWeight(),
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
index 45e0f77267ff..615eaa4ecc31 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php
@@ -8,6 +8,7 @@
 namespace Drupal\Core\Menu;
 
 use Drupal\Core\Plugin\PluginBase;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -39,7 +40,7 @@ public function getRouteName() {
   /**
    * {@inheritdoc}
    */
-  public function getRouteParameters(Request $request) {
+  public function getRouteParameters(RouteMatchInterface $route_match) {
     $parameters = isset($this->pluginDefinition['route_parameters']) ? $this->pluginDefinition['route_parameters'] : array();
     $route = $this->routeProvider()->getRouteByName($this->getRouteName());
     $variables = $route->compile()->getVariables();
@@ -51,7 +52,7 @@ public function getRouteParameters(Request $request) {
     // /filter/tips/{filter_format} and the path is /filter/tips/plain_text then
     // $raw_variables->get('filter_format') == 'plain_text'.
 
-    $raw_variables = $request->attributes->get('_raw_variables');
+    $raw_variables = $route_match->getRawParameters();
 
     foreach ($variables as $name) {
       if (isset($parameters[$name])) {
@@ -61,8 +62,8 @@ public function getRouteParameters(Request $request) {
       if ($raw_variables && $raw_variables->has($name)) {
         $parameters[$name] = $raw_variables->get($name);
       }
-      elseif ($request->attributes->has($name)) {
-        $parameters[$name] = $request->attributes->get($name);
+      elseif ($value = $route_match->getRawParameter($name)) {
+        $parameters[$name] = $value;
       }
     }
     // The UrlGenerator will throw an exception if expected parameters are
@@ -109,7 +110,7 @@ public function getWeight() {
   /**
    * {@inheritdoc}
    */
-  public function getOptions(Request $request) {
+  public function getOptions(RouteMatchInterface $route_match) {
     $options = $this->pluginDefinition['options'];
     if ($this->active) {
       if (empty($options['attributes']['class']) || !in_array('active', $options['attributes']['class'])) {
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskInterface.php b/core/lib/Drupal/Core/Menu/LocalTaskInterface.php
index 8064596749c9..6330d2274abe 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskInterface.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskInterface.php
@@ -7,7 +7,7 @@
 
 namespace Drupal\Core\Menu;
 
-use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Defines an interface for menu local tasks.
@@ -36,13 +36,13 @@ public function getTitle();
   /**
    * Returns the route parameters needed to render a link for the local task.
    *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The HttpRequest object representing the current request.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    *
    * @return array
    *   An array of parameter names and values.
    */
-  public function getRouteParameters(Request $request);
+  public function getRouteParameters(RouteMatchInterface $route_match);
 
   /**
    * Returns the weight of the local task.
@@ -55,13 +55,13 @@ public function getWeight();
   /**
    * Returns options for rendering a link to the local task.
    *
-   * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The HttpRequest object representing the current request.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    *
    * @return array
    *   An associative array of options.
    */
-  public function getOptions(Request $request);
+  public function getOptions(RouteMatchInterface $route_match);
 
   /**
    * Sets the active status.
diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
index 5b85d7ff4dc3..997c6db0d763 100644
--- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php
+++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Access\AccessManagerInterface;
 use Drupal\Core\Cache\Cache;
 use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Cache\NullBackend;
 use Drupal\Core\Controller\ControllerResolverInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\LanguageManagerInterface;
@@ -19,6 +20,7 @@
 use Drupal\Core\Plugin\Discovery\YamlDiscovery;
 use Drupal\Core\Plugin\Factory\ContainerFactory;
 use Drupal\Core\Routing\RouteBuilderInterface;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Url;
@@ -67,6 +69,13 @@ class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerI
    */
   protected $requestStack;
 
+  /**
+   * The current route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
+  protected $routeMatch;
+
   /**
    * The plugin instances.
    *
@@ -109,6 +118,8 @@ class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerI
    *   An object to use in introspecting route methods.
    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
    *   The request object to use for building titles and paths for plugin instances.
+   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
+   *   The current route match.
    * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider
    *   The route provider to load routes by name.
    * @param \Drupal\Core\Routing\RouteBuilderInterface $route_builder
@@ -124,12 +135,13 @@ class LocalTaskManager extends DefaultPluginManager implements LocalTaskManagerI
    * @param \Drupal\Core\Session\AccountInterface $account
    *   The current user.
    */
-  public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteProviderInterface $route_provider, RouteBuilderInterface $route_builder, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
+  public function __construct(ControllerResolverInterface $controller_resolver, RequestStack $request_stack, RouteMatchInterface $route_match, RouteProviderInterface $route_provider, RouteBuilderInterface $route_builder, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManagerInterface $language_manager, AccessManagerInterface $access_manager, AccountInterface $account) {
     $this->discovery = new YamlDiscovery('links.task', $module_handler->getModuleDirectories());
     $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
     $this->factory = new ContainerFactory($this, '\Drupal\Core\Menu\LocalTaskInterface');
     $this->controllerResolver = $controller_resolver;
     $this->requestStack = $request_stack;
+    $this->routeMatch = $route_match;
     $this->routeProvider = $route_provider;
     $this->routeBuilder = $route_builder;
     $this->accessManager = $access_manager;
@@ -289,11 +301,11 @@ public function getTasksBuild($current_route_name) {
     // of SQL queries that would otherwise be triggered by the access manager.
     $routes = $route_names ? $this->routeProvider->getRoutesByNames($route_names) : array();
 
-    $request = $this->requestStack->getCurrentRequest();
     foreach ($tree as $level => $instances) {
+      /** @var $instances \Drupal\Core\Menu\LocalTaskInterface[] */
       foreach ($instances as $plugin_id => $child) {
         $route_name = $child->getRouteName();
-        $route_parameters = $child->getRouteParameters($request);
+        $route_parameters = $child->getRouteParameters($this->routeMatch);
 
         // Find out whether the user has access to the task.
         $access = $this->accessManager->checkNamedRoute($route_name, $route_parameters, $this->account);
@@ -308,7 +320,7 @@ public function getTasksBuild($current_route_name) {
           $link = array(
             'title' => $this->getTitle($child),
             'url' => Url::fromRoute($route_name, $route_parameters),
-            'localized_options' => $child->getOptions($request),
+            'localized_options' => $child->getOptions($this->routeMatch),
           );
           $build[$level][$plugin_id] = array(
             '#theme' => 'menu_local_task',
@@ -340,14 +352,13 @@ protected function isRouteActive($current_route_name, $route_name, $route_parame
     // Flag the list element as active if this tab's route and parameters match
     // the current request's route and route variables.
     $active = $current_route_name == $route_name;
-    $request = $this->requestStack->getCurrentRequest();
     if ($active) {
       // The request is injected, so we need to verify that we have the expected
       // _raw_variables attribute.
-      $raw_variables_bag = $request->attributes->get('_raw_variables');
+      $raw_variables_bag = $this->routeMatch->getRawParameters();
       // If we don't have _raw_variables, we assume the attributes are still the
       // original values.
-      $raw_variables = $raw_variables_bag ? $raw_variables_bag->all() : $request->attributes->all();
+      $raw_variables = $raw_variables_bag ? $raw_variables_bag->all() : $this->routeMatch->getParameters()->all();
       $active = array_intersect_assoc($route_parameters, $raw_variables) == $route_parameters;
     }
     return $active;
diff --git a/core/modules/block_content/src/Plugin/Menu/LocalAction/BlockContentAddLocalAction.php b/core/modules/block_content/src/Plugin/Menu/LocalAction/BlockContentAddLocalAction.php
index e22425e0d101..1cf3bdcd30c3 100644
--- a/core/modules/block_content/src/Plugin/Menu/LocalAction/BlockContentAddLocalAction.php
+++ b/core/modules/block_content/src/Plugin/Menu/LocalAction/BlockContentAddLocalAction.php
@@ -8,8 +8,7 @@
 namespace Drupal\block_content\Plugin\Menu\LocalAction;
 
 use Drupal\Core\Menu\LocalActionDefault;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Modifies the 'Add custom block' local action.
@@ -19,18 +18,14 @@ class BlockContentAddLocalAction extends LocalActionDefault {
   /**
    * {@inheritdoc}
    */
-  public function getOptions(Request $request) {
-    $options = parent::getOptions($request);
+  public function getOptions(RouteMatchInterface $route_match) {
+    $options = parent::getOptions($route_match);
     // If the route specifies a theme, append it to the query string.
-    if ($request->attributes->has('theme')) {
-      $options['query']['theme'] = $request->attributes->get('theme');
+    if ($theme = $route_match->getParameter('theme')) {
+      $options['query']['theme'] = $theme;
     }
     // Adds a destination on custom block listing.
-    if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'block_content.list') {
-      $options['query']['destination'] = 'admin/structure/block/block-content';
-    }
-    // Adds a destination on custom block listing.
-    if ($request->attributes->get(RouteObjectInterface::ROUTE_NAME) == 'block_content.list') {
+    if ($route_match->getRouteName() == 'block_content.list') {
       $options['query']['destination'] = 'admin/structure/block/block-content';
     }
     return $options;
diff --git a/core/modules/menu_ui/src/Plugin/Menu/LocalAction/MenuLinkAdd.php b/core/modules/menu_ui/src/Plugin/Menu/LocalAction/MenuLinkAdd.php
index 9fee161129eb..f4e04fef165c 100644
--- a/core/modules/menu_ui/src/Plugin/Menu/LocalAction/MenuLinkAdd.php
+++ b/core/modules/menu_ui/src/Plugin/Menu/LocalAction/MenuLinkAdd.php
@@ -8,8 +8,8 @@
 namespace Drupal\menu_ui\Plugin\Menu\LocalAction;
 
 use Drupal\Core\Menu\LocalActionDefault;
-use Symfony\Cmf\Component\Routing\RouteObjectInterface;
-use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Url;
 
 /**
  * Modifies the 'Add link' local action to add a destination.
@@ -19,18 +19,11 @@ class MenuLinkAdd extends LocalActionDefault {
   /**
    * {@inheritdoc}
    */
-  public function getOptions(Request $request) {
-    $options = parent::getOptions($request);
+  public function getOptions(RouteMatchInterface $route_match) {
+    $options = parent::getOptions($route_match);
     // Append the current path as destination to the query string.
-    if ($request->attributes->has(RouteObjectInterface::ROUTE_NAME)) {
-      $route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME);
-      $raw_variables = array();
-      if ($request->attributes->has('_raw_variables')) {
-        $raw_variables = $request->attributes->get('_raw_variables')->all();
-      }
-      // @todo Use RouteMatch instead of Request.
-      //   https://www.drupal.org/node/2294157
-      $options['query']['destination'] = \Drupal::urlGenerator()->generateFromRoute($route_name, $raw_variables);
+    if ($route_name = $route_match->getRouteName()) {
+      $options['query']['destination'] = Url::fromRoute($route_name, $route_match->getRawParameters()->all())->toString();
     }
     return $options;
   }
diff --git a/core/modules/tracker/src/Plugin/Menu/UserTrackerTab.php b/core/modules/tracker/src/Plugin/Menu/UserTrackerTab.php
index 3e195afe81b0..6430f676ecc4 100644
--- a/core/modules/tracker/src/Plugin/Menu/UserTrackerTab.php
+++ b/core/modules/tracker/src/Plugin/Menu/UserTrackerTab.php
@@ -8,7 +8,7 @@
 namespace Drupal\tracker\Plugin\Menu;
 
 use Drupal\Core\Menu\LocalTaskDefault;
-use Symfony\Component\HttpFoundation\Request;
+use Drupal\Core\Routing\RouteMatchInterface;
 
 /**
  * Provides route parameters needed to link to the current user tracker tab.
@@ -41,7 +41,7 @@ protected function currentUser() {
   /**
    * {@inheritdoc}
    */
-  public function getRouteParameters(Request $request) {
+  public function getRouteParameters(RouteMatchInterface $route_match) {
     return array('user' => $this->currentUser()->Id());
   }
 
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
index 7cb34b7dc4e4..b38c350925b5 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalActionManagerTest.php
@@ -14,6 +14,7 @@
 use Drupal\Core\Extension\ModuleHandlerInterface;
 use Drupal\Core\Language\Language;
 use Drupal\Core\Menu\LocalActionManager;
+use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Core\Session\AccountInterface;
 use Drupal\Core\Url;
@@ -115,8 +116,9 @@ protected function setUp() {
     $this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
     $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
     $this->factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
+    $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
 
-    $this->localActionManager = new TestLocalActionManager($this->controllerResolver, $this->request, $this->routeProvider, $this->moduleHandler, $this->cacheBackend, $this->accessManager, $this->account, $this->discovery, $this->factory);
+    $this->localActionManager = new TestLocalActionManager($this->controllerResolver, $this->request, $route_match, $this->routeProvider, $this->moduleHandler, $this->cacheBackend, $this->accessManager, $this->account, $this->discovery, $this->factory);
   }
 
   /**
@@ -339,7 +341,7 @@ public function getActionsForRouteProvider() {
 
 class TestLocalActionManager extends LocalActionManager {
 
-  public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, AccessManagerInterface $access_manager, AccountInterface $account, DiscoveryInterface $discovery, FactoryInterface $factory) {
+  public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteMatchInterface $route_match, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, AccessManagerInterface $access_manager, AccountInterface $account, DiscoveryInterface $discovery, FactoryInterface $factory) {
     $this->discovery = $discovery;
     $this->factory = $factory;
     $this->routeProvider = $route_provider;
@@ -348,6 +350,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re
     $this->controllerResolver = $controller_resolver;
     $this->requestStack = new RequestStack();
     $this->requestStack->push($request);
+    $this->routeMatch = $route_match;
     $this->moduleHandler = $module_handler;
     $this->alterInfo('menu_local_actions');
     $this->setCacheBackend($cache_backend, 'local_action_plugins', array('local_action'));
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
index 530b8a147466..11bd9c719c4c 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskDefaultTest.php
@@ -8,9 +8,9 @@
 namespace Drupal\Tests\Core\Menu;
 
 use Drupal\Core\Menu\LocalTaskDefault;
+use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\RouteProviderInterface;
 use Drupal\Tests\UnitTestCase;
-use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Routing\Route;
 
@@ -99,8 +99,8 @@ public function testGetRouteParametersForStaticRoute() {
 
     $this->setupLocalTaskDefault();
 
-    $request = Request::create('/');
-    $this->assertEquals(array(), $this->localTaskBase->getRouteParameters($request));
+    $route_match = new RouteMatch('', new Route('/'));
+    $this->assertEquals(array(), $this->localTaskBase->getRouteParameters($route_match));
   }
 
   /**
@@ -119,9 +119,8 @@ public function testGetRouteParametersInPluginDefinitions() {
 
     $this->setupLocalTaskDefault();
 
-    $request = new Request();
-
-    $this->assertEquals(array('parameter' => 'example'), $this->localTaskBase->getRouteParameters($request));
+    $route_match = new RouteMatch('', new Route('/'));
+    $this->assertEquals(array('parameter' => 'example'), $this->localTaskBase->getRouteParameters($route_match));
   }
 
   /**
@@ -134,16 +133,17 @@ public function testGetRouteParametersForDynamicRoute() {
       'route_name' => 'test_route'
     );
 
+    $route = new Route('/test-route/{parameter}');
     $this->routeProvider->expects($this->once())
       ->method('getRouteByName')
       ->with('test_route')
-      ->will($this->returnValue(new Route('/test-route/{parameter}')));
+      ->will($this->returnValue($route));
 
     $this->setupLocalTaskDefault();
 
-    $request = new Request(array(), array(), array('parameter' => 'example'));
+    $route_match = new RouteMatch('', $route, array(), array('parameter' => 'example'));
 
-    $this->assertEquals(array('parameter' => 'example'), $this->localTaskBase->getRouteParameters($request));
+    $this->assertEquals(array('parameter' => 'example'), $this->localTaskBase->getRouteParameters($route_match));
   }
 
   /**
@@ -156,20 +156,16 @@ public function testGetRouteParametersForDynamicRouteWithUpcastedParameters() {
       'route_name' => 'test_route'
     );
 
+    $route = new Route('/test-route/{parameter}');
     $this->routeProvider->expects($this->once())
       ->method('getRouteByName')
       ->with('test_route')
-      ->will($this->returnValue(new Route('/test-route/{parameter}')));
+      ->will($this->returnValue($route));
 
     $this->setupLocalTaskDefault();
 
-    $request = new Request();
-    $raw_variables = new ParameterBag();
-    $raw_variables->set('parameter', 'example');
-    $request->attributes->set('parameter', (object) array('example2'));
-    $request->attributes->set('_raw_variables', $raw_variables);
-
-    $this->assertEquals(array('parameter' => 'example'), $this->localTaskBase->getRouteParameters($request));
+    $route_match = new RouteMatch('', $route, array('parameter' => (object) 'example2'), array('parameter' => 'example'));
+    $this->assertEquals(array('parameter' => 'example'), $this->localTaskBase->getRouteParameters($route_match));
   }
 
   /**
@@ -307,8 +303,8 @@ public function testGetOptions() {
 
     $this->setupLocalTaskDefault();
 
-    $request = Request::create('/');
-    $this->assertEquals($this->pluginDefinition['options'], $this->localTaskBase->getOptions($request));
+    $route_match = new RouteMatch('', new Route('/'));
+    $this->assertEquals($this->pluginDefinition['options'], $this->localTaskBase->getOptions($route_match));
 
     $this->localTaskBase->setActive(TRUE);
 
@@ -319,7 +315,7 @@ public function testGetOptions() {
           'active'
         )
       )
-    ), $this->localTaskBase->getOptions($request));
+    ), $this->localTaskBase->getOptions($route_match));
   }
 
 }
diff --git a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
index 4c3718b8aae7..8502d7e4f459 100644
--- a/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
+++ b/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
@@ -84,6 +84,13 @@ class LocalTaskManagerTest extends UnitTestCase {
    */
   protected $accessManager;
 
+  /**
+   * The route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface|\PHPUnit_Framework_MockObject_MockObject
+   */
+  protected $routeMatch;
+
   /**
    * {@inheritdoc}
    */
@@ -98,6 +105,7 @@ protected function setUp() {
     $this->factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
     $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
     $this->accessManager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
+    $this->routeMatch = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
 
     $this->setupLocalTaskManager();
   }
@@ -256,7 +264,7 @@ protected function setupLocalTaskManager() {
       ->will($this->returnValue(new Language(array('id' => 'en'))));
 
     $account = $this->getMock('Drupal\Core\Session\AccountInterface');
-    $this->manager = new LocalTaskManager($this->controllerResolver, $request_stack, $this->routeProvider, $this->routeBuilder, $module_handler, $this->cacheBackend, $language_manager, $this->accessManager, $account);
+    $this->manager = new LocalTaskManager($this->controllerResolver, $request_stack, $this->routeMatch, $this->routeProvider, $this->routeBuilder, $module_handler, $this->cacheBackend, $language_manager, $this->accessManager, $account);
 
     $property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'discovery');
     $property->setAccessible(TRUE);
-- 
GitLab