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. :(

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

dww created an issue. See original summary.

dww’s picture

Status: Active » Needs review
FileSize
758 bytes

Curious 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. ;)

Lendude’s picture

We 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.

The last submitted patch, 3: 2959316-3-TEST_ONLY.patch, failed testing. View results

dww’s picture

FileSize
3.61 KB
1.15 KB

Sweet, 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.

Lendude’s picture

Status: Needs review » Reviewed & tested by the community

Relevant comment cleanup looks good. Looks ready to me.

dawehner’s picture

@dww Thank you for this bugfix! This explanation makes 100% sense.

dawehner’s picture

+++ b/core/modules/views/src/ViewExecutable.php
@@ -1110,9 +1111,11 @@ protected function _buildArguments() {
+        $substitutions["{{ raw_arguments.$id }}"] = strip_tags(Html::decodeEntities($argument->argument));

Could we use $argument->getValue() here instead?

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

#8 makes sense.

dww’s picture

Assigned: Unassigned » dww

Sure, makes sense. I'll re-roll and give it a try. Stay tuned.

dww’s picture

Assigned: dww » Unassigned
Status: Needs work » Needs review
FileSize
3.62 KB
818 bytes

Yup, works fine with local testing. This should be RTBC as soon as the bot comes back clean.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Thank you!

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

@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!

  • alexpott committed 26a5a2a on 8.6.x
    Issue #2959316 by dww, Lendude, dawehner: Views argument validators that...

  • alexpott committed 5ae77a9 on 8.5.x
    Issue #2959316 by dww, Lendude, dawehner: Views argument validators that...
dww’s picture

Yay, thanks!

Cheers,
-Derek

xjm’s picture

I haven't confirmed it, but I've a suspicion that this broke Postgres: https://www.drupal.org/pift-ci-job/935929

dww’s picture

Ugh. I was kinda wondering about that uid argument test using string values. Maybe this works?

dww’s picture

While 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?

Status: Needs review » Needs work

The last submitted patch, 20: 2959316-20.fix-postgres.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

dww’s picture

Status: Needs work » Needs review

Not 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

Lendude’s picture

Lets 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!

  • alexpott committed 3c08a5b on 8.6.x
    Revert "Issue #2959316 by dww, Lendude, dawehner: Views argument...

  • alexpott committed c24bdd2 on 8.5.x
    Revert "Issue #2959316 by dww, Lendude, dawehner: Views argument...
alexpott’s picture

Status: Needs review » Needs work

I reverted the issue we'll need a merged patch to go forward. I agree with @Lendude just doing the minimal is okay.

+++ b/core/modules/views/tests/modules/views_test_data/src/Plugin/views/argument_validator/ArgumentValidatorTest.php
@@ -38,7 +38,7 @@ protected function defineOptions() {
-      $this->argument->argument = 'this value is replaced!';
+      $this->argument->argument = '1';

We should add a comment here about why '1' is a good value.

Lendude’s picture

Merged patch with a comment, interdiff is vs #11

xjm’s picture

In 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?

xjm’s picture

P.S., #20 did make me giggle. :)

alexpott’s picture

This 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.

dww’s picture

Sorry 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.

dww’s picture

Here's #27 again, as-is, to prevent the bot from changing this to needs work.

The last submitted patch, 31: 2959316-31.TEST-ONLY.patch, failed testing. View results

dww’s picture

Status: Needs review » Reviewed & tested by the community

Okay, #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:

1) Drupal\Tests\views\Kernel\ViewExecutableTest::testArgumentValidatorValueOverride
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
 Array (
     '{{ arguments.uid }}' => '1'
-    '{{ raw_arguments.uid }}' => '1'
+    '{{ raw_arguments.uid }}' => 'this value should be replaced'
 )

#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.

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed 25d9690811 to 8.6.x and 9b8e728160 to 8.5.x. Thanks!

Second time lucky!

  • alexpott committed 25d9690 on 8.6.x
    Issue #2959316 by dww, Lendude, alexpott, dawehner, xjm: Views argument...

  • alexpott committed 9b8e728 on 8.5.x
    Issue #2959316 by dww, Lendude, alexpott, dawehner, xjm: Views argument...
dww’s picture

Sweet, 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...

Status: Fixed » Closed (fixed)

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