Issue #2272201 by kim.pepper: Move drupal_match_path in path.inc to a service.
parent
d5be5c0454
commit
9b821cd3fe
|
@ -403,6 +403,10 @@ services:
|
|||
path.alias_storage:
|
||||
class: Drupal\Core\Path\AliasStorage
|
||||
arguments: ['@database', '@module_handler']
|
||||
path.matcher:
|
||||
class: Drupal\Core\Path\PathMatcher
|
||||
arguments: ['@config.factory']
|
||||
|
||||
# The argument to the hashing service defined in services.yml, to the
|
||||
# constructor of PhpassHashedPassword is the log2 number of iterations for
|
||||
# password stretching.
|
||||
|
|
|
@ -322,6 +322,9 @@ function install_begin_request(&$install_state) {
|
|||
$container
|
||||
->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
|
||||
->addArgument(new Reference('language_manager'));
|
||||
$container
|
||||
->register('path.matcher', 'Drupal\Core\Path\PathMatcher')
|
||||
->addArgument(new Reference('config.factory'));
|
||||
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
|
|
|
@ -41,27 +41,12 @@ function drupal_is_front_page() {
|
|||
*
|
||||
* @return
|
||||
* Boolean value: TRUE if the path matches a pattern, FALSE otherwise.
|
||||
*
|
||||
* @deprecated as of Drupal 8.0. Use
|
||||
* \Drupal\Core\Path\PathMatcherInterface::matchPath() instead.
|
||||
*/
|
||||
function drupal_match_path($path, $patterns) {
|
||||
$regexps = &drupal_static(__FUNCTION__);
|
||||
|
||||
if (!isset($regexps[$patterns])) {
|
||||
// Convert path settings to a regular expression.
|
||||
// Therefore replace newlines with a logical or, /* with asterisks and the <front> with the frontpage.
|
||||
$to_replace = array(
|
||||
'/(\r\n?|\n)/', // newlines
|
||||
'/\\\\\*/', // asterisks
|
||||
'/(^|\|)\\\\<front\\\\>($|\|)/' // <front>
|
||||
);
|
||||
$replacements = array(
|
||||
'|',
|
||||
'.*',
|
||||
'\1' . preg_quote(\Drupal::config('system.site')->get('page.front'), '/') . '\2'
|
||||
);
|
||||
$patterns_quoted = preg_quote($patterns, '/');
|
||||
$regexps[$patterns] = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/';
|
||||
}
|
||||
return (bool)preg_match($regexps[$patterns], $path);
|
||||
return \Drupal::service('path.matcher')->matchPath($path, $patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Path\PathMatcher.
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Path;
|
||||
|
||||
use Drupal\Core\Config\ConfigFactoryInterface;
|
||||
|
||||
/**
|
||||
* Provides a path matcher.
|
||||
*/
|
||||
class PathMatcher implements PathMatcherInterface {
|
||||
|
||||
/**
|
||||
* The default front page.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $frontPage;
|
||||
|
||||
/**
|
||||
* The cache of regular expressions.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $regexes;
|
||||
|
||||
/**
|
||||
* The config factory service.
|
||||
*
|
||||
* @var \Drupal\Core\Config\ConfigFactoryInterface
|
||||
*/
|
||||
protected $configFactory;
|
||||
|
||||
/**
|
||||
* Creates a new PathMatcher.
|
||||
*
|
||||
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
|
||||
* The config factory.
|
||||
*/
|
||||
public function __construct(ConfigFactoryInterface $config_factory) {
|
||||
$this->configFactory = $config_factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function matchPath($path, $patterns) {
|
||||
|
||||
if (!isset($this->regexes[$patterns])) {
|
||||
// Lazy-load front page config.
|
||||
if (!isset($this->frontPage)) {
|
||||
$this->frontPage = $this->configFactory->get('system.site')->get('page.front');
|
||||
}
|
||||
// Convert path settings to a regular expression.
|
||||
$to_replace = array(
|
||||
// Replace newlines with a logical 'or'.
|
||||
'/(\r\n?|\n)/',
|
||||
// Quote asterisks.
|
||||
'/\\\\\*/',
|
||||
// Quote <front> keyword.
|
||||
'/(^|\|)\\\\<front\\\\>($|\|)/',
|
||||
);
|
||||
$replacements = array(
|
||||
'|',
|
||||
'.*',
|
||||
'\1' . preg_quote($this->frontPage, '/') . '\2',
|
||||
);
|
||||
$patterns_quoted = preg_quote($patterns, '/');
|
||||
$this->regexes[$patterns] = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/';
|
||||
}
|
||||
return (bool) preg_match($this->regexes[$patterns], $path);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Core\Path\PathMatcherInterface
|
||||
*/
|
||||
|
||||
namespace Drupal\Core\Path;
|
||||
|
||||
/**
|
||||
* Provides an interface for URL path matchers.
|
||||
*/
|
||||
interface PathMatcherInterface {
|
||||
|
||||
/**
|
||||
* Checks if a path matches any pattern in a set of patterns.
|
||||
*
|
||||
* @param string $path
|
||||
* The path to match.
|
||||
* @param string $patterns
|
||||
* A set of patterns separated by a newline.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the path matches a pattern, FALSE otherwise.
|
||||
*/
|
||||
public function matchPath($path, $patterns);
|
||||
|
||||
}
|
|
@ -10,6 +10,7 @@ namespace Drupal\system\Plugin\Condition;
|
|||
use Drupal\Component\Utility\Unicode;
|
||||
use Drupal\Core\Condition\ConditionPluginBase;
|
||||
use Drupal\Core\Path\AliasManagerInterface;
|
||||
use Drupal\Core\Path\PathMatcherInterface;
|
||||
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
|
||||
use Drupal\Core\StringTranslation\StringTranslationTrait;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
@ -32,6 +33,13 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
|||
*/
|
||||
protected $aliasManager;
|
||||
|
||||
/**
|
||||
* The path matcher.
|
||||
*
|
||||
* @var \Drupal\Core\Path\PathMatcherInterface
|
||||
*/
|
||||
protected $pathMatcher;
|
||||
|
||||
/**
|
||||
* The request stack.
|
||||
*
|
||||
|
@ -44,6 +52,8 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
|||
*
|
||||
* @param \Drupal\Core\Path\AliasManagerInterface $alias_manager
|
||||
* An alias manager to find the alias for the current system path.
|
||||
* @param \Drupal\Core\Path\PathMatcherInterface $path_matcher
|
||||
* The path matcher service.
|
||||
* @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
|
||||
* The request stack.
|
||||
* @param array $configuration
|
||||
|
@ -53,9 +63,10 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
|||
* @param array $plugin_definition
|
||||
* The plugin implementation definition.
|
||||
*/
|
||||
public function __construct(AliasManagerInterface $alias_manager, RequestStack $request_stack, array $configuration, $plugin_id, array $plugin_definition) {
|
||||
public function __construct(AliasManagerInterface $alias_manager, PathMatcherInterface $path_matcher, RequestStack $request_stack, 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;
|
||||
}
|
||||
|
||||
|
@ -65,6 +76,7 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
|||
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
|
||||
return new static(
|
||||
$container->get('path.alias_manager.cached'),
|
||||
$container->get('path.matcher'),
|
||||
$container->get('request_stack'),
|
||||
$configuration,
|
||||
$plugin_id,
|
||||
|
@ -128,22 +140,6 @@ class RequestPath extends ConditionPluginBase implements ContainerFactoryPluginI
|
|||
$path = $request->attributes->get('_system_path');
|
||||
$path_alias = Unicode::strtolower($this->aliasManager->getAliasByPath($path));
|
||||
|
||||
return $this->matchPath($path_alias, $pages) || (($path != $path_alias) && $this->matchPath($path, $pages));
|
||||
return $this->pathMatcher->matchPath($path_alias, $pages) || (($path != $path_alias) && $this->pathMatcher->matchPath($path, $pages));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a path matches any pattern in a set of patterns.
|
||||
*
|
||||
* @param string $path
|
||||
* The path to match.
|
||||
* @param string $patterns
|
||||
* String containing a set of patterns separated by \n, \r or \r\n.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if the path matches a pattern, FALSE otherwise.
|
||||
*/
|
||||
protected function matchPath($path, $patterns) {
|
||||
return drupal_match_path($path, $patterns);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,131 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Definition of Drupal\system\Tests\Path\MatchPathTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\system\Tests\Path;
|
||||
|
||||
use Drupal\simpletest\WebTestBase;
|
||||
|
||||
/**
|
||||
* Unit tests for the drupal_match_path() function in path.inc.
|
||||
*
|
||||
* @see drupal_match_path().
|
||||
*/
|
||||
class MatchPathTest extends WebTestBase {
|
||||
protected $front;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Drupal match path',
|
||||
'description' => 'Tests the drupal_match_path() function to make sure it works properly.',
|
||||
'group' => 'Path API',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
// Set up the database and testing environment.
|
||||
parent::setUp();
|
||||
|
||||
// Set up a random site front page to test the '<front>' placeholder.
|
||||
$this->front = $this->randomName();
|
||||
\Drupal::config('system.site')->set('page.front', $this->front)->save();
|
||||
// Refresh our static variables from the database.
|
||||
$this->refreshVariables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run through our test cases, making sure each one works as expected.
|
||||
*/
|
||||
function testDrupalMatchPath() {
|
||||
// Set up our test cases.
|
||||
$tests = $this->drupalMatchPathTests();
|
||||
foreach ($tests as $patterns => $cases) {
|
||||
foreach ($cases as $path => $expected_result) {
|
||||
$actual_result = drupal_match_path($path, $patterns);
|
||||
$this->assertIdentical($actual_result, $expected_result, format_string('Tried matching the path <code>@path</code> to the pattern <pre>@patterns</pre> - expected @expected, got @actual.', array('@path' => $path, '@patterns' => $patterns, '@expected' => var_export($expected_result, TRUE), '@actual' => var_export($actual_result, TRUE))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for testDrupalMatchPath(): set up an array of test cases.
|
||||
*
|
||||
* @return
|
||||
* An array of test cases to cycle through.
|
||||
*/
|
||||
private function drupalMatchPathTests() {
|
||||
return array(
|
||||
// Single absolute paths.
|
||||
'example/1' => array(
|
||||
'example/1' => TRUE,
|
||||
'example/2' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
// Single paths with wildcards.
|
||||
'example/*' => array(
|
||||
'example/1' => TRUE,
|
||||
'example/2' => TRUE,
|
||||
'example/3/edit' => TRUE,
|
||||
'example/' => TRUE,
|
||||
'example' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
// Single paths with multiple wildcards.
|
||||
'node/*/revisions/*' => array(
|
||||
'node/1/revisions/3' => TRUE,
|
||||
'node/345/revisions/test' => TRUE,
|
||||
'node/23/edit' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
// Single paths with '<front>'.
|
||||
'<front>' => array(
|
||||
$this->front => TRUE,
|
||||
"$this->front/" => FALSE,
|
||||
"$this->front/edit" => FALSE,
|
||||
'node' => FALSE,
|
||||
'' => FALSE,
|
||||
),
|
||||
// Paths with both '<front>' and wildcards (should not work).
|
||||
'<front>/*' => array(
|
||||
$this->front => FALSE,
|
||||
"$this->front/" => FALSE,
|
||||
"$this->front/edit" => FALSE,
|
||||
'node/12' => FALSE,
|
||||
'' => FALSE,
|
||||
),
|
||||
// Multiple paths with the \n delimiter.
|
||||
"node/*\nnode/*/edit" => array(
|
||||
'node/1' => TRUE,
|
||||
'node/view' => TRUE,
|
||||
'node/32/edit' => TRUE,
|
||||
'node/delete/edit' => TRUE,
|
||||
'node/50/delete' => TRUE,
|
||||
'test/example' => FALSE,
|
||||
),
|
||||
// Multiple paths with the \r delimiter.
|
||||
"user/*\rexample/*" => array(
|
||||
'user/1' => TRUE,
|
||||
'example/1' => TRUE,
|
||||
'user/1/example/1' => TRUE,
|
||||
'user/example' => TRUE,
|
||||
'test/example' => FALSE,
|
||||
'user' => FALSE,
|
||||
'example' => FALSE,
|
||||
),
|
||||
// Multiple paths with the \r\n delimiter.
|
||||
"test\r\n<front>" => array(
|
||||
'test' => TRUE,
|
||||
$this->front => TRUE,
|
||||
'example' => FALSE,
|
||||
),
|
||||
// Test existing regular expressions (should be escaped).
|
||||
'[^/]+?/[0-9]' => array(
|
||||
'test/1' => FALSE,
|
||||
'[^/]+?/[0-9]' => TRUE,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains Drupal\Tests\Core\Path\PathMatcherTest
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Path;
|
||||
|
||||
use Drupal\Component\Utility\String;
|
||||
use Drupal\Core\Path\PathMatcher;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @group Drupal
|
||||
* @see \Drupal\Core\Path\PathMatcher
|
||||
*/
|
||||
class PathMatcherTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The path matcher under test.
|
||||
*
|
||||
* @var \Drupal\Core\Path\PathMatcher
|
||||
*/
|
||||
protected $pathMatcher;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Path Matcher tests',
|
||||
'description' => 'Tests that path matching is working properly.',
|
||||
'group' => 'Path',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
// Create a stub config factory with all config settings that will be
|
||||
// checked during this test.
|
||||
$config_factory_stub = $this->getConfigFactoryStub(
|
||||
array(
|
||||
'system.site' => array(
|
||||
'page.front' => 'dummy',
|
||||
),
|
||||
)
|
||||
);
|
||||
$this->pathMatcher = new PathMatcher($config_factory_stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that standard paths works with multiple patterns.
|
||||
*
|
||||
* @dataProvider getMatchPathData
|
||||
*/
|
||||
public function testMatchPath($patterns, $paths) {
|
||||
foreach ($paths as $path => $expected_result) {
|
||||
$actual_result = $this->pathMatcher->matchPath($path, $patterns);
|
||||
$this->assertEquals($actual_result, $expected_result, String::format('Tried matching the path <code>@path</code> to the pattern <pre>@patterns</pre> - expected @expected, got @actual.', array(
|
||||
'@path' => $path,
|
||||
'@patterns' => $patterns,
|
||||
'@expected' => var_export($expected_result, TRUE),
|
||||
'@actual' => var_export($actual_result, TRUE),
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test path data.
|
||||
*
|
||||
* @return array
|
||||
* A nested array of pattern arrays and path arrays.
|
||||
*/
|
||||
public function getMatchPathData() {
|
||||
return array(
|
||||
array(
|
||||
// Single absolute paths.
|
||||
'example/1',
|
||||
array(
|
||||
'example/1' => TRUE,
|
||||
'example/2' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
// Single paths with wildcards.
|
||||
'example/*',
|
||||
array(
|
||||
'example/1' => TRUE,
|
||||
'example/2' => TRUE,
|
||||
'example/3/edit' => TRUE,
|
||||
'example/' => TRUE,
|
||||
'example' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
// Single paths with multiple wildcards.
|
||||
'node/*/revisions/*',
|
||||
array(
|
||||
'node/1/revisions/3' => TRUE,
|
||||
'node/345/revisions/test' => TRUE,
|
||||
'node/23/edit' => FALSE,
|
||||
'test' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
// Single paths with '<front>'.
|
||||
"<front>",
|
||||
array(
|
||||
'dummy' => TRUE,
|
||||
"dummy/" => FALSE,
|
||||
"dummy/edit" => FALSE,
|
||||
'node' => FALSE,
|
||||
'' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
// Paths with both '<front>' and wildcards (should not work).
|
||||
"<front>/*",
|
||||
array(
|
||||
'dummy' => FALSE,
|
||||
'dummy/' => FALSE,
|
||||
'dummy/edit' => FALSE,
|
||||
'node/12' => FALSE,
|
||||
'' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
// Multiple paths with the \n delimiter.
|
||||
"node/*\nnode/*/edit",
|
||||
array(
|
||||
'node/1' => TRUE,
|
||||
'node/view' => TRUE,
|
||||
'node/32/edit' => TRUE,
|
||||
'node/delete/edit' => TRUE,
|
||||
'node/50/delete' => TRUE,
|
||||
'test/example' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
// Multiple paths with the \r delimiter.
|
||||
"user/*\rexample/*",
|
||||
array(
|
||||
'user/1' => TRUE,
|
||||
'example/1' => TRUE,
|
||||
'user/1/example/1' => TRUE,
|
||||
'user/example' => TRUE,
|
||||
'test/example' => FALSE,
|
||||
'user' => FALSE,
|
||||
'example' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
// Multiple paths with the \r\n delimiter.
|
||||
"test\r\n<front>",
|
||||
array(
|
||||
'test' => TRUE,
|
||||
'dummy' => TRUE,
|
||||
'example' => FALSE,
|
||||
),
|
||||
),
|
||||
array(
|
||||
// Test existing regular expressions (should be escaped).
|
||||
'[^/]+?/[0-9]',
|
||||
array(
|
||||
'test/1' => FALSE,
|
||||
'[^/]+?/[0-9]' => TRUE,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue