Problem/Motivation

We are converting most of core to OOP. drupal_match_path is procedural and is called from a lot of OO code. This makes that code difficult to unit test.

Proposed resolution

Create a new PathMatcher service and move procedural code from path.inc to the service. Mark procedural code as deprecated, and do conversions in a follow up.

Remaining tasks

Do it.

User interface changes

None.

API changes

drupal_match_path in path.inc are marked deprecated.

Follow ups

Files: 
CommentFileSizeAuthor
#33 interdiff.txt3.47 KBkim.pepper
#33 2272201-path-service-33.patch17.53 KBkim.pepper
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,845 pass(es). View
#30 interdiff.txt9.48 KBkim.pepper
#30 2272201-path-service-30.patch14.06 KBkim.pepper
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,756 pass(es). View
#27 2272201-path-service-27.patch8.03 KBkim.pepper
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,789 pass(es). View
#25 2272201-path-service-25.patch7.96 KBkim.pepper
FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] Unable to apply patch 2272201-path-service-25.patch. Unable to apply patch. See the log in the details link for more information. View
#16 interdiff.txt543 byteskim.pepper
#16 2272201-path-service-16.patch7.96 KBkim.pepper
FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] Unable to apply patch 2272201-path-service-16.patch. Unable to apply patch. See the log in the details link for more information. View
#14 interdiff.txt3.28 KBkim.pepper
#14 2272201-path-service-14.patch8.02 KBkim.pepper
FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,740 pass(es), 31 fail(s), and 305 exception(s). View
#8 interdiff.txt1.41 KBkim.pepper
#8 2272201-path-service-8.patch8.23 KBkim.pepper
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,750 pass(es). View
#5 coverage.png31.31 KBkim.pepper
#4 interdiff.txt4.07 KBkim.pepper
#4 2272201-path-service-4.patch7.95 KBkim.pepper
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,769 pass(es). View
#2 2272201-path-service-2.patch7.49 KBkim.pepper
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,683 pass(es). View

Comments

kim.pepper’s picture

kim.pepper’s picture

Status: Active » Needs review
FileSize
7.49 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,683 pass(es). View

Initial commit of a PathMatcher service. This only includes drupal_match_path for now.

larowlan’s picture

My 2c

  1. +++ b/core/lib/Drupal/Core/Path/PathMatcher.php
    @@ -0,0 +1,69 @@
    +      // Convert path settings to a regular expression.
    +      // Therefore replace newlines with a logical or, /* with asterisks and the
    +      // <front> with the frontpage.
    

    Some spacing could be cleaned up here? Also sentence doesn't really make sense.

  2. +++ b/core/lib/Drupal/Core/Path/PathMatcherInterface.php
    @@ -0,0 +1,28 @@
    + * Interface for URL path matchers.
    

    nitpick: I think this has to start with a verb, 'Provides an' maybe

  3. +++ b/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php
    @@ -0,0 +1,84 @@
    +  /**
    +   * Test that standard paths works with multiple patterns.
    +   */
    +  public function testPathsMultiplePatterns() {
    +    $patterns = array('my/pass/page', 'my/pass/page2', 'foo');
    +    $this->assertTrue($this->pathMatcher->matchPath('my/pass/page', $patterns), 'The path my/pass/page matches.');
    +    $this->assertTrue($this->pathMatcher->matchPath('my/pass/page2', $patterns), 'The path my/pass/page2 matches.');
    +  }
    +
    +  /**
    +   * Test paths match against wildcards.
    +   */
    +  public function testWildcardPath() {
    +    $patterns = array('my/pass/*');
    +    $this->assertTrue($this->pathMatcher->matchPath('my/pass/page3', $patterns), 'The path my/pass/page3 matches.');
    +  }
    +
    +  /**
    +   * Test a missing path does not match.
    +   */
    +  public function testNoMatchPath() {
    +    $patterns = array('my/pass/page', 'my/pass/page2', 'foo');
    +    $this->assertFalse($this->pathMatcher->matchPath('my/pass/page4', $patterns), 'The path my/pass/page4 does not match.');
    +  }
    

    these lend themselves to a provider?

kim.pepper’s picture

FileSize
7.95 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,769 pass(es). View
4.07 KB

Thanks for the review!

Fixes for #3.

kim.pepper’s picture

FileSize
31.31 KB

While there is very little code to cover, code coverage report looks good!

dawehner’s picture

  1. +++ b/core/lib/Drupal/Core/Path/PathMatcher.php
    @@ -0,0 +1,67 @@
    +  public function __construct(ConfigFactoryInterface $config_factory) {
    +    $this->frontPage = $config_factory->get('system.site')->get('page.front');
    +  }
    

    It would be great to not do anything in the constructor. Calling the config factory methods could deal with language overrides which could trigger the entity system and what not. This resulted in a couple of circular dependencies in the past, so we figure out that it is a bad pattern.

  2. +++ b/core/lib/Drupal/Core/Path/PathMatcherInterface.php
    @@ -0,0 +1,28 @@
    +   * @param string[] $patterns
    

    Nice!

dawehner’s picture

Status: Needs review » Needs work

:(

kim.pepper’s picture

Status: Needs work » Needs review
FileSize
8.23 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,750 pass(es). View
1.41 KB

Thanks for the review dawehner!

I've changed it so the configure front page gets called only when needed.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you

hass’s picture

Why are we supporting arrays and strings as patterns and not only arrays?

tim.plunkett’s picture

@hass, open a feature request. This just moves the function to a method, we're not changing the expectations or internals.

hass’s picture

It changes internals.

kim.pepper’s picture

+++ b/core/lib/Drupal/Core/Path/PathMatcher.php
@@ -0,0 +1,79 @@
+  public function matchPath($path, array $patterns) {
+    // Convert array to a string for easier find and replace.
+    $pattern_string = implode("\n", $patterns);

@hass is correct. This changes the method signature from taking a string to an array of strings, then joining them again.

kim.pepper’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
8.02 KB
FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,740 pass(es), 31 fail(s), and 305 exception(s). View
3.28 KB

This rolls back the api change so matchPath just takes a single string of patterns separated by newline. This is now essentially just moving old code into a service.

Kim

Status: Needs review » Needs work

The last submitted patch, 14: 2272201-path-service-14.patch, failed testing.

kim.pepper’s picture

Status: Needs work » Needs review
FileSize
7.96 KB
FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] Unable to apply patch 2272201-path-service-16.patch. Unable to apply patch. See the log in the details link for more information. View
543 bytes

Missed something in the rollback. Try again!

hass’s picture

:-( i was happy about this array change... Just wished it will change consequently in all places of core... :-)

kim.pepper’s picture

@hass Are you happy to mark this reviewed and make api changes in a follow-up?

ParisLiakos’s picture

Title: Move drupal_match_path and other functions in path.inc to a service » Move drupal_match_path in path.inc to a service
Issue summary: View changes

Looks good but needs a draft change notice:)

kim.pepper’s picture

Thanks @ParisLiakos. Added a draft change notice [#2274675]

ParisLiakos’s picture

Issue summary: View changes
Status: Needs review » Reviewed & tested by the community

i liked the array version too, but lets do a straight conversion here and move the array change to a followup.

thanks @kim.pepper !

kim.pepper’s picture

hass’s picture

Sounds very good to me. Thx.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 16: 2272201-path-service-16.patch, failed testing.

kim.pepper’s picture

Status: Needs work » Needs review
FileSize
7.96 KB
FAILED: [[SimpleTest]]: [PHP 5.4 MySQL] Unable to apply patch 2272201-path-service-25.patch. Unable to apply patch. See the log in the details link for more information. View

Re-roll after PSR4 got committed.

Status: Needs review » Needs work

The last submitted patch, 25: 2272201-path-service-25.patch, failed testing.

kim.pepper’s picture

Status: Needs work » Needs review
FileSize
8.03 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,789 pass(es). View

Another re-roll

hass’s picture

Status: Needs review » Reviewed & tested by the community

Looks green

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

Can we remove Drupal\system\Tests\Path\MatchPathTest - and ensure that all the test cases that covers are covered by the phpunit test.

kim.pepper’s picture

Status: Needs work » Needs review
FileSize
14.06 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,756 pass(es). View
9.48 KB

I've removed Drupal\system\Tests\Path\MatchPathTest and copied all the tests in there over to core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php

jibran’s picture

Status: Needs review » Reviewed & tested by the community

Thank you. Back to RTBC.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

We can now inject this into the new RequestPath condition

kim.pepper’s picture

Status: Needs work » Needs review
FileSize
17.53 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 71,845 pass(es). View
3.47 KB

Injected PathMatcher into the request path condition.

Status: Needs review » Needs work

The last submitted patch, 33: 2272201-path-service-33.patch, failed testing.

kim.pepper’s picture

33: 2272201-path-service-33.patch queued for re-testing.

tim.plunkett’s picture

Status: Needs work » Reviewed & tested by the community

Everything in here looks good. @kim.pepper++

+++ /dev/null
@@ -1,131 +0,0 @@
-class MatchPathTest extends WebTestBase {

+++ b/core/tests/Drupal/Tests/Core/Path/PathMatcherTest.php
@@ -0,0 +1,176 @@
+class PathMatcherTest extends UnitTestCase {

Nice!

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed 9b821cd and pushed to 8.x. Thanks!

  • Commit 9b821cd on 8.x by alexpott:
    Issue #2272201 by kim.pepper: Move drupal_match_path in path.inc to a...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.