Problem/Motivation
The pager_query_add_page() function, used by the pager to prepare the querystring of the pager links, fails to reflect changes done programmatically to other querystring elements than the 'page' one (i.e. by setting specific querystring elements via the '#parameters' of the 'pager' theme). The query elements of the current request always prevail.
Proposed resolution
- Just swap the order of the arrays merged together in the function, to ensure any parameter passed programmatically overrides the one coming from the current request.
- Add tests.
Remaining tasks
- Review
User interface changes
None.
API changes
None.
Original report by @mondrake
Hi,
if you invoke theme_pager() passing querystring parameters through $variables['parameters'], AND the current url has already a different value for any of the parameters passed, then the current url's value overrides any value passed programmatically.
Steps to reproduce - Drupal 8:
Run the attached code in a page callback function:
// #1588138 - theme_pager overrides parameters passed programmatically - example
// Example query.
$header_0 = array(
array('data' => 'wid'),
array('data' => 'type'),
array('data' => 'timestamp'),
);
$query_0 = db_select('watchdog', 'd')->extend('Drupal\Core\Database\Query\PagerSelectExtender')->element(0);
$query_0->fields('d', array('wid', 'type', 'timestamp'));
$result_0 = $query_0
->limit(5)
->orderBy('d.wid')
->execute();
$rows_0 = array();
foreach ($result_0 as $row) {
$rows_0[] = array('data' => (array) $row);
}
$build['pager_table_0'] = array(
'#theme' => 'table',
'#header' => $header_0,
'#rows' => $rows_0,
'#empty' => t("There are no watchdog records found in the db"),
);
// Counter of clicks to the current pager.
$query_params = pager_get_query_parameters();
$pager_clicks = isset($query_params['pager_clicks']) ? ($query_params['pager_clicks'] ? $query_params['pager_clicks'] : 0) : 0;
$build['l_pager_pager_0'] = array('#markup' => "<b>Pager clicks: $pager_clicks</b>");
// Pager.
$build['pager_pager_0'] = array(
'#theme' => 'pager',
'#element' => 0,
'#parameters' => array(
'pager_clicks' => ++$pager_clicks,
),
);
return $build;
The first time the page is called, with page '1' being the current, then the counter will be 0.
You would expect that each time a pager link is clicked, the requested page will be loaded, and the counter 'Pager clicks' incremented by one.
But actually the counter is only incremented on first click, and then stays on 1 for any following click.
Proposed fix - Drupal 7:
I believe the issue lays in the following piece of (Drupal 7) code of the theme_page_link() function in pager.inc
$query = array();
if (count($parameters)) {
$query = drupal_get_query_parameters($parameters, array());
}
if ($query_pager = pager_get_query_parameters()) {
$query = array_merge($query, $query_pager);
}
In fact $query_pager retrieves all the parameters' values (but 'q' and 'page') from current url. PHP's array_merge behaviour is such that "if the input arrays have the same string keys, then the later value for that key will overwrite the previous one". Since $query_pager comes second in the function, the current url values do overwrite whatever passed to the function.
I would suggest to change the order of the variables passed to array_merge like this
- $query = array_merge($query, $query_pager);
+ $query = array_merge($query_pager, $query);
so that parameters input to the function will prevail on the current url's ones.
Related:
#1778990: Merge theme_pager_link*() theme functions into theme_link()
#1786724: theme_pager does not always respect parameters option while generating pager links.
#1898474: pager.inc - Convert theme_ functions to Twig
Beta phase evaluation
| Issue category | Bug |
|---|---|
| Unfrozen changes | Unfrozen because it only changes the pager to fix a bug, and the issue also exists in Drupal 7. |
| Comment | File | Size | Author |
|---|---|---|---|
| #59 | interdiff_58-59.txt | 839 bytes | mondrake |
| #59 | pager_query_parameters_d7-1588138-59.patch | 4.52 KB | mondrake |
| #58 | pager_query_parameters_d7-1588138-58.patch | 4.52 KB | mondrake |
Comments
Comment #1
mondrakeHi, do I understand right this has to be flagged against 8.x-dev, and only eventually backported to 7.x?
Thanks
Comment #2
mondrakeHi,
I propose a patch for the above. I hope I am following the right process :)
Comment #4
mondrake#2: fix_theme_pager_link-1588138-2.patch queued for re-testing.
Comment #5
mondrakeGiven that in D8 theme_pager_link() is being removed on behalf of more general usage of theme_link, patch in #2 does not make sense any longer.
A new patch will be needed after #1778990: Merge theme_pager_link*() theme functions into theme_link() lands.
Comment #5.0
mondraketypo
Comment #5.1
mondrakenew dependency
Comment #5.2
mondrakeadded related issue
Comment #6
mondrakeEdited issue summary to include steps to reproduce. Set to needs review to check if patch is still applicable.
Comment #7
mondrakeand the patch
Comment #8
mondrakeStill blocked by #1778990: Merge theme_pager_link*() theme functions into theme_link(), which is going to remove theme_pager_link() entirely, and move the code for determining the query parameters in a new pager_query_add_page() function.
Comment #8.0
mondrakeadded steps to reproduce
Comment #9
mondrakeChanged title to reflect the edited issue summary.
Comment #10
mondrake#7: fix_theme_pager_link-1588138-2.patch queued for re-testing.
Comment #11
mondrakeHi,
#1778990: Merge theme_pager_link*() theme functions into theme_link() has not moved for almost for a month, so I wonder whether this could go in first.
Comment #12
star-szr@mondrake - The bug report looks great and the fix makes sense. A couple things worth mentioning to move this issue forward.
This bugfix definitely needs tests (and I've set the status to 'needs work' because tests are a core gate). The good news is that it looks like you (or someone else) already has a pretty good guide for writing an automated test via your steps to reproduce code in the issue summary. Contributor doc on writing automated tests: http://drupal.org/node/1468170
Adding automated test coverage will prove that this bug exists, and help prevent regressions in the future.
In short, this is an independent bug that deserves its own issue, and your best bet at seeing this issue resolved is to add that test coverage and keep the patch here up to date.
Tagging for tests and D7 backport.
Comment #13
mondrakeUpdating summary to reflect input in #12.
I am not sure how a test could be written here: I am pretty sure this bug will not appear in the existing core codebase (otherwise it would have popped up before), as there seems to be no invocation of theme('pager', ...) with additional 'parameters' specified, there.
Rather, this is a matter of providing correct functionality to contrib/custom modules that may want to use the 'parameters' variable when invoking theme('pager', ...), see e.g. Pagerer.
So, I am willing to develop a test coverage for this, but I do not know how to setup the test so that a drupalGet call could retrieve the page callback as specified in the issue summary. Any input appreciated.
Comment #13.0
mondrakemade reference to theme_pager() instead of theme_pager_link()
Comment #14
star-szrThe fact that this bug has not popped up before is even more reason to add test coverage :)
If the bug depends on having a page callback and cannot be reproduced by just calling theme('pager', …) with additional 'parameters', then you can create a small test module with page callbacks etc. to test against.
See for example block_test.module:
http://drupalcode.org/project/drupal.git/tree/refs/heads/8.x:/core/modul...
If you'd like more help, feel free to stop by Drupal core contribution mentoring:
http://drupal.org/core-office-hours
Comment #15
star-szrA better example is aggregator_test.module:
http://drupalcode.org/project/drupal.git/tree/refs/heads/8.x:/core/modul...
Comment #16
mondrakeThanks :)
I was coming to the same conclusion after some browsing... I will write a pager_test module and see how this moves forward.
Cheers
Comment #17
mondrakeSo.
The test_only patch should prove the bug described in the summary.
The full patch should fix the bug and test should be OK.
(Theoretically :))
Let's see what bot thinks first of all.
Comment #18
mondrakeOh yes, and the status change.
Comment #19
star-szrThe test looks pretty reasonable, good work! A few minor nitpicks ahead:
The format for these changed, should be:
Contains \Drupal\system…
I don't think this
useis needed for your tests, should be removed.Few bits of trailing whitespace, please remove per http://drupal.org/coding-standards#indenting.
The only other thing I would recommend at this time would be to add a comment above this line you're changing to explain the reasoning behind the order of arguments passed to array_merge().
Comment #20
mondrakeThanks for review @Cottser!
New patch, with all input in #19 addressed.
Comment #21
star-szrFor the "Contains \Drupal\system…" the initial slash wasn't a typo, please see http://drupal.org/node/1354#file.
Interdiffs are great, too :)
Comment #22
mondrakeThanks for you patience, @Cottser!
Here we go.
Comment #23
mondrake#22: theme_pager_query_parameters-1588138-22.patch queued for re-testing.
Comment #24
mondrakeRe-roll to align to #1606794: Implement new routing system and to #1292284: Require 'type' key in .info.yml files. Remove 'Needs tests' tag.
Comment #25
jwilson3Do we really nee 5 lines of comments for this explanation? I think it would be much improved by clearer field names, and a brief plain english comment.
Something like this:
thoughts?
Comment #26
jwilson3Comment #27
mondrakeWhy not, however the precedence is taken by the input values, not the current request's ones (that's the actual reason of this entire issue :))
Comment #28
mondrake.. and status change
Comment #29
jwilson3Oops, thanks,... see, it *was* confusing!
Comment #30
mondrake#27: theme_pager_query_parameters-1588138-27.patch queued for re-testing.
Comment #32
mondrakeRe-roll after #1898474: pager.inc - Convert theme_ functions to Twig got committed.
Comment #33
mondrake#32: theme_pager_query_parameters-1588138-32.patch queued for re-testing.
Comment #33.0
mondrakeedit based on feedback in #12
Comment #34
mondrake32: theme_pager_query_parameters-1588138-32.patch queued for re-testing.
Comment #36
mondrakeRerolled / refreshed.
Comment #38
mondrake36: pager_query_parameters-1588138-36.patch queued for re-testing.
Comment #39
mondrakeTest was cancelled
Comment #41
mondrake#40 refers to the failure of test in #36
#39 is green and up for review :)
Comment #42
mondrakeReroll after #340723: Make modules and installation profiles only require .info.yml files.
Comment #44
mondrake42: pager_query_parameters-1588138-42.patch queued for re-testing.
Comment #45
mondrakeComment #46
mondrakeReroll for #2247991: [May 27] Move all module code from …/lib/Drupal/… to …/src/… for PSR-4
Comment #47
jwilson3Nothing jumps out at me as wrong with the latest patch.
But because this is such an obscure and confusing problem, do you think you could provide a patch file that contains *just* the test (eg suffix the filename with -test-only.patch) to see what Drupal errors on currently?
Hat tip: https://twitter.com/xjmdrupal/status/195113152759865344
Comment #48
jwilson3Oops, I take it back.
The comma placement here makes this difficult to read and the terminology "in variables" is abstract enough to be confusing. Which variables are we talking about?
Could we change this comment again to something like:
This small change will give you and opportunity for a new patch, and a test-only patch on the same comment.
Comment #49
jhedstromNeeds work based on #48.
Comment #50
mondrakeRerolled and addressed comments in #47 and #48. Sorry no interdiff.
Comment #52
star-szrBased on the latest patch this title seems more accurate to me. Perhaps the issue summary should be updated a bit. Happy to see this is still moving :)
Comment #53
mondrakeI'll try to update the IS. Readded backport to 7 tag which got lost.
Comment #54
mondrakeComment #55
jhedstromI've added a beta phase evaluation to the issue summary. The patch in #50 looks good to me. Marking RTBC.
Comment #57
alexpottCommitted b7a6866 and pushed to 8.0.x. Thanks!
Thanks for adding the beta evaluation to the issue summary.
Comment #58
mondrakeD7 ported patch.
Comment #59
mondrakeWhoops
Comment #63
jonmcl commentedI believe if this fix is implemented, there is going to be a problem with the Date module's implementation of Views exposed select filters. I'm not sure if it is correct or incorrect, but that module generated a form element name that is like
name="field_example_date[value][year]"and this issue's fix will cause a fatal error:I created an issue on the Date module: #2821200: Unusual form element name attribute for exposed Views select filter?
So it appears that the array_merge bug, outlined in this issue, was allowing the Date module's three-dimensional form element name to work. Fixing this issue will cause the link generated to trigger a fatal error because of the way the Date module (incorrectly or correctly) constructs the form element's name.
Comment #66
tommyblopes commentedHi,
I am currently facing this issue on Drupal 7.54, and patch #59 works like a charm.
I can see it was merged into 8.x, but why hasn't it been merged into 7.x ? We need this bug resolved in the core.
Thanks