diff --git a/core/core.services.yml b/core/core.services.yml index c4b55ac..05d9477 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -185,6 +185,9 @@ services: path.alias_manager: class: Drupal\Core\Path\AliasManager arguments: ['@path.alias_storage', '@path.alias_whitelist', '@language_manager'] + path.matcher: + class: Drupal\Core\Path\PathMatcher + arguments: ['@config.factory'] http_client: class: Drupal\Core\Http\Client tags: diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index b00d23b..7108d24 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -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); diff --git a/core/includes/path.inc b/core/includes/path.inc index 6043749..3898d15 100644 --- a/core/includes/path.inc +++ b/core/includes/path.inc @@ -41,27 +41,13 @@ 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 with the frontpage. - $to_replace = array( - '/(\r\n?|\n)/', // newlines - '/\\\\\*/', // asterisks - '/(^|\|)\\\\($|\|)/' // - ); - $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); + $patterns_array = preg_split('/(\r\n?|\n)/', $patterns); + return \Drupal::service('path.matcher')->matchPath($path, $patterns_array); } /** diff --git a/core/lib/Drupal/Core/Path/PathMatcher.php b/core/lib/Drupal/Core/Path/PathMatcher.php new file mode 100644 index 0000000..fada60a --- /dev/null +++ b/core/lib/Drupal/Core/Path/PathMatcher.php @@ -0,0 +1,67 @@ +frontPage = $config_factory->get('system.site')->get('page.front'); + } + + /** + * {@inheritdoc} + */ + public function matchPath($path, array $patterns) { + // Convert array to a string for easier find and replace. + $pattern_string = implode("\n", $patterns); + if (!isset($this->regexes[$pattern_string])) { + // Convert path settings to a regular expression. + $to_replace = array( + // Replace newlines with a logical 'or'. + '/(\r\n?|\n)/', + // Quote asterisks. + '/\\\\\*/', + // Quote keyword. + '/(^|\|)\\\\($|\|)/', + ); + $replacements = array( + '|', + '.*', + '\1' . preg_quote($this->frontPage, '/') . '\2', + ); + $patterns_quoted = preg_quote($pattern_string, '/'); + $this->regexes[$pattern_string] = '/^(' . preg_replace($to_replace, $replacements, $patterns_quoted) . ')$/'; + } + return (bool) preg_match($this->regexes[$pattern_string], $path); + } +} diff --git a/core/lib/Drupal/Core/Path/PathMatcherInterface.php b/core/lib/Drupal/Core/Path/PathMatcherInterface.php new file mode 100644 index 0000000..402641b --- /dev/null +++ b/core/lib/Drupal/Core/Path/PathMatcherInterface.php @@ -0,0 +1,28 @@ + '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' => 'user', + ), + ) + ); + $this->pathMatcher = new PathMatcher($config_factory_stub); + $this->patterns = "my/pass/page\r\nmy/pass/page2\r\nfoo"; + } + + + /** + * Test that paths matching works with multiple patterns. + * + * @dataProvider getMatchPathData + */ + public function testMatchPath($patterns, $paths) { + foreach ($paths as $path) { + $this->assertTrue($this->pathMatcher->matchPath($path, $patterns), "The path $path matches the patterns."); + } + } + + /** + * Test that standard paths works with multiple patterns. + * + * @dataProvider getNoMatchPathData + */ + public function testNoMatchPath($patterns, $paths) { + foreach ($paths as $path) { + $this->assertFalse($this->pathMatcher->matchPath($path, $patterns), "The path $path does not match the patterns."); + } + } + + /** + * Provides test path data. + * + * @return array + * A nested array of pattern arrays and path arrays. + */ + public function getMatchPathData() { + return array( + // Match explicit path pattern. + array( + array('my/pass/page', 'my/pass/page2', 'foo'), + array('my/pass/page', 'my/pass/page2'), + ), + // Match wildcard path pattern. + array( + array('my/pass/*'), + array('my/pass/page3'), + ), + ); + } + + /** + * Provides test path data for non-matches. + * + * @return array + * A nested array of pattern arrays and path arrays. + */ + public function getNoMatchPathData() { + return array( + array( + array('my/pass/page', 'my/pass/page2', 'foo'), + array('my/pass/page4'), + ), + ); + } +}