Problem/Motivation
When source field doesn't have a value static_map plugin produces PHP notice "array_key_exists(): The first argument should be either a string or an integer NestedArray.php:72".
Proposed resolution
The original proposal was to add a try/catch around NestedArray::getValue(). However, in #24, mikelutz explains that that is not helpful in this case because it is a php warning that is thrown. Catching that would hide the problem.
Add a test for NULL source, with and without a NULL in the map.
Documentation for how Null source value is handled was done in #2941323: StaticMap should document how/whether it handles source values of NULL, TRUE, FALSE.
Remaining tasks
Patch
Review
Commit
User interface changes
API changes
Data model changes
Release notes snippet
Comments
Comment #2
rosk0Test only patch.
Comment #4
aleevasComment #5
rosk0Hm, this test is actually wrong.
Comment #6
aleevasHere is my patch.
Was updated test and added fix for pass all tests.
Comment #8
aleevasComment #9
aleevasMy next try
Comment #10
aleevasI hope that tests now will be passed.
But I'm not sure in 100% that it the best way. So need review and other opinion.
Comment #11
aleevasSorry, I had attached the patch without test in my previous comment.
Comment #12
xurizaemonAssigning to myself to review this coming weekend.
Comment #13
mikelutzLets not just plow forward with an empty string here. Let's throw the same exception on NULL that we do on an empty array. Can we just replace
with
And update the tests to check for the exception being thrown on NULL?
Comment #14
aleevas@mikelutz, thanks for your review!
You are right, that's way is much better.
In this patch implemented this approach.
Please review
Comment #16
xurizaemonIn the docs we have this relating to the case where a float(-ish thing) is passed in as $value. Should we also throw an exception then?
1.1 (or 500.00) can be a valid array key if it's a string, but will trigger array_key_exists() warning if it's received as a float, and 500.00 will look like '500' at this point, making you drupalwtf at why array_key_exists() is complaining that an apparent int is not an int (it's a double!)
Even if we don't include that behaviour in this change, we could possibly document not using null / empty string inputs also.
Comment #18
quietone commentedComment #20
quietone commentedIt took a bit to see that the work here is attempting to fix what is thought to be a problem with the processing of NULL in the static map process plugin. That is not the error reported in the IS but the title of this issue suggests it is. xurizaemon, #16, was on the right track. There are potentially two problems
For now, let's defer the issue about the processing of the NULL, whatever static map is doing it is working and folks are expected the behavior to remain the same. Proof of that is patch #14 which alters the processing of NULL and then we have test failures.
That leaves the error from array_key_exists. For that, we need a fail patch, one that generates the error reported in the IS, which is not is not generated with NULL as the source value. And then, I think a try/catch around NestedArray.
Comment #21
quietone commentedAdd tag.
Comment #22
quietone commentedNow back to the processing of NULL. When the source value is NULL it is changed to [NULL] before being passed to NestedArray::getValue() and will not cause an error or a warning. On return the array_key will not exist and then if the default_value is set that is returned. If there is no default value and bypass is empty then a MigrateSkipRowException is thrown, other wise NULL is returned.
Does anyone think that logic needs to change?
Comment #24
mikelutzSo first, let me say I was wrong about NULL, I did some testing, and NULL seems to be converted into an empty string, which is a valid array key and is not throwing the warning. Passing a float, array or object to array_key_exists does trigger the warning, and there are various inputs that can cause that to happen, all of them wrong.
I don't like the float test here. The reason that it works if the value is found, but not if it isn't is because the array key is converted to an integer on assignment and lookup. $configuration['map'][1.2] = 'float'; actually sets $configuration['map'][1] = 'float', and nested array checks for $configuration['map'][1.2] and php returns $configuration['map'][1], which exists, so array_key_exists is never called. in the second case, [1] doesn't exist so array_key_exists is called throwing the warning. This is a whole mess of potentially buggy things that can happen, and php is not going to help us find them. I think we should explicitly throw an exception if we get a float value.
Finally, the try/catch is actually not helpful here. The MigrateException only gets thrown in the test because the errorhandler in phpunit converts the warning to an \Exception. in the real world, It's a php warning that is thrown, not an \Exception, so the warning wouldn't be caught anyway.
You could, of course catch a \Throwable instead of an \Exception, but it's a bad smell to me to try to catch errors/warnings after they are thrown. It's much better to detect the situations that can trigger them in advance and throw an \Exception before it ever gets to the point of throwing php error or warning.
Comment #26
quietone commentedSo, what is to be done here? It looks like we go back and add a test for NULL as a source and add documentation. There is already an issue for the documentation, maybe we can combine the two?
I started from the patch in #11, added a new test for a valid NULL source and added the documentation from the related issue. There is no interdiff because this is starting over.
Comment #27
quietone commentedWell, that was a complete mess. Ignore #26
Based on the comment in #24, this patch starts from the patch in #11, added a new test for a valid NULL source. No interdiff because this is starting over.
Comment #28
quietone commentedComment #29
lendudeSince this no longer changes any existing behaviour and only adds extra test coverage, I'm gonna change this to a task.
This looks good and the tested behaviour matches the the doc block example added in #2941323: StaticMap should document how/whether it handles source values of NULL, TRUE, FALSE
Comment #32
catchCommitted/pushed to 9.2.x and cherry-picked to 9.1.x, thanks!