Problem/Motivation
With a View, if you limit the options of an exposed Language filter, two things happen:
- Several errors will be generated:
- Notice: Undefined property: Drupal\Core\StringTranslation\TranslatableMarkup::$option in Drupal\views\Plugin\views\filter\InOperator->reduceValueOptions() (line 277 of core/modules/views/src/Plugin/views/filter/InOperator.php)
- Warning: array_keys() expects parameter 1 to be array, null given in Drupal\views\Plugin\views\filter\InOperator->reduceValueOptions() (line 277 of core/modules/views/src/Plugin/views/filter/InOperator.php)
- Warning: array_shift() expects parameter 1 to be array, null given in Drupal\views\Plugin\views\filter\InOperator->reduceValueOptions() (line 278 of core/modules/views/src/Plugin/views/filter/InOperator.php)
- Special languages (site language default, site language interface, and site language content) aren't listed, even if they're selected as allowed
The cause is due to InOperator->reduceValueOptions() assuming objects it is given have an "option" property. In the case of the Language selector, some of the options arrive as TranslatableMarkup objects (site language default, site language interface, and site language content), which do not have an option property.
The comments in that method don't actually describe what kind of objects are expected to be given to that method:
// Because options may be an array of strings, or an array of mixed arrays
// and strings (optgroups) or an array of objects, we have to
// step through and handle each one individually.But since the code is verbatim from Drupal 7 Views, it doesn't have any "awareness" of the TranslatableMarkup class, which is functionally a string but of course an regular PHP object.
Proposed resolution
Over in the LanguageFilter class we can update the getValueOptions method to cast the language values to string. When they arrive to the InOperator class there won't be any TranslatableMarkup objects and the logic will work as expected.
Comments
Comment #2
CalebD commentedAttached is a patch that updates
LanguageFilter::getValueOptions()to cast the returned languages to string.Comment #3
CalebD commentedComment #4
ragnarkurm commentedThe patch looks good to me
and works as expected.
Comment #5
lendudeNice find!
I like what this does but this line is pretty unreadable, maybe wrap it at some point?
Also, this needs tests.
As a bug this can go against 8.1.x
Comment #6
MerryHamster commentedWorked for me
Comment #8
tsymi commentedWorked for me too, thanks.
Comment #9
d.olaresko commentedThis patch works for 8.2.3 too.
Comment #10
flocondetoile#2 fix the notices on 8.2.3
Comment #12
mkalkbrennerPatch #2 still applies for 8.3.x and solves the issue for Search API based views, especially Search API Solr Multilingual.
I increase the priority because this issue heavily spams the watchdog on every single search.
Comment #13
tstoecklerI think the better choice would be to adapt
reduceValueOptionsto account forTranslatableMarkupobjects.Maybe something like changing
to
or something like that? That should do the trick.
Comment #14
duneblpatch #2 solve the notice problem but apply with an offset on 8.4
Comment #15
ajlib commentedThanks CalebD for working on this. I'm unassigning this to open it up for others to work on it.
I'm at the TCDrupal sprint and working on following the meta instructions for major issue triage (https://www.drupal.org/node/2474049).
Comment #16
ajlib commentedI was able to reproduce this on simplytest.me with 8.4.0-dev version - see attached image for errors screenshot (errors-8.4.0-dev.png). Then I applied the patch from CalebD which did not produce any errors.
The steps I used to reproduce with and without the patch:
Comment #17
ajlib commentedI was searching for duplicates and found a plan around fixing multilingual views issues which this issue seems to fall under so I am linking it.
Comment #18
ajlib commentedWhile looking over the issue to see if the summary is up-to-date, as called for in the major issue triage documentation, I feel like it is. But, as it's likely related to a greater issue with multilingual views, which was linked in comment #17, there could be other issues and it would be good for someone else to review it.
Comment #19
ajlib commentedI finished going through all the steps on the meta for major issue triage.
Comment #20
steveoriol#2 fix the notices on 8.3.4
Comment #21
flyke commentedI had this error on Drupal 8.3.5:
Notice: Undefined property: Drupal\Core\StringTranslation\TranslatableMarkup::$option in Drupal\views\Plugin\views\filter\InOperator->reduceValueOptions() (line 272 of core\modules\views\src\Plugin\views\filter\InOperator.php).I applied patch #2 (via composer) and it fixed the problem.
Comment #23
sanduhrsReroll against 8.5.x, applies well to 8.4.x, too.
Taking #5 and #13 into account.
Comment #24
marcoscanoManually tested #23 and it works fine for removing the warning when the language is used in an exposed filter.
Comment #25
devad commentedPatch #23 works for me as well. No more log errors.
And it applies cleanly to current 8.4.x-dev and 8.5.x-dev.
marking RTBC
Comment #26
xjmThanks for working on this and for confirming that it resolves the issue.
We do still need to add an automated test that fails without the fix and passes when combined with it. Thanks!
Comment #27
mqannehPatch #23 fixed the issue for me on 8.x-4.x-dev
Comment #28
duneblsmall notice when applying #23
Comment #30
ludo.rI applied patch #23 on Drupal 8.3.7.
Patch is applied successfully and errors disappear!
Comment #31
mikelutzI don't have enough internal knowledge of views to write a full on Functional test that attempts to trigger the error naturally, however if the agreement is that LanguageFilter::getValueOptions should not return an instance of MarkupInterface as an element of its array, I'm happy to write that test.
Comment #32
mikelutzWith a failed and passing test, I'm moving this back to needs review.
Comment #33
vlad.dancerLooks good to me.
+1 RTBC
2 years for acepting a patch for fixing a notice! ;)
Comment #34
andypostRTBC++ tests added #26
Comment #35
devad commentedAn attempt to apply patch #31 to d8.5.0 at simplytest.me fails with http 500 error.
Do we need this patch re-roll for d8.5.0 ?
Comment #36
mikelutzI don't think so. I rebased locally against a new 8.5.x pull and it applied fine, but I'll requeue the tests here and will post a new patch if they fail.
Comment #37
mikelutzThe tests pass against 8.5-dev and 8.6-dev. This should be fine to commit to 8.6 and cherry-pick for 8.5.1
Comment #38
catchIs this change still necessary when it's being changed in LanguageFilter? Also it doesn't look like the test coverage handles this code.
Very minor - missing space after foreach().
Comment #39
devad commentedTested patch #31 again at simplytest.me and it applies cleanly now.
It could be that simplytest.me platform had some issues these days...
Comment #40
mikelutzStrictly speaking it isn't necessary to check twice. Either reduceValueOptions should gracefully handle markup, or we should require filters to return strings.
Comment #41
lendudeSince requiring filters to return strings would be an API change, that would be harder to do. Currently the return value is just
array.Also it can't require just strings, it also has support for objects, as long as they have certain properties set....
Handling this in reduceValueOptions sounds like the better route then. Probably just an
elseif ($option instanceof MarkupInterface) {$option = (string) $option; }or something along those lines?
Comment #42
simgui8 commented#31 fixes array_shift warning when using language filter with limited options.
--Drupal 8.5.3
thanks everyone
Comment #43
maxplus commentedThanks! #31 fixes this error for me on 8.5.4 when limiting language options:
Comment #45
handkerchiefPatch from #31 works for me too as mentioned in #42 and #43.
-- Drupal Core 8.6.x-dev
Comment #46
mikelutz#41 and the reporter are correct, in_operator reduceValueOptions should handle translatable markup. The author of #31 clearly had no idea what he was doing. In fact, if you follow back through FilterPluginBase::buildExposedForm() The filter system will handle TranslatableMarkup in options just fine, all InOperator needs to do is recognize the difference between a markup object and an options object, and pass the markup through like it would a string.
Here's a new test showing that in_operator can handle translatable markup in options, and a much cleaner fix. No interdiff because it's a from scratch new approach.
Comment #48
mikelutzComment #49
andypostWould be great to get this in
Comment #50
ludo.r#46 mikelutz:
#31 mikelutz
LOL :D
Comment #51
alexpottCredited @Lendude, @tstoeckler, @catch for review comments
Comment #52
alexpottCommitted and pushed 0b6c398e7b to 8.7.x and 6cd36113bf to 8.6.x. Thanks!