diff --git a/core/core.services.yml b/core/core.services.yml index 9badfe5..05e3c92 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -212,7 +212,7 @@ services: arguments: ['@controller_resolver', '@request', '@router.route_provider', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user'] plugin.manager.menu.local_task: class: Drupal\Core\Menu\LocalTaskManager - arguments: ['@controller_resolver', '@request', '@router.route_provider', '@router.builder', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user'] + arguments: ['@controller_resolver', '@request', '@router.route_provider', '@router.builder', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user', '@request_info'] plugin.manager.menu.contextual_link: class: Drupal\Core\Menu\ContextualLinkManager arguments: ['@controller_resolver', '@module_handler', '@cache.cache', '@language_manager', '@access_manager', '@current_user'] @@ -231,7 +231,7 @@ services: arguments: ['@service_container'] controller_resolver: class: Drupal\Core\Controller\ControllerResolver - arguments: ['@service_container'] + arguments: ['@service_container', '@request_info'] title_resolver: class: Drupal\Core\Controller\TitleResolver arguments: ['@controller_resolver', '@string_translation'] @@ -495,7 +495,7 @@ services: - { name: access_check, applies_to: _entity_access } access_check.entity_create: class: Drupal\Core\Entity\EntityCreateAccessCheck - arguments: ['@entity.manager'] + arguments: ['@entity.manager', '@request_info'] tags: - { name: access_check, applies_to: _entity_create_access } access_check.theme: diff --git a/core/lib/Drupal/Core/Controller/ControllerResolver.php b/core/lib/Drupal/Core/Controller/ControllerResolver.php index 7928c36..88571dc 100644 --- a/core/lib/Drupal/Core/Controller/ControllerResolver.php +++ b/core/lib/Drupal/Core/Controller/ControllerResolver.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Controller; +use Drupal\Core\Routing\RequestInfo; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Controller\ControllerResolver as BaseControllerResolver; use Symfony\Component\HttpKernel\Log\LoggerInterface; @@ -45,16 +46,25 @@ class ControllerResolver extends BaseControllerResolver implements ControllerRes protected $logger; /** + * The request info service. + * + * @var \Drupal\Core\Routing\RequestInfo + */ + protected $requestInfo; + + /** * Constructs a new ControllerResolver. * * @param \Symfony\Component\DependencyInjection\ContainerInterface $container * A ContainerInterface instance. * @param \Symfony\Component\HttpKernel\Log\LoggerInterface $logger * (optional) A LoggerInterface instance. + * @param \Drupal\Core\Routing\RequestInfo $request_info + * (optional) The request info service. */ - public function __construct(ContainerInterface $container, LoggerInterface $logger = NULL) { + public function __construct(ContainerInterface $container, LoggerInterface $logger = NULL, RequestInfo $request_info = NULL) { $this->container = $container; - + $this->requestInfo = $request_info; parent::__construct($logger); } @@ -158,7 +168,7 @@ protected function doGetArguments(Request $request, $controller, array $paramete // 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()) { + if ($this->requestInfo->getRawVariables($request) && $raw = $this->requestInfo->getRawVariables($request)->all()) { foreach ($parameters as $parameter) { // Use the raw value if a parameter has no typehint. if (!$parameter->getClass() && isset($raw[$parameter->name])) { diff --git a/core/lib/Drupal/Core/Entity/EntityCreateAccessCheck.php b/core/lib/Drupal/Core/Entity/EntityCreateAccessCheck.php index 1cf7d87..94851e6 100644 --- a/core/lib/Drupal/Core/Entity/EntityCreateAccessCheck.php +++ b/core/lib/Drupal/Core/Entity/EntityCreateAccessCheck.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Entity; use Drupal\Core\Routing\Access\AccessInterface; +use Drupal\Core\Routing\RequestInfo; use Drupal\Core\Session\AccountInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Route; @@ -25,6 +26,13 @@ class EntityCreateAccessCheck implements AccessInterface { protected $entityManager; /** + * The request info service. + * + * @var \Drupal\Core\Routing\RequestInfo + */ + protected $requestInfo; + + /** * The key used by the routing requirement. * * @var string @@ -36,9 +44,12 @@ class EntityCreateAccessCheck implements AccessInterface { * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. + * @param \Drupal\Core\Routing\RequestInfo $request_info + * The request info service. */ - public function __construct(EntityManagerInterface $entity_manager) { + public function __construct(EntityManagerInterface $entity_manager, RequestInfo $request_info) { $this->entityManager = $entity_manager; + $this->requestInfo = $request_info; } /** @@ -51,7 +62,7 @@ public function access(Route $route, Request $request, AccountInterface $account // {name}, loop over the raw variables and attempt to replace them in the // bundle name. If a placeholder does not exist, it won't get replaced. if ($bundle && strpos($bundle, '{') !== FALSE) { - foreach ($request->get('_raw_variables')->all() as $name => $value) { + foreach ($this->requestInfo->getRawVariables($request)->all() as $name => $value) { $bundle = str_replace('{' . $name . '}', $value, $bundle); } // If we were unable to replace all placeholders, deny access. diff --git a/core/lib/Drupal/Core/Menu/LocalActionDefault.php b/core/lib/Drupal/Core/Menu/LocalActionDefault.php index 1661ac9..4f7dba0 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\RequestInfo; use Drupal\Core\Routing\RouteProviderInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -26,6 +27,13 @@ class LocalActionDefault extends PluginBase implements LocalActionInterface, Con protected $routeProvider; /** + * The request info service. + * + * @var \Drupal\Core\Routing\RequestInfo + */ + protected $requestInfo; + + /** * Constructs a LocalActionDefault object. * * @param array $configuration @@ -36,11 +44,14 @@ class LocalActionDefault extends PluginBase implements LocalActionInterface, Con * The plugin implementation definition. * @param \Drupal\Core\Routing\RouteProviderInterface $route_provider * The route provider to load routes by name. + * @param \Drupal\Core\Routing\RequestInfo $request_info + * The request info service. */ - public function __construct(array $configuration, $plugin_id, array $plugin_definition, RouteProviderInterface $route_provider) { + public function __construct(array $configuration, $plugin_id, array $plugin_definition, RouteProviderInterface $route_provider, RequestInfo $request_info) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->routeProvider = $route_provider; + $this->requestInfo = $request_info; } /** @@ -51,7 +62,8 @@ public static function create(ContainerInterface $container, array $configuratio $configuration, $plugin_id, $plugin_definition, - $container->get('router.route_provider') + $container->get('router.route_provider'), + $container->get('request_info') ); } @@ -90,12 +102,12 @@ public function getRouteParameters(Request $request) { $variables = $route->compile()->getVariables(); // Normally the \Drupal\Core\ParamConverter\ParamConverterManager has - // processed the Request attributes, and in that case the _raw_variables + // processed the Request attributes, and in that case the raw variables // attribute holds the original path strings keyed to the corresponding // 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 = $this->requestInfo->getRawVariables($request); foreach ($variables as $name) { if (isset($parameters[$name])) { diff --git a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php index 1f5180a..b3724be 100644 --- a/core/lib/Drupal/Core/Menu/LocalTaskDefault.php +++ b/core/lib/Drupal/Core/Menu/LocalTaskDefault.php @@ -7,13 +7,16 @@ namespace Drupal\Core\Menu; +use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\Plugin\PluginBase; +use Drupal\Core\Routing\RequestInfo; +use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; /** * Default object used for LocalTaskPlugins. */ -class LocalTaskDefault extends PluginBase implements LocalTaskInterface { +class LocalTaskDefault extends PluginBase implements LocalTaskInterface, ContainerFactoryPluginInterface { /** * The route provider to load routes by name. @@ -30,6 +33,52 @@ class LocalTaskDefault extends PluginBase implements LocalTaskInterface { protected $active = FALSE; /** + * The request info service. + * + * @var \Drupal\Core\Routing\RequestInfo + */ + protected $requestInfo; + + /** + * @param array $configuration + * Plugin configuration. + * @param string $plugin_id + * The plugin id. + * @param array $plugin_definition + * The plugin definition. + * @param \Drupal\Core\Routing\RequestInfo $request_info + * The request info service. + */ + public function __construct(array $configuration, $plugin_id, array $plugin_definition, RequestInfo $request_info) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + $this->requestInfo = $request_info; + } + + /** + * Creates an instance of the plugin. + * + * @param \Symfony\Component\DependencyInjection\ContainerInterface $container + * The container to pull out services used in the plugin. + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin ID for the plugin instance. + * @param array $plugin_definition + * The plugin implementation definition. + * + * @return static + * Returns an instance of this plugin. + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) { + return new static( + $configuration, + $plugin_id, + $plugin_definition, + $container->get('request_info') + ); + } + + /** * {@inheritdoc} */ public function getRouteName() { @@ -45,13 +94,13 @@ public function getRouteParameters(Request $request) { $variables = $route->compile()->getVariables(); // Normally the \Drupal\Core\ParamConverter\ParamConverterManager has - // processed the Request attributes, and in that case the _raw_variables + // processed the Request attributes, and in that case the raw variables // attribute holds the original path strings keyed to the corresponding // 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 = $this->requestInfo->getRawVariables($request); foreach ($variables as $name) { if (isset($parameters[$name])) { diff --git a/core/lib/Drupal/Core/Menu/LocalTaskManager.php b/core/lib/Drupal/Core/Menu/LocalTaskManager.php index 5f954d1..6a15fc7 100644 --- a/core/lib/Drupal/Core/Menu/LocalTaskManager.php +++ b/core/lib/Drupal/Core/Menu/LocalTaskManager.php @@ -18,6 +18,7 @@ use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator; use Drupal\Core\Plugin\Discovery\YamlDiscovery; use Drupal\Core\Plugin\Factory\ContainerFactory; +use Drupal\Core\Routing\RequestInfo; use Drupal\Core\Routing\RouteBuilderInterface; use Drupal\Core\Routing\RouteProviderInterface; use Drupal\Core\Session\AccountInterface; @@ -106,6 +107,13 @@ class LocalTaskManager extends DefaultPluginManager { protected $account; /** + * The request info service. + * + * @var \Drupal\Core\Routing\RequestInfo + */ + protected $requestInfo; + + /** * Constructs a \Drupal\Core\Menu\LocalTaskManager object. * * @param \Drupal\Core\Controller\ControllerResolverInterface $controller_resolver @@ -126,8 +134,10 @@ class LocalTaskManager extends DefaultPluginManager { * The access manager. * @param \Drupal\Core\Session\AccountInterface $account * The current user. + * @param \Drupal\Core\Routing\RequestInfo $request_info + * The request info service. */ - public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, RouteBuilderInterface $route_builder, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManager $language_manager, AccessManager $access_manager, AccountInterface $account) { + public function __construct(ControllerResolverInterface $controller_resolver, Request $request, RouteProviderInterface $route_provider, RouteBuilderInterface $route_builder, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, LanguageManager $language_manager, AccessManager $access_manager, AccountInterface $account, RequestInfo $request_info) { $this->discovery = new YamlDiscovery('local_tasks', $module_handler->getModuleDirectories()); $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery); $this->factory = new ContainerFactory($this); @@ -138,6 +148,7 @@ public function __construct(ControllerResolverInterface $controller_resolver, Re $this->accessManager = $access_manager; $this->account = $account; $this->moduleHandler = $module_handler; + $this->requestInfo = $request_info; $this->alterInfo('local_tasks'); $this->setCacheBackend($cache, $language_manager, 'local_task_plugins', array('local_task' => TRUE)); } @@ -348,8 +359,8 @@ protected function isRouteActive($current_route_name, $route_name, $route_parame $active = $current_route_name == $route_name; if ($active) { // The request is injected, so we need to verify that we have the expected - // _raw_variables attribute. - $raw_variables_bag = $this->request->attributes->get('_raw_variables'); + // raw variables. + $raw_variables_bag = $this->requestInfo->getRawVariables($this->request); // 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() : $this->request->attributes->all(); diff --git a/core/lib/Drupal/Core/Routing/RequestInfo.php b/core/lib/Drupal/Core/Routing/RequestInfo.php index c62e1f3..c4dfcb4 100644 --- a/core/lib/Drupal/Core/Routing/RequestInfo.php +++ b/core/lib/Drupal/Core/Routing/RequestInfo.php @@ -87,4 +87,18 @@ public function getSystemPath(Request $request = NULL) { return $request->attributes->get('_system_path'); } + /** + * Gets the raw variables. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * (optional) The request. + * + * @return \Symfony\Component\HttpFoundation\ParameterBag + * The original variables prior to conversion by the ParamConverterManager. + */ + public function getRawVariables(Request $request = NULL) { + $request = $request ?: $this->request; + return $request->attributes->get('_raw_variables'); + } + } diff --git a/core/modules/field_ui/field_ui.services.yml b/core/modules/field_ui/field_ui.services.yml index e643e54..bcaf502 100644 --- a/core/modules/field_ui/field_ui.services.yml +++ b/core/modules/field_ui/field_ui.services.yml @@ -10,7 +10,7 @@ services: - { name: access_check, applies_to: _field_ui_field_delete_access } access_check.field_ui.view_mode: class: Drupal\field_ui\Access\ViewModeAccessCheck - arguments: ['@entity.manager'] + arguments: ['@entity.manager', '@request_info'] tags: - { name: access_check, applies_to: _field_ui_view_mode_access } access_check.field_ui.form_mode: diff --git a/core/modules/field_ui/lib/Drupal/field_ui/Access/ViewModeAccessCheck.php b/core/modules/field_ui/lib/Drupal/field_ui/Access/ViewModeAccessCheck.php index 8b115df..90503ab 100644 --- a/core/modules/field_ui/lib/Drupal/field_ui/Access/ViewModeAccessCheck.php +++ b/core/modules/field_ui/lib/Drupal/field_ui/Access/ViewModeAccessCheck.php @@ -9,6 +9,7 @@ use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Routing\Access\AccessInterface; +use Drupal\Core\Routing\RequestInfo; use Drupal\Core\Session\AccountInterface; use Symfony\Component\Routing\Route; use Symfony\Component\HttpFoundation\Request; @@ -26,13 +27,23 @@ class ViewModeAccessCheck implements AccessInterface { protected $entityManager; /** + * The request info service. + * + * @var \Drupal\Core\Routing\RequestInfo + */ + protected $requestInfo; + + /** * Creates a new ViewModeAccessCheck. * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. + * @param \Drupal\Core\Routing\RequestInfo $request_info + * The request info service. */ - public function __construct(EntityManagerInterface $entity_manager) { + public function __construct(EntityManagerInterface $entity_manager, RequestInfo $request_info) { $this->entityManager = $entity_manager; + $this->requestInfo = $request_info; } /** @@ -44,7 +55,7 @@ public function access(Route $route, Request $request, AccountInterface $account if (!($bundle = $request->attributes->get('bundle'))) { $entity_type = $this->entityManager->getDefinition($entity_type_id); - $bundle = $request->attributes->get('_raw_variables')->get($entity_type->getBundleEntityType()); + $bundle = $this->requestInfo->getRawVariables($request)->get($entity_type->getBundleEntityType()); } $visibility = FALSE; diff --git a/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php b/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php index cd18409..5e066ab 100644 --- a/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php +++ b/core/modules/views/lib/Drupal/views/Routing/ViewPageController.php @@ -10,6 +10,7 @@ use Drupal\Component\Utility\String; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityStorageControllerInterface; +use Drupal\Core\Routing\RequestInfo; use Drupal\views\ViewExecutableFactory; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -35,16 +36,26 @@ class ViewPageController implements ContainerInjectionInterface { protected $executableFactory; /** + * The request info service. + * + * @var \Drupal\Core\Routing\RequestInfo + */ + protected $requestInfo; + + /** * Constructs a ViewPageController object. * * @param \Drupal\Core\Entity\EntityStorageControllerInterface $storage_controller * The entity storage controller. * @param \Drupal\views\ViewExecutableFactory $executable_factory * The view executable factory + * @param \Drupal\Core\Routing\RequestInfo $request_info + * The request info service. */ - public function __construct(EntityStorageControllerInterface $storage_controller, ViewExecutableFactory $executable_factory) { + public function __construct(EntityStorageControllerInterface $storage_controller, ViewExecutableFactory $executable_factory, RequestInfo $request_info) { $this->storageController = $storage_controller; $this->executableFactory = $executable_factory; + $this->requestInfo = $request_info; } /** @@ -53,7 +64,8 @@ public function __construct(EntityStorageControllerInterface $storage_controller public static function create(ContainerInterface $container) { return new static( $container->get('entity.manager')->getStorageController('view'), - $container->get('views.executable') + $container->get('views.executable'), + $container->get('request_info') ); } @@ -87,8 +99,8 @@ public function handle(Request $request) { // First try to get from the original values then on the not converted // ones. - if ($request->attributes->has('_raw_variables')) { - $arg = $request->attributes->get('_raw_variables')->get($attribute); + if ($raw_variables = $this->requestInfo->getRawVariables($request)) { + $arg = $raw_variables->get($attribute); } else { $arg = $request->attributes->get($attribute); diff --git a/core/tests/Drupal/Tests/Core/Routing/RequestInfoTest.php b/core/tests/Drupal/Tests/Core/Routing/RequestInfoTest.php index 6fe064a..f4e33dd 100644 --- a/core/tests/Drupal/Tests/Core/Routing/RequestInfoTest.php +++ b/core/tests/Drupal/Tests/Core/Routing/RequestInfoTest.php @@ -10,6 +10,7 @@ use Drupal\Tests\UnitTestCase; use Drupal\Core\Routing\RequestInfo; use Symfony\Cmf\Component\Routing\RouteObjectInterface; +use Symfony\Component\HttpFoundation\ParameterBag; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\Route; @@ -101,4 +102,27 @@ public function testGetSystemPath() { $this->assertSame('path_2', $this->requestInfo->getSystemPath($request_2)); } + /** + * Test the getRawVariables(). + * + * @covers ::getRawVariables + */ + public function testGetRawVariables() { + $raw_1 = new ParameterBag(); + $raw_1->set('foo', 'bar'); + + $raw_2 = new ParameterBag(); + $raw_2->set('baz', 'bob'); + + $request_1 = new Request(array(), array(), array('_raw_variables' => $raw_1)); + $request_2 = new Request(array(), array(), array('_raw_variables' => $raw_2)); + + $this->assertSame('bar', $this->requestInfo->getRawVariables($request_1)->get('foo')); + + $this->requestInfo->setRequest($request_1); + $this->assertSame('bar', $this->requestInfo->getRawVariables()->get('foo')); + + $this->assertSame('bob', $this->requestInfo->getRawVariables($request_2)->get('baz')); + } + }