diff --git a/core/core.services.yml b/core/core.services.yml index 9f5d6fc..cfb8608 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -280,6 +280,9 @@ services: path.alias_manager: class: Drupal\Core\Path\AliasManager arguments: ['@path.alias_storage', '@path.alias_whitelist', '@language_manager', '@cache.data'] + path.current: + class: Drupal\Core\Path\CurrentPath + arguments: ['@request_stack'] http_client: class: Drupal\Core\Http\Client tags: @@ -529,7 +532,7 @@ services: arguments: ['@current_route_match'] router.route_provider: class: Drupal\Core\Routing\RouteProvider - arguments: ['@database', '@router.builder', '@state'] + arguments: ['@database', '@router.builder', '@state', '@path.current'] tags: - { name: event_subscriber } - { name: backend_overridable } @@ -540,6 +543,7 @@ services: - { name: 'event_subscriber' } router.matcher.final_matcher: class: Drupal\Core\Routing\UrlMatcher + arguments: ['@path.current'] router.matcher: class: Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher arguments: ['@router.route_provider'] @@ -832,7 +836,7 @@ services: class: Drupal\Core\EventSubscriber\PathSubscriber tags: - { name: event_subscriber } - arguments: ['@path.alias_manager', '@path_processor_manager'] + arguments: ['@path.alias_manager', '@path_processor_manager', '@path.current'] finish_response_subscriber: class: Drupal\Core\EventSubscriber\FinishResponseSubscriber tags: diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 9ce21ff..aac4689 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1353,7 +1353,7 @@ function template_preprocess_html(&$variables) { $variables['root_path'] = FALSE; } else { - $system_path = \Drupal::request()->attributes->get('_system_path'); + $system_path = \Drupal::service('path.current')->getPath(); $variables['root_path'] = explode('/', $system_path)[0]; } diff --git a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php index 472b31c..3d72b0d 100644 --- a/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php +++ b/core/lib/Drupal/Core/EventSubscriber/PathSubscriber.php @@ -8,6 +8,7 @@ namespace Drupal\Core\EventSubscriber; use Drupal\Core\Path\AliasManagerInterface; +use Drupal\Core\Path\CurrentPath; use Drupal\Core\PathProcessor\InboundPathProcessorInterface; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelEvents; @@ -34,9 +35,25 @@ class PathSubscriber implements EventSubscriberInterface { */ protected $pathProcessor; - public function __construct(AliasManagerInterface $alias_manager, InboundPathProcessorInterface $path_processor) { + /** + * The current path. + * + * @var \Drupal\Core\Path\CurrentPath + */ + protected $currentPath; + + /** + * Constructs a new PathSubscriber instance. + * + * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager + * @param \Drupal\Core\PathProcessor\InboundPathProcessorInterface $path_processor + * @param \Drupal\Core\Path\CurrentPath $current_path + * The current path. + */ + public function __construct(AliasManagerInterface $alias_manager, InboundPathProcessorInterface $path_processor, CurrentPath $current_path) { $this->aliasManager = $alias_manager; $this->pathProcessor = $path_processor; + $this->currentPath = $current_path; } /** @@ -49,7 +66,7 @@ public function onKernelRequestConvertPath(GetResponseEvent $event) { $request = $event->getRequest(); $path = trim($request->getPathInfo(), '/'); $path = $this->pathProcessor->processInbound($path, $request); - $request->attributes->set('_system_path', $path); + $this->currentPath->setPath($path, $request); // Set the cache key on the alias manager cache decorator. if ($event->getRequestType() == HttpKernelInterface::MASTER_REQUEST) { diff --git a/core/lib/Drupal/Core/Path/CurrentPath.php b/core/lib/Drupal/Core/Path/CurrentPath.php new file mode 100644 index 0000000..5239ad5 --- /dev/null +++ b/core/lib/Drupal/Core/Path/CurrentPath.php @@ -0,0 +1,84 @@ +requestStack = $request_stack; + $this->paths = new \SplObjectStorage(); + } + + /** + * Returns the path of the current request. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * (optional) The request. + * + * @return string + * Returns the path, without leading slashes. + */ + public function getPath($request = NULL) { + if (!isset($request)) { + $request = $this->requestStack->getCurrentRequest(); + } + if (!isset($this->paths[$request])) { + $this->paths[$request] = trim($request->getPathInfo(), '/'); + } + + return $this->paths[$request]; + } + + /** + * Sets the current path. + * + * @param string $path + * The path. + * @param \Symfony\Component\HttpFoundation\Request $request + * (optional) The request. + * + * @return $this + */ + public function setPath($path, $request = NULL) { + if (!isset($request)) { + $request = $this->requestStack->getCurrentRequest(); + } + $this->paths[$request] = $path; + + return $this; + } + +} diff --git a/core/lib/Drupal/Core/Routing/RouteProvider.php b/core/lib/Drupal/Core/Routing/RouteProvider.php index 26ff91d..81e26d7 100644 --- a/core/lib/Drupal/Core/Routing/RouteProvider.php +++ b/core/lib/Drupal/Core/Routing/RouteProvider.php @@ -8,6 +8,7 @@ namespace Drupal\Core\Routing; use Drupal\Component\Utility\String; +use Drupal\Core\Path\CurrentPath; use Drupal\Core\State\StateInterface; use Symfony\Cmf\Component\Routing\PagedRouteCollection; use Symfony\Cmf\Component\Routing\PagedRouteProviderInterface; @@ -60,6 +61,13 @@ class RouteProvider implements RouteProviderInterface, PagedRouteProviderInterfa protected $routes = array(); /** + * The current path. + * + * @var \Drupal\Core\Path\CurrentPath + */ + protected $currentPath; + + /** * Constructs a new PathMatcher. * * @param \Drupal\Core\Database\Connection $connection @@ -68,14 +76,17 @@ class RouteProvider implements RouteProviderInterface, PagedRouteProviderInterfa * The route builder. * @param \Drupal\Core\State\StateInterface $state * The state. + * @param \Drupal\Core\Path\CurrentPath $current_path + * THe current path. * @param string $table * The table in the database to use for matching. */ - public function __construct(Connection $connection, RouteBuilderInterface $route_builder, StateInterface $state, $table = 'router') { + public function __construct(Connection $connection, RouteBuilderInterface $route_builder, StateInterface $state, CurrentPath $current_path, $table = 'router') { $this->connection = $connection; $this->routeBuilder = $route_builder; $this->state = $state; $this->tableName = $table; + $this->currentPath = $current_path; } /** @@ -104,22 +115,7 @@ public function __construct(Connection $connection, RouteBuilderInterface $route * @todo Should this method's found routes also be included in the cache? */ public function getRouteCollectionForRequest(Request $request) { - - // The '_system_path' has language prefix stripped and path alias resolved, - // whereas getPathInfo() returns the requested path. In Drupal, the request - // always contains a system_path attribute, but this component may get - // adopted by non-Drupal projects. Some unit tests also skip initializing - // '_system_path'. - // @todo Consider abstracting this to a separate object. - if ($request->attributes->has('_system_path')) { - // _system_path never has leading or trailing slashes. - $path = '/' . $request->attributes->get('_system_path'); - } - else { - // getPathInfo() always has leading slash, and might or might not have a - // trailing slash. - $path = rtrim($request->getPathInfo(), '/'); - } + $path = '/' . $this->currentPath->getPath($request); $collection = $this->getRoutesByPath($path); diff --git a/core/lib/Drupal/Core/Routing/UrlMatcher.php b/core/lib/Drupal/Core/Routing/UrlMatcher.php index a7ed9e8..088353c 100644 --- a/core/lib/Drupal/Core/Routing/UrlMatcher.php +++ b/core/lib/Drupal/Core/Routing/UrlMatcher.php @@ -7,6 +7,7 @@ namespace Drupal\Core\Routing; +use Drupal\Core\Path\CurrentPath; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\Routing\RouteCollection; use Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher as BaseUrlMatcher; @@ -17,27 +18,32 @@ class UrlMatcher extends BaseUrlMatcher { /** + * The current path. + * + * @var \Drupal\Core\Path\CurrentPath + */ + protected $currentPath; + + /** * Constructs a new UrlMatcher. * * The parent class has a constructor we need to skip, so just override it * with a no-op. + * + * @param \Drupal\Core\Path\CurrentPath $current_path + * The current path. */ - public function __construct() {} + public function __construct(CurrentPath $current_path) { + $this->currentPath = $current_path; + } public function finalMatch(RouteCollection $collection, Request $request) { $this->routes = $collection; $context = new RequestContext(); $context->fromRequest($request); $this->setContext($context); - if ($request->attributes->has('_system_path')) { - // _system_path never has leading or trailing slashes. - $path = '/' . $request->attributes->get('_system_path'); - } - else { - // getPathInfo() always has leading slash, and might or might not have a - // trailing slash. - $path = rtrim($request->getPathInfo(), '/'); - } + $path = '/' . $this->currentPath->getPath($request); + return $this->match($path); } diff --git a/core/modules/system/src/PathBasedBreadcrumbBuilder.php b/core/modules/system/src/PathBasedBreadcrumbBuilder.php index 6080d6b..c63f9e4 100644 --- a/core/modules/system/src/PathBasedBreadcrumbBuilder.php +++ b/core/modules/system/src/PathBasedBreadcrumbBuilder.php @@ -14,6 +14,7 @@ use Drupal\Core\Controller\TitleResolverInterface; use Drupal\Core\Link; use Drupal\Core\ParamConverter\ParamNotConvertedException; +use Drupal\Core\Path\CurrentPath; use Drupal\Core\PathProcessor\InboundPathProcessorInterface; use Drupal\Core\Routing\RequestContext; use Drupal\Core\Routing\RouteMatch; @@ -99,8 +100,10 @@ class PathBasedBreadcrumbBuilder implements BreadcrumbBuilderInterface { * The title resolver service. * @param \Drupal\Core\Session\AccountInterface $current_user * The current user object. + * @param \Drupal\Core\Path\CurrentPath $current_path + * The current path. */ - public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user) { + public function __construct(RequestContext $context, AccessManagerInterface $access_manager, RequestMatcherInterface $router, InboundPathProcessorInterface $path_processor, ConfigFactoryInterface $config_factory, TitleResolverInterface $title_resolver, AccountInterface $current_user, CurrentPath $current_path) { $this->context = $context; $this->accessManager = $access_manager; $this->router = $router; @@ -108,6 +111,7 @@ public function __construct(RequestContext $context, AccessManagerInterface $acc $this->config = $config_factory->get('system.site'); $this->titleResolver = $title_resolver; $this->currentUser = $current_user; + $this->currentPath = $current_path; } /** @@ -191,7 +195,7 @@ protected function getRequestForPath($path, array $exclude) { // This resolves to the front page, which we already add. return NULL; } - $request->attributes->set('_system_path', $processed); + $this->currentPath->setPath($processed, $request); // Attempt to match this path to provide a fully built request. try { $request->attributes->add($this->router->matchRequest($request)); diff --git a/core/modules/system/src/Plugin/Condition/RequestPath.php b/core/modules/system/src/Plugin/Condition/RequestPath.php index a5f5613..42e4d10 100644 --- a/core/modules/system/src/Plugin/Condition/RequestPath.php +++ b/core/modules/system/src/Plugin/Condition/RequestPath.php @@ -11,6 +11,7 @@ use Drupal\Core\Condition\ConditionPluginBase; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Path\AliasManagerInterface; +use Drupal\Core\Path\CurrentPath; use Drupal\Core\Path\PathMatcherInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; use Drupal\Core\StringTranslation\StringTranslationTrait; @@ -49,6 +50,13 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI protected $requestStack; /** + * The current path. + * + * @var \Drupal\Core\Path\CurrentPath + */ + protected $currentPath; + + /** * Constructs a RequestPath condition plugin. * * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager @@ -57,6 +65,8 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI * The path matcher service. * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack * The request stack. + * @param \Drupal\Core\Path\CurrentPath $current_path + * The curren path. * @param array $configuration * A configuration array containing information about the plugin instance. * @param string $plugin_id @@ -64,11 +74,12 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI * @param array $plugin_definition * The plugin implementation definition. */ - public function __construct(AliasManagerInterface $alias_manager, PathMatcherInterface $path_matcher, RequestStack $request_stack, array $configuration, $plugin_id, array $plugin_definition) { + public function __construct(AliasManagerInterface $alias_manager, PathMatcherInterface $path_matcher, RequestStack $request_stack, CurrentPath $current_path, array $configuration, $plugin_id, array $plugin_definition) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->aliasManager = $alias_manager; $this->pathMatcher = $path_matcher; $this->requestStack = $request_stack; + $this->currentPath = $current_path; } /** @@ -79,6 +90,7 @@ public static function create(ContainerInterface $container, array $configuratio $container->get('path.alias_manager'), $container->get('path.matcher'), $container->get('request_stack'), + $container->get('path.current'), $configuration, $plugin_id, $plugin_definition); @@ -141,9 +153,7 @@ public function evaluate() { $request = $this->requestStack->getCurrentRequest(); // Compare the lowercase path alias (if any) and internal path. - // @todo Remove dependency on the internal _system_path attribute: - // https://www.drupal.org/node/2293581. - $path = $request->attributes->get('_system_path'); + $path = $this->currentPath->getPath($request); $path_alias = Unicode::strtolower($this->aliasManager->getAliasByPath($path)); return $this->pathMatcher->matchPath($path_alias, $pages) || (($path != $path_alias) && $this->pathMatcher->matchPath($path, $pages)); diff --git a/core/modules/system/src/Tests/Plugin/Condition/RequestPathTest.php b/core/modules/system/src/Tests/Plugin/Condition/RequestPathTest.php index c1d4b2a..8298431 100644 --- a/core/modules/system/src/Tests/Plugin/Condition/RequestPathTest.php +++ b/core/modules/system/src/Tests/Plugin/Condition/RequestPathTest.php @@ -7,6 +7,7 @@ namespace Drupal\system\Tests\Plugin\Condition; +use Drupal\Core\Path\CurrentPath; use Drupal\simpletest\KernelTestBase; use Drupal\system\Tests\Routing\MockAliasManager; use Symfony\Component\HttpFoundation\Request; @@ -49,6 +50,13 @@ class RequestPathTest extends KernelTestBase { public static $modules = array('system', 'user', 'field', 'path'); /** + * The current path. + * + * @var \Drupal\Core\Path\CurrentPath + */ + protected $currentPath; + + /** * {@inheritdoc} */ protected function setUp() { @@ -65,6 +73,8 @@ protected function setUp() { // Set the test request stack in the container. $this->requestStack = new RequestStack(); $this->container->set('request_stack', $this->requestStack); + + $this->currentPath = new CurrentPath($this->requestStack); } /** @@ -78,7 +88,6 @@ public function testConditions() { $pages = "my/pass/page\r\nmy/pass/page2\r\nfoo"; $request = Request::create('/my/pass/page2'); - $request->attributes->set('_system_path', 'my/pass/page2'); $this->requestStack->push($request); /* @var \Drupal\system\Plugin\Condition\RequestPath $condition */ @@ -91,7 +100,7 @@ public function testConditions() { $this->assertEqual($condition->summary(), 'Return true on the following pages: my/pass/page, my/pass/page2, foo', 'The condition summary matches for a standard path'); // Test an aliased path. - $request->attributes->set('_system_path', 'my/aliased/page'); + $this->currentPath->setPath('my/aliased/page', $request); $this->requestStack->pop(); $this->requestStack->push($request); @@ -102,7 +111,7 @@ public function testConditions() { // Test a wildcard path. $this->aliasManager->addAlias('my/pass/page3', 'my/pass/page3'); - $request->attributes->set('_system_path', 'my/pass/page3'); + $this->currentPath->setPath('my/pass/page3', $request); $this->requestStack->pop(); $this->requestStack->push($request); @@ -112,9 +121,9 @@ public function testConditions() { $this->assertEqual($condition->summary(), 'Return true on the following pages: my/pass/*', 'The condition summary matches for a wildcard path'); // Test a missing path. - $request->attributes->set('_system_path', 'my/fail/page4'); $this->requestStack->pop(); $this->requestStack->push($request); + $this->currentPath->setPath('my/fail/page4', $request); $condition->setConfig('pages', 'my/pass/*'); diff --git a/core/modules/system/src/Tests/Routing/RouteProviderTest.php b/core/modules/system/src/Tests/Routing/RouteProviderTest.php index 6ba9f97..50a262e 100644 --- a/core/modules/system/src/Tests/Routing/RouteProviderTest.php +++ b/core/modules/system/src/Tests/Routing/RouteProviderTest.php @@ -8,9 +8,11 @@ namespace Drupal\system\Tests\Routing; use Drupal\Core\KeyValueStore\KeyValueMemoryFactory; +use Drupal\Core\Path\CurrentPath; use Drupal\Core\State\State; use Drupal\simpletest\KernelTestBase; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\Routing\Exception\RouteNotFoundException; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; @@ -49,11 +51,19 @@ class RouteProviderTest extends KernelTestBase { */ protected $state; + /** + * The current path. + * + * @var \Drupal\Core\Path\CurrentPath + */ + protected $currentPath; + protected function setUp() { parent::setUp(); $this->fixtures = new RoutingFixtures(); $this->routeBuilder = new NullRouteBuilder(); $this->state = new State(new KeyValueMemoryFactory()); + $this->currentPath = new CurrentPath(new RequestStack()); } protected function tearDown() { @@ -68,7 +78,7 @@ protected function tearDown() { public function testCandidateOutlines() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $parts = array('node', '5', 'edit'); @@ -91,7 +101,7 @@ public function testCandidateOutlines() { */ function testExactPathMatch() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -115,7 +125,7 @@ function testExactPathMatch() { */ function testOutlinePathMatch() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -144,7 +154,7 @@ function testOutlinePathMatch() { */ function testOutlinePathMatchTrailingSlash() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -173,7 +183,7 @@ function testOutlinePathMatchTrailingSlash() { */ function testOutlinePathMatchDefaults() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -211,7 +221,7 @@ function testOutlinePathMatchDefaults() { */ function testOutlinePathMatchDefaultsCollision() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -250,7 +260,7 @@ function testOutlinePathMatchDefaultsCollision() { */ function testOutlinePathMatchDefaultsCollision2() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -289,7 +299,7 @@ function testOutlinePathMatchDefaultsCollision2() { */ public function testOutlinePathMatchZero() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -324,7 +334,7 @@ public function testOutlinePathMatchZero() { */ function testOutlinePathNoMatch() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -349,7 +359,7 @@ function testOutlinePathNoMatch() { */ function testSystemPathMatch() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -358,7 +368,7 @@ function testSystemPathMatch() { $dumper->dump(); $request = Request::create('/path/one', 'GET'); - $request->attributes->set('_system_path', 'path/two'); + $this->currentPath->setPath('path/two', $request); $routes_by_pattern = $provider->getRoutesByPattern('/path/two'); $routes = $provider->getRouteCollectionForRequest($request); @@ -374,7 +384,7 @@ function testSystemPathMatch() { */ protected function testRouteByName() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); @@ -409,7 +419,7 @@ protected function testRouteByName() { */ public function testGetRoutesByPatternWithLongPatterns() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); // This pattern has only 3 parts, so we will get candidates, but no routes, @@ -467,7 +477,7 @@ public function testGetRoutesByPatternWithLongPatterns() { */ public function testGetRoutesPaged() { $connection = Database::getConnection(); - $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, 'test_routes'); + $provider = new RouteProvider($connection, $this->routeBuilder, $this->state, $this->currentPath, 'test_routes'); $this->fixtures->createTables($connection); $dumper = new MatcherDumper($connection, $this->state, 'test_routes'); diff --git a/core/modules/system/system.services.yml b/core/modules/system/system.services.yml index 2a21015..223f442 100644 --- a/core/modules/system/system.services.yml +++ b/core/modules/system/system.services.yml @@ -12,7 +12,7 @@ services: arguments: ['@module_handler', '@entity.manager', '@request_stack', '@menu.link_tree', '@menu.active_trail'] system.breadcrumb.default: class: Drupal\system\PathBasedBreadcrumbBuilder - arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user'] + arguments: ['@router.request_context', '@access_manager', '@router', '@path_processor_manager', '@config.factory', '@title_resolver', '@current_user', '@path.current'] tags: - { name: breadcrumb_builder, priority: 0 } path_processor.files: diff --git a/core/modules/views/src/Controller/ViewAjaxController.php b/core/modules/views/src/Controller/ViewAjaxController.php index e938ef8..177e586 100644 --- a/core/modules/views/src/Controller/ViewAjaxController.php +++ b/core/modules/views/src/Controller/ViewAjaxController.php @@ -12,6 +12,7 @@ use Drupal\Core\Ajax\ReplaceCommand; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; use Drupal\Core\Entity\EntityStorageInterface; +use Drupal\Core\Path\CurrentPath; use Drupal\Core\Render\RendererInterface; use Drupal\views\Ajax\ScrollTopCommand; use Drupal\views\Ajax\ViewAjaxResponse; @@ -48,6 +49,13 @@ class ViewAjaxController implements ContainerInjectionInterface { protected $renderer; /** + * The current path. + * + * @var \Drupal\Core\Path\CurrentPath + */ + protected $currentPath; + + /** * Constructs a ViewAjaxController object. * * @param \Drupal\Core\Entity\EntityStorageInterface $storage @@ -56,11 +64,14 @@ class ViewAjaxController implements ContainerInjectionInterface { * The factory to load a view executable with. * @param \Drupal\Core\Render\RendererInterface $renderer * The renderer. + * @param \Drupal\Core\Path\CurrentPath $current_path + * The current path. */ - public function __construct(EntityStorageInterface $storage, ViewExecutableFactory $executable_factory, RendererInterface $renderer) { + public function __construct(EntityStorageInterface $storage, ViewExecutableFactory $executable_factory, RendererInterface $renderer, CurrentPath $current_path) { $this->storage = $storage; $this->executableFactory = $executable_factory; $this->renderer = $renderer; + $this->currentPath = $current_path; } /** @@ -70,7 +81,8 @@ public static function create(ContainerInterface $container) { return new static( $container->get('entity.manager')->getStorage('view'), $container->get('views.executable'), - $container->get('renderer') + $container->get('renderer'), + $container->get('path.current') ); } @@ -123,7 +135,7 @@ public function ajaxView(Request $request) { $response->setView($view); // Fix the current path for paging. if (!empty($path)) { - $request->attributes->set('_system_path', $path); + $this->currentPath->setPath($path, $request); } // Add all POST data, because AJAX is always a post and many things, diff --git a/core/modules/views/src/Plugin/views/argument_default/Raw.php b/core/modules/views/src/Plugin/views/argument_default/Raw.php index 9d194e5..7a96512 100644 --- a/core/modules/views/src/Plugin/views/argument_default/Raw.php +++ b/core/modules/views/src/Plugin/views/argument_default/Raw.php @@ -9,6 +9,7 @@ use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Path\AliasManagerInterface; +use Drupal\Core\Path\CurrentPath; use Drupal\views\Plugin\CacheablePluginInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; @@ -33,6 +34,13 @@ class Raw extends ArgumentDefaultPluginBase implements CacheablePluginInterface protected $aliasManager; /** + * The current path. + * + * @var \Drupal\Core\Path\CurrentPath + */ + protected $currentPath; + + /** * Constructs a Raw object. * * @param array $configuration @@ -43,11 +51,14 @@ class Raw extends ArgumentDefaultPluginBase implements CacheablePluginInterface * The plugin implementation definition. * @param \Drupal\Core\Path\AliasManagerInterface $alias_manager * The alias manager. + * @param \Drupal\Core\Path\CurrentPath $current_path + * The current path. */ - public function __construct(array $configuration, $plugin_id, $plugin_definition, AliasManagerInterface $alias_manager) { + public function __construct(array $configuration, $plugin_id, $plugin_definition, AliasManagerInterface $alias_manager, CurrentPath $current_path) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->aliasManager = $alias_manager; + $this->currentPath = $current_path; } /** @@ -58,7 +69,8 @@ public static function create(ContainerInterface $container, array $configuratio $configuration, $plugin_id, $plugin_definition, - $container->get('path.alias_manager') + $container->get('path.alias_manager'), + $container->get('path.current') ); } @@ -91,9 +103,7 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { } public function getArgument() { - // @todo Remove dependency on the internal _system_path attribute: - // https://www.drupal.org/node/2293581. - $path = $this->view->getRequest()->attributes->get('_system_path'); + $path = $this->currentPath->getPath($this->view->getRequest()); if ($this->options['use_alias']) { $path = $this->aliasManager->getAliasByPath($path); } diff --git a/core/modules/views/tests/src/Unit/Plugin/argument_default/RawTest.php b/core/modules/views/tests/src/Unit/Plugin/argument_default/RawTest.php index 2d1df0e..0f9593b 100644 --- a/core/modules/views/tests/src/Unit/Plugin/argument_default/RawTest.php +++ b/core/modules/views/tests/src/Unit/Plugin/argument_default/RawTest.php @@ -7,9 +7,11 @@ namespace Drupal\Tests\views\Unit\Plugin\argument_default; +use Drupal\Core\Path\CurrentPath; use Drupal\Tests\UnitTestCase; use Drupal\views\Plugin\views\argument_default\Raw; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; /** * @coversDefaultClass \Drupal\views\Plugin\views\argument_default\Raw @@ -29,8 +31,10 @@ public function testGetArgument() { $display_plugin = $this->getMockBuilder('Drupal\views\Plugin\views\display\DisplayPluginBase') ->disableOriginalConstructor() ->getMock(); + $current_path = new CurrentPath(new RequestStack()); - $request = new Request(array(), array(), array('_system_path' => 'test/example')); + $request = new Request(); + $current_path->setPath('test/example', $request); $view->expects($this->any()) ->method('getRequest') ->will($this->returnValue($request)); @@ -39,7 +43,7 @@ public function testGetArgument() { ->method('getAliasByPath'); // Don't use aliases. - $raw = new Raw(array(), 'raw', array(), $alias_manager); + $raw = new Raw(array(), 'raw', array(), $alias_manager, $current_path); $options = array( 'use_alias' => FALSE, 'index' => 0, @@ -47,7 +51,7 @@ public function testGetArgument() { $raw->init($view, $display_plugin, $options); $this->assertEquals('test', $raw->getArgument()); - $raw = new Raw(array(), 'raw', array(), $alias_manager); + $raw = new Raw(array(), 'raw', array(), $alias_manager, $current_path); $options = array( 'use_alias' => FALSE, 'index' => 1, @@ -62,7 +66,7 @@ public function testGetArgument() { ->with($this->equalTo('test/example')) ->will($this->returnValue('other/example')); - $raw = new Raw(array(), 'raw', array(), $alias_manager); + $raw = new Raw(array(), 'raw', array(), $alias_manager, $current_path); $options = array( 'use_alias' => TRUE, 'index' => 0, @@ -70,7 +74,7 @@ public function testGetArgument() { $raw->init($view, $display_plugin, $options); $this->assertEquals('other', $raw->getArgument()); - $raw = new Raw(array(), 'raw', array(), $alias_manager); + $raw = new Raw(array(), 'raw', array(), $alias_manager, $current_path); $options = array( 'use_alias' => TRUE, 'index' => 1,