Skip to content

[Routing][FrameworkBundle] Allow configurable query encoding type in UrlGenerator #27969

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Conversation

likeuntomurphy
Copy link

Q A
Branch? master
Bug fix? no
New feature? yes
BC breaks? no
Deprecations? no
Tests pass? yes
Fixed tickets
License MIT
Doc PR symfony/symfony-docs#10073

This PR introduces a change that makes it very easy for developers to use RFC 1738 if they choose.

I have seen #19625, but I believe there are cases when PHP_QUERY_RFC1738 may be preferred even if the generator is not used in a form context, strictly speaking. One such case is search — it can begin with an actual form, but subsequent facet and pagination links can simply be generated. Pagination and related search links in Google use RFC 1738, as do pagination and “Pro Tip!” recommendation links on GitHub.

While we could simply replace %20 with + after generating facet URLs, it becomes much more complicated to accomplish the same effect in pagination links if you are using a bundle like KnpPaginatorBundle.

Extending the generator class seems excessive, as it would require copying over 150 lines of code to override the doGenerate method just to change one parameter.

@likeuntomurphy likeuntomurphy changed the title [Routing][FrameworkBundle] Allow configurable query encoding type in UrlGenerator [WIP][Routing][FrameworkBundle] Allow configurable query encoding type in UrlGenerator Jul 16, 2018
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch from b1fd637 to d4d210c Compare July 16, 2018 23:42
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch from d4d210c to 01c65c8 Compare July 16, 2018 23:48
Copy link
Contributor

@linaori linaori left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not entirely sure if this covers all use-cases. What if you generate a URL to an external page which doesn't follow the same encoding type? Should we add a reserved key for that in the parameters list perhaps?

*
* @return int
*/
public function getQueryEncType();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method is not used, should it really be added?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my comment in the main thread.

@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch 2 times, most recently from f03f7a9 to feac7fd Compare July 17, 2018 20:02
@likeuntomurphy likeuntomurphy changed the title [WIP][Routing][FrameworkBundle] Allow configurable query encoding type in UrlGenerator [Routing][FrameworkBundle] Allow configurable query encoding type in UrlGenerator Jul 17, 2018
Copy link
Author

@likeuntomurphy likeuntomurphy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback!

I understand your concern, but I am not convinced it falls within the scope of this change. Because the URL generator currently uses a hard-coded value, not being able to change the encoding type is already a limitation. I am less concerned with that limitation than I am with being able to change the encoding type deep inside the URL generator class in a simple way.

That said, you can actually now change the encoding type on the fly if you are so inclined. For instance, it is now possible to do something like,

$originalEncoding = $generator->getQueryEncodingType();
$generator->setQueryEncodingType($preferredEncoding);
$url = $generator->generateUrl(...$args);
$generator->setQueryEncodingType($originalEncoding);

I am not convinced that is the most elegant way of handling this situation, but it is the reason the getQueryEncodingType method is included in the ConfigurableQueryEncodingTypeInterface.

*
* @return int
*/
public function getQueryEncType();
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please see my comment in the main thread.

@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch from 6058e86 to f1bf418 Compare July 21, 2018 09:53
@nicolas-grekas nicolas-grekas added this to the next milestone Jul 23, 2018
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you decorate the generator and simply str_replace('%20', '+', parent::doGenerate(...) to achieve the same?

@likeuntomurphy
Copy link
Author

It would require a more complex block of code than that in order to execute the replacement only on the query component of the URL — str_replace would also catch %20 in the path and fragment components, which is not desired.

So it could be something like this:

$url = parent::doGenerate(...);

$parts = parse_url($url);

if (isset($parts['query'])) {
    $search = $parts['query'];
    $replace = str_replace('%20', '+', $search);
    $url = str_replace($search, $replace, $url);
}

For reliability I would be more comfortable with something like

if (isset($parts['query'])) {
    $parts['query'] = str_replace('%20', '+', $parts['query']);

    $url = '';
    
    if (isset($parts['scheme'])) {
        $url .= $parts['scheme'];
    }
    
    if (isset($parts['host'])) {
        ...
    }
    
    if (isset($parts['port'])) {
        ...
    }
    
    ...
}

But to me that starts to be excessively redundant with the heavy lifting doGenerate has already done, and it seems much preferable to simply have a way to toggle the parameter passed to http_build_query.

@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch 2 times, most recently from e69f459 to 0c6b5e6 Compare July 26, 2018 12:20
@Tobion
Copy link
Contributor

Tobion commented Jul 27, 2018

I don't think a global config is appropriate for this. Using RFC 1738 depends on the mime type of the page and you could even mix links with encoding RFC 1738 and RFC 3986 in the same page if you need to. So a global config would not fit there.
For this reason, it seems better to just write a helper function that replaces %20 with + as you pointed out and does not require a change in route generation.

While we could simply replace %20 with + after generating facet URLs, it becomes much more complicated to accomplish the same effect in pagination links if you are using a bundle like KnpPaginatorBundle.

You can provide a custom template for the pagination in the KnpPaginatorBundle that uses + for spaces: https://github.com/KnpLabs/KnpPaginatorBundle/blob/f4ece5b347121b9fe13166264f197f90252d4bd2/Twig/Extension/PaginationExtension.php#L46
Or you could write a response filter that just replaces all links in the pagination div.

@Tobion
Copy link
Contributor

Tobion commented Jul 27, 2018

Btw, the PR with the implementation and description is excellent. Good job! I just don't think this is the right solution to the problem.

@likeuntomurphy
Copy link
Author

Thanks, @Tobion.

I was trying to make a good argument by anticipating counterarguments — but ultimately, I would not have created the pull request if I did not feel that the framework should let the developer have control over which query encoding type is used and avoid complex workarounds. I understand that RFC 1738 may be considered outdated, and RFC 3986 is the default for good reason. But I want to copy what Google does! 😄

you could even mix links with encoding RFC 1738 and RFC 3986 in the same page
if you need to.

This is a point @iltar also raised, and it’s a good one. But I don’t understand how it is a relevant criticism of this PR, because you can’t do this currently.

As I see it, there are four options:

  1. as of [Routing] build query string with PHP_QUERY_RFC3986 #19625 — the generator always uses RFC 1738
  2. as of [Routing] Generate URLs in compliance with PHP_QUERY_RFC3986 #19639 — the generator always uses RFC 3986
  3. this PR — the generator always uses the developer’s preferred encoding type
  4. TBD — the generator lets you specify the encoding type at runtime (as a method arg perhaps?)

Are you suggesting we skip 3 and proceed straight to 4? Or do you feel that the framework should continue to use RFC 3986 exclusively and leave it to developers to find alternate ways of achieving RFC 1738 links?

@nicolas-grekas
Copy link
Member

Honestly, I'm fine with this feature. I don't see why we should force RFC 3986 over RFC 1738. Changing globally is fine to me. At least there are no practical downsides I know about. @Tobion I feel like you're suggesting there are differences related to the mime content type, can you elaborate?

@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch 4 times, most recently from b6e3ff0 to 661eaa9 Compare August 21, 2018 00:50
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch from 661eaa9 to c0cf250 Compare August 30, 2018 15:12
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch 2 times, most recently from 8a68f40 to 296314f Compare September 2, 2018 10:51
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch 3 times, most recently from 2ed84ae to d93fa0c Compare September 12, 2018 23:41
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch from d93fa0c to 42e7c4b Compare September 18, 2018 11:47
@nicolas-grekas
Copy link
Member

Can't we make RFC1738 the hardcoded behavior instead of RFC 3986 actually, for the query part only?

@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch from 42e7c4b to 741d99b Compare September 21, 2018 12:41
@likeuntomurphy
Copy link
Author

That was the original behavior before #19639 was merged, since the enc_type in http_build_query defaults to PHP_QUERY_RFC1738.

Undoing that change would nullify the discussion and decisions in #19625 and #19639. It would also create a BC break for anyone who made adjustments because of the previous BC break (#20856).

@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch 2 times, most recently from ff34dc8 to 33581f8 Compare October 3, 2018 13:23
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch 3 times, most recently from 9c49978 to d451b22 Compare October 11, 2018 12:46
@nicolas-grekas nicolas-grekas self-assigned this Oct 21, 2018
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch from d451b22 to 1a3eab4 Compare October 22, 2018 23:27
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch 2 times, most recently from af038a8 to 26dc8ef Compare November 13, 2018 15:49
@likeuntomurphy likeuntomurphy force-pushed the configurable_query_enc_type branch from 26dc8ef to 94d59fe Compare December 7, 2018 17:26
Copy link
Member

@nicolas-grekas nicolas-grekas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Time to move forward here.
OK on my side. @symfony/deciders?

@Tobion
Copy link
Contributor

Tobion commented Dec 13, 2018

Global configs are a dead end IMO. Let's say I write a reusable bundle and generate links to a controller. I cannot even assume anymore that I can read links properly that I generated myself.

@lyrixx
Copy link
Member

lyrixx commented Dec 14, 2018

I agree with @Tobion here

@nicolas-grekas
Copy link
Member

I'm closing as won't fix: the currently generated URLs work fine so the matter is purely cosmetic, and we didn't reach an agreement to find the best way this should be configurable if it should.
Thanks for opening.

@nicolas-grekas nicolas-grekas modified the milestones: next, 4.3 Apr 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants