When I install Drupal 8 in s subdirectory and use the URLgenerator to create a path with the subdir name repeated 2x:

like: http://127.0.0.1:8082/subdir-d8/subdir-d8/admin/structure/views/add

The generator is being called like on a route name (string):

$this->generator->generate($this->getRouteName());

the generator was pulled from the DIC container in a plugin create() method:

$container->get('url_generator')

This is causing test fails in #1981644: Figure out how to deal with 'title/title callback' and blocking progress on other issues. That patch can be used to reproduce the issue.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

pwolanin’s picture

So the bug seems to be that the output of the generator is getting passed back to the url() function which appends the base path again.

I'm not sure if the answer is "don't do that" or if we should be testing for that

pwolanin’s picture

Priority: Critical » Major

could maybe fix like this?

--- a/core/lib/Drupal/Core/Routing/UrlGenerator.php
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -272,6 +272,10 @@ public function generateFromPath($path = NULL, $options = array()) {
     }
     else {
       $path = ltrim($this->processPath($path, $options), '/');
+      if (!empty($this->basePath) && strpos($path, $this->basePath) === 0) {
+        // If the path has the base path, strip it off.
+        $path = substr($path, strlen($this->basePath));
+      }
     }
 
     if (!isset($options['script'])) {

pwolanin’s picture

Title: URLgenerator broken for Drupal installed in a subdirectory » URLgenerator broken for Drupal installed in a subdirectory - doesn't have a way to get a Drupal path

Well, I'm not sure that's right either - for now I'm stripping the base URL back of the result of ->generate(), but perhaps we need a new method added to the interface to support returning just the Drupal path for a route?

dawehner’s picture

Status: Active » Needs review
FileSize
2.17 KB
pwolanin’s picture

do we not need processPath? I was assuming that's where values like {node} would get replaced.

dawehner’s picture

FileSize
3.85 KB

Let's also add the path processor function and add unit tests

dawehner’s picture

FileSize
2.58 KB
5.49 KB

Replaced to trim the end and the start.

dawehner’s picture

Issue tags: +PHPUnit, +WSCCI
pwolanin’s picture

Status: Needs review » Reviewed & tested by the community
FileSize
2.46 KB
5.32 KB

RTBC after minor code comment and whitespace fixes.

dawehner’s picture

FileSize
1.36 KB
5.26 KB

Fixed documents based upon your latest changes.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.phpundefined
@@ -139,6 +138,18 @@ public function generate($name, $parameters = array(), $absolute = FALSE) {
+    // Remove any leading or trailing "/".
+    return trim($path, '/');
...
+    $path = '/' . $this->getPathFromRoute($name, $parameters);

Let's not do this... things that needs to trim the result of getPathFromRoute() can do it themselves...

pwolanin’s picture

Status: Needs work » Needs review
FileSize
2.23 KB
5.89 KB

Per IRC discussion w/ alexpott. A Drupal path should not have leading or trailing spaces.

So, we can have a commonly used protected method to avoid trimming and then adding back the '/'.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.phpundefined
@@ -108,6 +108,25 @@ public function setRequest(Request $request) {
+  protected function getUrlPathFromRoute($name, $parameters = array()) {

I can't think of a better name for now, but as it is internally, it feels great.

katbailey’s picture

Status: Reviewed & tested by the community » Needs work

Some logic seems to have gone askew in the moving around here - the $scheme_req variable which we use to store $route_requirements['_scheme'] before unsetting that from the $route_requirements array, is now getting set (or not) in the getUrlPathFromRoute() method, but being checked in the generate() method, where it will never be set.

It may well be that we never use $route_requirements['_scheme'] but we still need to fix the logic here as it doesn't make sense.

katbailey’s picture

Status: Needs work » Needs review
FileSize
2.18 KB
5.08 KB
9.09 KB

I've added a test for the 'scheme' route requirement. The test passes in HEAD but fails with this patch.
I hope it's ok that I also took this opportunity to rework the UrlGeneratorTest a little too as it was getting pretty unwieldy.

Setting to needs review just to show the test failure.

katbailey’s picture

Status: Needs review » Needs work
dawehner’s picture

Status: Needs work » Needs review
FileSize
3.35 KB
11.49 KB

Thanks for spotting the problem!

Let's extract the logic to get the route and use that information to build a proper url.

Status: Needs review » Needs work
Issue tags: -PHPUnit, -WSCCI

The last submitted patch, drupal-2031353-17.patch, failed testing.

pwolanin’s picture

Status: Needs work » Needs review
Issue tags: +PHPUnit, +WSCCI

#17: drupal-2031353-17.patch queued for re-testing.

pwolanin’s picture

small tweak to avoid calling getroute() 2x.

Status: Needs review » Needs work

The last submitted patch, drupal-2031353-20.patch, failed testing.

pwolanin’s picture

Weird - that should have been a no-op change.

pwolanin’s picture

Status: Needs work » Needs review
FileSize
973 bytes
11.9 KB

Ah, just missing the name in context now, which is only used for error messages, so this passes the path instead (oddly the route seems not to know its own name). Also, it looks like before this would have been a bit broken if you passed in an actual route object as that param.

Status: Needs review » Needs work
Issue tags: -PHPUnit, -WSCCI

The last submitted patch, drupal-2031353-23.patch, failed testing.

pwolanin’s picture

Status: Needs work » Needs review
Issue tags: +PHPUnit, +WSCCI

#23: drupal-2031353-23.patch queued for re-testing.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Opened an upstream bug report: https://github.com/symfony/symfony/issues/8394

dawehner’s picture

YesCT’s picture

Issue tags: +RTBC July 1

This issue was RTBC and passing tests on July 1, the beginning of API freeze.

msonnabaum’s picture

It's not immediately clear to me that getUrlPathFromRoute returns the exact same thing as getPathFromRoute, just with slashes added.

Changing the name isn't critical since it's not a public method, but could we maybe document that it exists to workaround what symfony's route returns?

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
+++ b/core/lib/Drupal/Core/Routing/PathBasedGeneratorInterface.phpundefined
@@ -30,6 +30,20 @@
+   * Gets the internal path of a route.

+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.phpundefined
@@ -105,17 +105,29 @@ public function setRequest(Request $request) {
+  public function getPathFromRoute($name, $parameters = array()) {
...
+   * Gets the path of a route.
...
+  protected function getUrlPathFromRoute(SymfonyRoute $route, $parameters = array()) {

I agree we need to clear this up a bit... what is the difference between Gets the internal path of a route. and Gets the path of a route??

Maybe the following will help us come up with something... I'm not 100% convinced myself :)

How about getUrlFromRoute() for the public function? And the protected function getPathFromRoute?

The docs for getUrlFromRoute() could be something like Gets the relative url for a route
The docs for getPathFromRoute() could be something like Gets the path of a route

dawehner’s picture

Mh, doesn't the url() method give you a path with a prefix, so exactly what we want to not have on the longrun?

dawehner’s picture

Status: Needs work » Needs review

well, getUrlFromRoute is pointless actually, because that is exactly the usecase of the generate method, or?

pwolanin’s picture

We are using it as part of the internal flow of generate, right? It's not pointless since it doesn't include any prefix (e.g. language) or alias.

We could call it internalPathWithSlashes() for all I care - it mostly exists since AlexPott didn't like stripping and then adding back the slashes for the generate flow.

pwolanin’s picture

Status: Needs review » Reviewed & tested by the community

@alexpott - I think you are confusing the issue.

The one and only thing we need to add to the public methods is a way to get the Drupal (internal) path for a route. That's what's missing currently.

We can bikeshed the name of the protected function, but it really doesn't matter - we can change it in a follow-up if it really bothers someone.

pwolanin’s picture

Status: Reviewed & tested by the community » Needs work

This think this is wrong - we don't want to call processPath() when we are looking for the system path, since that will potentially add a language prefix or do other things we don't want.

pwolanin’s picture

Status: Needs work » Needs review
FileSize
3.44 KB
12.06 KB

Right, and I think the test was wrong - it was looking for the path alias, not the path.

katbailey’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -WSCCI

This looks good to me.

chx’s picture

Status: Reviewed & tested by the community » Needs review
    $query_pos = strpos($path, '?');
    if ($query_pos !== FALSE) {
      $path = substr($path, 0, $query_pos);
     }

Meh. $path = preg_replace('/\?.*/', '', $path);

pwolanin’s picture

Issue tags: +WSCCI
FileSize
718 bytes
11.99 KB

fine that way too.

chx’s picture

Status: Needs review » Reviewed & tested by the community

Thanks

dawehner’s picture

Status: Reviewed & tested by the community » Needs review

Okay, so we save 3 lines of code with a regular expression. Whether this is easier to read or not is up to the reader. Can we please also just document what this
regex itself is doing here?

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

back to rtbc

pwolanin’s picture

Status: Reviewed & tested by the community » Needs review
FileSize
12.07 KB

just improves the code comment.

pwolanin’s picture

forgot to attach the incremental diff

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you very much!

alexpott’s picture

Title: URLgenerator broken for Drupal installed in a subdirectory - doesn't have a way to get a Drupal path » Change notice: URLgenerator broken for Drupal installed in a subdirectory - doesn't have a way to get a Drupal path
Priority: Major » Critical
Status: Reviewed & tested by the community » Active
Issue tags: +Needs change record

Committed 486f5d0 and pushed to 8.x. Thanks!

We still need a change notice for #1888424: Make Drupal's URL generation logic available to HttpKernel, and minimize code repetition/divergence and this should be part of it!

pwolanin’s picture

making a start on the change notice at https://drupal.org/node/2046643

pwolanin’s picture

Priority: Critical » Major
Status: Active » Fixed
Issue tags: -Needs change record

change notice is reasonably done.

jibran’s picture

Title: Change notice: URLgenerator broken for Drupal installed in a subdirectory - doesn't have a way to get a Drupal path » URLgenerator broken for Drupal installed in a subdirectory - doesn't have a way to get a Drupal path

Fixing title.

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