Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
In the code for UrlHelper::buildQuery() is the comment:
* @todo Remove this function once PHP 5.4 is required as we can use just
* http_build_query() directly.
Since we now require PHP 5.4, we should proceed with this.
Proposed resolution
For now replace the guts of the method with the built-in functional call.
Remaining tasks
make patch, see if any tests fail
User interface changes
N/A
API changes
N/A
Comment | File | Size | Author |
---|---|---|---|
#47 | 224857-47.interdiff.txt | 5.61 KB | neclimdul |
#47 | 224857-47.patch | 21.25 KB | neclimdul |
#27 | optimize-2248257-27.patch | 14.74 KB | neclimdul |
#27 | optimize-2248257-27.interdiff.txt | 1.06 KB | neclimdul |
#27 | http_build_query_benchmarks.txt | 1.44 KB | neclimdul |
Comments
Comment #1
pwolanin CreditAttribution: pwolanin commentedThis outputs the brackets urlencoded too, which is a little annoying.
Comment #3
pwolanin CreditAttribution: pwolanin commented1: 2248257-1.patch queued for re-testing.
Comment #5
pwolanin CreditAttribution: pwolanin commented1: 2248257-1.patch queued for re-testing.
Comment #7
pwolanin CreditAttribution: pwolanin commented1: 2248257-1.patch queued for re-testing.
Comment #11
dawehner1: 2248257-1.patch queued for re-testing.
Comment #13
pwolanin CreditAttribution: pwolanin commentedhttp://tools.ietf.org/html/rfc3986 and related discussed suggest the PHP built-in escaping is correct in terms of the spec.
Patch with test fixes. neclimdul suggested changing it so we just test against the PHP function in case someone changes the wrapper.
Comment #14
tim.plunkettHow is this asserting *anything*? It's just the implementation compared to the method using that implementation. The $expected should not be removed, IMO
Isn't this the entire reason why we have this implementation? Those are ugly.
Comment #15
neclimdul1) Yeah, so I mentioned we should remove it since we don't want to be in the business of testing php's code. That's the job of php's test suite. However if we're concerned about coverage then we could do that. It basically just confirms we're calling it correctly I guess... I'm not really sure how to test this to be honest.
2) Yeah... those are ugly. Cleaning them up seems likely to be a beast though since we get back a string.
Looking at the changes it seems we're also introducing a "regression" in not supporting
array('foo' => NULL)
and requiringarray('foo' => '')
. I'm actually OK with this unless there are some deeper implications I can't think of.Comment #16
pwolanin CreditAttribution: pwolanin commentedWe can cut the pointless tests for sure - my only thought to leave it was as a regression test if someone tries to change the implementation?
So, in terms of omitting NULL values, PHP itself parses a query key with no = as having an empty string value. So ?x and ?x= are both found in $_GET['x'] as ''
While this is slightly ugly, are any en users going to care about the rare query string with a trailing = that didn't have it before?
Comment #17
tim.plunkettThis change is not ideal. We're now essentially testing that calling a method two different times will give the same results. Please revert!
We shouldn't have to change our tests :(
Comment #19
dagmarRe-rolled, doesn't applied anymore. Let's start again from #1 I can't see the results from the logger two years after this patch was tested.
Comment #21
neclimdulOh goodness we have that much code still doing string matches :(
Comment #22
neclimdulThis will still fail but it fixes UrlHelperTest. Similar to pwolanin's approach but slightly different. It looks like it changed more but it actually changed less I think. Every case is covered as it was before. By comparing that the result of the method decodes to the same value we're testing the intent of the method without testing the exact string output. I attached the test change alone to confirm its testing and passing the same without the optimization.
The gotcha here is parse_str(), which decodes query strings, drops leading spaces from keys for some crazy reason. As best I can tell we have to string compare on this one but luckily the output of the 2 implementation is identical for this case.
I also hacked the
['foo' => NULL];
logic in as you'll see from the interdiff so that test case is also unchanged. I'd prefer we stick with http_build_query() directly since we documented that as the goal of the method but we should also keep with our API promise and be consistent across minor releases. Especially if we have a test that caught the change. We can change that in 9 (or remove entirely).Undoubtedly the other string matches like in bigpipe are going to still fail though. :(
Comment #24
neclimdulNeat fact, this was casting objects. http_build_query() doesn't do that. Turns out by accident we had coverage for this "functionality" because of t() and safestring. Another back ported functionality added. Added explicit unit test since that's probably an important usability improvement.
Comment #26
neclimdulThe bigpipe method that builds the ids is protected so we can't call it in the test without modifying the class :(
This uses our helpers though instead of hardcoding the strings though so its a bit better off.
Comment #27
neclimdulDoing some benchmarks I realized the if statements where unnecessary and its a bit faster to just cast everything. string casting a string is significantly cheaper then applying the 2 if statements.
The benchmarks are a bit of a mixed bag though. We see huge improvements in 5.x php but in 7 we are just a smidge slower in most cases. The exception being nested data which is always a lot faster. Seems the array walk is a bit slower then the loop for some reason that might be worth investigating.
Comment #28
dagmar@neclimdul I assume you already know this but, have you considered use reflection to test private methods?
Comment #29
neclimdulI'd avoid using reflection for that since its pretty heavy. Much easier to create a stub and expose the method through it. Definitely possible though. I went with the hacky solution since I planned on making a follow up to discuss making it public.
Comment #36
idimopoulos CreditAttribution: idimopoulos at Randstad Digital for European Commission and European Union Institutions, Agencies and Bodies commentedI am not sure if this is correct.
I have tested the
http_build_query
with booleans and it converts them to numbers. 1 for true and 0 for false.This will convert the false to an empty string.
This will keep the
::buildQuery
being different that thehttp_build_query
itself.format_string is now deprecated. This should be updated to use the
FormattableMarkup
class.We need to also test the boolean values here.
I will add one more case.
I have an issue with the boolean values here.
While the other cases work fine, using
['autoplay' => FALSE, 'fullscreen' => TRUE]
.The
UrlHelper::buildQuery($query)
returnsautoplay=&fullscreen=1
.The
http_build_query
returnsautoplay=0&fullscreen=1
.The second problem is the parse_str. It will also convert the query into the following array:
Even if this is not the same as the initial array, the
$this->assertEquals
is considering them equals.In addition, if I try to work around it and end up having
autoplay = 0
, the assertion will fail because string 0 is not equals to false.IMO we should not test the query encoding by parsing the string. The query built is not obliged to be decoded since multiple values might be converted to the same result (e.g. both 0 and false are converted to "0" by
http_build_query
).I am re-rolling the patch fixing also the issues detected here. I will follow the previous philosophy of keeping the array_walk before doing the
http_build_query
but I think we should not workaround in order to provide results different that what php would do.Comment #37
idimopoulos CreditAttribution: idimopoulos at Randstad Digital for European Commission and European Union Institutions, Agencies and Bodies commentedI would like to, however, see what failures are there if we consider a proper solutions that query parameters with NULL are removed (just like
http_build_query
does).Comment #39
claudiu.cristea@neclimdul, @idimopoulos instead of adapting this function that will be dropped anyway, why not replacing all occurrences from core with
http_build_query()
? Of course, on each usage we'll have to account, if case, the different output. Then we deprecateUrlHelper::buildQuery()
.Comment #40
claudiu.cristea(deleted)
Comment #41
idimopoulos CreditAttribution: idimopoulos at Randstad Digital for European Commission and European Union Institutions, Agencies and Bodies commented@claudiu tbh, I also like that idea. I am attaching a small patch to check how tests will behave. I replaced the usage of the
::buildQuery
and cleaned up the test. I also deprecated the method.Comment #43
claudiu.cristeaIt seems that was a decision or, at least, a discussion to keep this method as it is because of the different output. See #2322059-50: Keep the UrlHelper::buildQuery method and remove @todo. It's likely that both issues will be "won't fix". Let's put on hold the work here till something is decided.
Comment #44
neclimdulIt sounds like its being overlooked still that buildQuery does object casting which http_build_query fails to do. This means if you have a stringable object in your query like a markup string or as the new test I added demonstrates an Attribute it fails to produce the correct output.
Granted this is super easy to miss and undocumented but this was a breaking change to core I documented in my patch and in the early comments. Getting rid of this method is likely to be a strangely breaking change I'm not sure makes sense.
Here's a re-roll of the earlier functioning patch. Also adding back my credit... not sure why that was removed.
Comment #47
neclimdulLets try this again now that this method's fate is decided.
Comment #55
joshuautley CreditAttribution: joshuautley commentedWith the recent release of Drupal 10 are there any other maintainers of core considering this for an upcoming minor version release?
Reference https://www.drupal.org/project/commerce_usps/issues/3326069#comment-1483...
With the holidays in full swing, this has become a hot topic.
Thank you everyone for your time.