Problem/Motivation

With Drupal 8.0.3,

drush php-eval 'print_r(\Drupal::urlGenerator()->generate("entity.node.content_translation_overview",["node" => 1], \Symfony\Component\Routing\Generator\UrlGeneratorInterface::ABSOLUTE_URL) . PHP_EOL);'

Outputs an absolute url:

http://default/node/1/translations

With Drupal 8.1.x, the same command outputs a relative url:

/node/1/translations

See https://github.com/symfony/routing/commit/502cac1e711e708044e23a38ef3a45... for the root cause.

Proposed resolution

Change the logic in our \Drupal\Core\Routing\UrlGenerator::generateFromRoute() and add explicit tests that looks we are lacking.

Remaining tasks

Provide a first patch

User interface changes

None.

API changes

Ideally none, we can abstract this Symfony change.

Data model changes

None.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

penyaskito created an issue. See original summary.

penyaskito’s picture

Status: Active » Needs review
FileSize
698 bytes

Initial patch.

dawehner’s picture

Issue tags: +Needs tests

Let's ensure we have test coverage for the different available types ...

catch’s picture

Priority: Normal » Major
Issue tags: +8.1.0 release notes

Tagging for release notes in case it's not fixed in time.

I'm assuming this breaks install in subdirectories, so bumping to major for that reason. If I've got that wrong and it's just a correct absolute vs. relative url then we could bump back to normal though.

Status: Needs review » Needs work

The last submitted patch, 2: 2674780-2.patch, failed testing.

dawehner’s picture

In general its great that we got this committed so people find the issue.

esclapes’s picture

Status: Needs work » Needs review
FileSize
3.04 KB

Looking at the root issue, there is a missmatch between the Synfony UrlGeneratorInterface->generate() which expects $refernceType to be a constant and our implemenentation at UrlGenerator->generate() that even renames $refernceType to absolute and uses a boolean.

A have added two tests for absolute and relative URL generation (some part of them might be redundant as I am not familiar with the bubbling thing) and moved the fix from #2 to the generate method.

esclapes’s picture

This is the same patch, but fixing the interface missmatch.

EDIT with more info.

public function generate($name, $parameters = array(), $reference_type = self::ABSOLUTE_PATH)

instead of

public function generate($name, $parameters = array(), $absolute = FALSE)

I have only run the tests with ./vendor/bin/phpunit --bootstrap ./core/tests/bootstrap.php core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php, and they pass with both patches.

The last submitted patch, 7: unexpected_api_change-2674780-7.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 8: unexpected_api_change-2674780-8.patch, failed testing.

esclapes’s picture

Issue tags: -Needs tests

Not sure why the new tests are failing. The messages in QA are these:

testAliasGenerationUsingInterfaceConstants
fail: [Other] Line 222 of core/tests/Drupal/Tests/Core/Render/MetadataBubblingUrlGeneratorTest.php:
--- Expected
testAbsoluteURLGenerationUsingInterfaceConstants
fail: [Other] Line 402 of core/tests/Drupal/Tests/Core/Render/MetadataBubblingUrlGeneratorTest.php:
--- Expected

Any idea? Test pass in my VM

catch’s picture

Status: Needs work » Needs review
FileSize
928 bytes
4.07 KB

Debugged the test locally. MetadataBubblingUrlGenerator needed exactly the same change as UrlGenerator. The test methods you added passed for that test, but this is a different test that inherits from the one you updated which is why it confusingly looks like the test is passing when you run just that one.

dawehner’s picture

+++ b/core/lib/Drupal/Core/Render/MetadataBubblingUrlGenerator.php
@@ -96,8 +96,8 @@ protected function bubble(GeneratedUrl $generated_url, array $options = []) {
+    $options['absolute'] = is_bool($reference_type) ? $reference_type : $reference_type === self::ABSOLUTE_URL;

+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -272,8 +272,8 @@ protected function getInternalPathFromRoute($name, SymfonyRoute $route, $paramet
+    $options['absolute'] = is_bool($reference_type) ? $reference_type : $reference_type === self::ABSOLUTE_URL;

Mh, so this fixes the case of ABSOLUTE_URL/ABSOLUTE_PATH but should we not also deal with the case of it being a string, see

        if (is_bool($referenceType) || is_string($referenceType)) {
            @trigger_error('The hardcoded value you are using for the $referenceType argument of the '.__CLASS__.'::generate method is deprecated since version 2.8 and will not be supported anymore in 3.0. Use the constants defined in the UrlGeneratorInterface instead.', E_USER_DEPRECATED);

            if (true === $referenceType) {
                $referenceType = self::ABSOLUTE_URL;
            } elseif (false === $referenceType) {
                $referenceType = self::ABSOLUTE_PATH;
            } elseif ('relative' === $referenceType) {
                $referenceType = self::RELATIVE_PATH;
            } elseif ('network' === $referenceType) {
                $referenceType = self::NETWORK_PATH;
            }
        }

Given that do we also expand the test coverage to use the other 2 reference types (relative path and network path)?

catch’s picture

Hmm well we only ever supported ABSOLUTE_URL/ABSOLUTE_PATH with the previous method signature via the $absolute = FALSE bool, so no-one should ever have been passing a string in there. Since this is just a bc layer I don't think we should support things we didn't previously by it.

Don't know about RELATIVE_PATH and NETWORK_PATH - again we didn't previously support them, I guess we could add coverage to ensure that now they are supported they actually work though.

dawehner’s picture

Okay that is a fair point. Can we open a follow up, given that we implement that interface, which documents it exists. People might expand it works

catch’s picture

Opened #2676288: Symfony 2.8 supports RELATIVE_URL and NETWORK_URL in the URL generator - add test coverage.

+++ b/core/lib/Drupal/Core/Routing/UrlGenerator.php
@@ -272,8 +272,8 @@ protected function getInternalPathFromRoute($name, SymfonyRoute $route, $paramet
+  public function generate($name, $parameters = array(), $reference_type = self::ABSOLUTE_PATH) {

I'm not sure if coding standards allow it, but it would be good to document the @deprecated parameters for $reference_type/$absolute here.

dawehner’s picture

I'm not sure if coding standards allow it, but it would be good to document the @deprecated parameters for $reference_type/$absolute here.

IMHO we should also keep the snake case of the interface, especially because otherwise API module might have a problem with scanning it.

esclapes’s picture

Includes suggestioins from #17 and #16:

we should also keep the snake case of the interface, especially because otherwise API module might have a problem with scanning it.

Indeed, the current generated docs do not detect the interface inheritance for the generate method.

I'm not sure if coding standards allow it, but it would be good to document the @deprecated parameters for $reference_type/$absolute here.

There seems to be no way to deprecate parameters in docblock so I used an if/else block and included a trigger_error. It makes for a bigger patch but it makes sense to rise a notice. I have found a few usages of trigger_error in core so I guess it is fine according to CS.

esclapes’s picture

Just realized that trigger_error makes phpunit fail. I see that other core components use the @trigger_error and passes with phpunit. Attached.

The last submitted patch, 18: unexpected_api_change-2674780-18.patch, failed testing.

catch’s picture

I personally wouldn't use trigger_error() yet, this is Symfony's deprecation not ours yet - we can just write that the bool is deprecated in the @param docs for now. I'd like to start using E_USER_DEPRECATED a lot more in 8.2.x though so good for a follow-up. See #2575081: [policy, no patch] Use E_USER_DEPRECATED in Drupal 8 minor releases for more discussion of that.

esclapes’s picture

OK, this patch is based on #12 and renames the argument to $referenceType in order to match the interface signature.

As per #1994890: Allow {@inheritdoc} and additional documentation there seems to be no way to add extra information to @inheritdoc so I did nothing regarding the deprecation info.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Can we add a follow up to actually support the other reference types as well, both in generate() and in generateFromRoute() ? For now this patch resolves the problem with the BC break.

IMHO its fine to stick with the current situation in terms of the documentation. generate() is not recommended API anyway.

penyaskito’s picture

dawehner’s picture

You are right!

catch’s picture

Issue tags: +beta target
alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed c4145ed and pushed to 8.1.x and 8.2.x. Thanks!

  • alexpott committed ce88723 on 8.2.x
    Issue #2674780 by esclapes, catch, penyaskito, dawehner: Unexpected API...

  • alexpott committed c4145ed on 8.1.x
    Issue #2674780 by esclapes, catch, penyaskito, dawehner: Unexpected API...

Status: Fixed » Closed (fixed)

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