This is sort of related to the monster issue @ #2640994: Label token replacement for views entity reference arguments not working, only insofar as it involves token replacement and taxonomy arguments. ;) But, I'm sure this is a separate bug since the code that I believe is broken isn't touched by that issue.
It's also related to #2645442: Can't use a taxonomy term name as the value for a contextual filter in a view because that's where I'm proposing we need to restore D7 View's argument validator that transforms a term name back into a term ID. But that's not this bug, either. ;)
The problem is that although the PHPDocs for Drupal\views\Plugin\views\argument_validator\ArgumentValidatorPluginBase claim the following:
* Views argument validator plugins validate arguments (contextual filters) on
* views. They can ensure arguments are valid, and even do transformations on
* the arguments. They can also provide replacement patterns for the view title.
* For example, the 'content' validator verifies verifies that the argument
* value corresponds to a node, loads that node, and provides the node title
* as a replacement pattern for the view title.
(emphasis mine).
How you actually do that isn't documented anywhere, but I wrote a module to do it: views_taxonomy_term_name_into_id. It's a very small module, that does the following:
TermNameAsId::validateArgument($argument) {
...
$this->argument->argument = $term->id();
...
}
That's what you need to have an argument_validator plugin change the raw value of the argument so that queries work.
SO, here's the bug this issue is about. ;)
Inside \Drupal\views\ViewExecutable.php, we do this:
protected function _buildArguments() {
...
$arg = isset($this->args[$position]) ? $this->args[$position] : NULL;
...
// Set the argument, which will also validate that the argument can be set.
if (!$argument->setArgument($arg)) {
$status = $argument->validateFail($arg);
break;
}
...
// Add this argument's substitution
$substitutions["{{ arguments.$id }}"] = $arg_title;
$substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($arg));
}
Boom! My nice argument transformation is lost for the purposes of the raw_argument token :( It needs to do this:
$substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($argument->argument));
Otherwise, the promise that argument_validator plugins can alter the argument is broken. :(
Comment | File | Size | Author |
---|---|---|---|
#31 | 2959316-31.TEST-ONLY.patch | 2.21 KB | dww |
#27 | 2959316-27.patch | 3.67 KB | Lendude |
#27 | interdiff-2959316-11-27.txt | 1.51 KB | Lendude |
#20 | 2959316-20.fix-postgres.patch | 2.2 KB | dww |
#19 | 2959316-19.fix-postgres.patch | 1.88 KB | dww |
Comments
Comment #2
dwwCurious what the test bot thinks of this. ;)
Someone will undoubtably want a test that shows the bug. I couldn't find a single argument validator in core that alters the argument value. :( So, I guess we'd need to write one. Or better yet, let's move https://www.drupal.org/project/views_taxonomy_term_name_into_id into core. ;)
Comment #3
LendudeWe can just abuse a test validator for the purpose of testing this. Here is a test. TEST_ONLY patch is also the interdiff.
Fix makes sense to me.
Comment #5
dwwSweet, thanks for the test! Looks good to me.
Since this is looking viable to commit soon, I figured it'd be wise to clean up the related code comments a bit, too.
Also, happy to report this applies cleanly to the end of 8.6.x branch, too.
Comment #6
LendudeRelevant comment cleanup looks good. Looks ready to me.
Comment #7
dawehner@dww Thank you for this bugfix! This explanation makes 100% sense.
Comment #8
dawehnerCould we use $argument->getValue() here instead?
Comment #9
alexpott#8 makes sense.
Comment #10
dwwSure, makes sense. I'll re-roll and give it a try. Stay tuned.
Comment #11
dwwYup, works fine with local testing. This should be RTBC as soon as the bot comes back clean.
Comment #12
dawehnerThank you!
Comment #13
dwwThanks!
Side note: If we don't like touching
$argument->argument
directly, it probably shouldn't bepublic
:#2959929: Consider making \Drupal\views\Plugin\views\argument\ArgumentPluginBase::$argument protected
Another quasi-related follow-up for folks who understand this code:
#2959933: Document \Drupal\views\Plugin\views\argument\ArgumentPluginBase::$value and clarify how/why it's different than ArgumentPluginBase::$argument
Cheers,
-Derek
Comment #14
alexpott@dww thanks for all the followups! Unfortunately things like making the argument protected will have to wait to Drupal 9 I think. But definitely worth an issue.
Committed and pushed 26a5a2ab8a to 8.6.x and 5ae77a99e8 to 8.5.x. Thanks!
Comment #17
dwwYay, thanks!
Cheers,
-Derek
Comment #18
xjmI haven't confirmed it, but I've a suspicion that this broke Postgres: https://www.drupal.org/pift-ci-job/935929
Comment #19
dwwUgh. I was kinda wondering about that uid argument test using string values. Maybe this works?
Comment #20
dwwWhile we're at it, maybe that test should ensure the non-transform case isn't broken? Or perhaps we already have tests for this elsewhere?
Comment #22
dwwNot sure why #20 failed (I'm probably doing something wrong by trying to reuse the same test case and not sufficiently restarting things), but #19 is the right fix. Probably RTBC, but I'll let someone else decide that.
Thanks/sorry,
-Derek
Comment #23
LendudeLets not try to increase the scope now and just do the minimal amount of changes needed to get this to pass on postgres. I would not do more then this.
This passes locally on postgres. Thanks @xjm for catching this!
Comment #26
alexpottI reverted the issue we'll need a merged patch to go forward. I agree with @Lendude just doing the minimal is okay.
We should add a comment here about why '1' is a good value.
Comment #27
LendudeMerged patch with a comment, interdiff is vs #11
Comment #28
xjmIn general I recommend running any Views API patches against all three databases before commit. :)
Looking at the patch, hmmm, is this a problem of altering/reusing a test fixture when we should be using a different one? With alters IMO it's usually good to create a new test fixture so we're not altering things used elsewhere or in other ways.
I'm also not sure replacing a string with a numeric value so that it works on Postgres makes sense; shouldn't we be replacing a numeric value then? Edit: And, separately a test case that works on strings?
We should have test coverage that proves this works on Postgres, and having a string value altered into a numeric value to do that seems brittle to me, like, the original value also shouldn't be a string in a numeric field because then the unmodified argument would break postgres and it's just not because of the particular behavior of the test. No?
Comment #29
xjmP.S., #20 did make me giggle. :)
Comment #30
alexpottThis is the first test that has actually executed the test_argument_dependency view.
But also the test added here is explicitly adding the argument as a string and then using the validator to replace the text with a number. This looks like a valid use-case of argument altering to me. I.e to convert a name to an ID.
We do have test coverage this works on Postgres - as the test proves.
Comment #31
dwwSorry for the trouble this issue has caused. :/
@xjm: Duly noted about requesting Postgres tests for views issues. Re: converting a string into a number in the test... that's exactly what views_taxonomy_term_name_into_id is trying to do, so I'm happy to have a test in core that ensures it works. Frankly, that module should be in core, then we could have test coverage of exactly that case.
Generally, it seems the "argument validators that transform values" case is sorely undocumented and untested in core right now. This is a small step in the right direction.
Feel free to commit #27. I think it's RTBC.
Meanwhile, at the risk of testbot and issue churn, here's a new test-only patch so it's obvious that this fails on both platforms (albeit they'll potentially fail for different reasons).
I'll re-upload #27 afterwards so the bot doesn't change the status here.
Comment #32
dwwHere's #27 again, as-is, to prevent the bot from changing this to needs work.
Comment #34
dwwOkay, #31 failed as expected:
MySQL: https://www.drupal.org/pift-ci-job/936704
Postgres: https://www.drupal.org/pift-ci-job/936705
In both cases:
#27 (and #32) show all tests passing on both MySQL and Postgres.
This confirms that:
a) The test ensures the functionality of this issue works. It's not failing b/c Postgres is brittle, it's failing because core doesn't honor argument validator plugin value transformations.
b) We did not break Postgres this time. ;)
Even though technically it's "my" patch, I really just split and re-uploaded parts/whole of Lendude's #27. So I'll be bold and re-RTBC.
Comment #35
alexpottCommitted and pushed 25d9690811 to 8.6.x and 9b8e728160 to 8.5.x. Thanks!
Second time lucky!
Comment #38
dwwSweet, thanks once more! And sorry again for the trouble and extra work.
Cheers,
-Derek
p.s. @xjm: Glad you liked #20. ;) I'm slightly sad some variant of that test didn't make it into core. Oh well...