Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
See #2927746-62: Update Symfony components to 3.4.*
Proposed resolution
Fix our usages in validation layer
Remove deprecation from whitelist in the deprecation bridge listener.
Comments
Comment #2
larowlanComment #4
Mile23Naively setting
$strict = TRUE
on ourChoice
subclass.Comment #5
Mile23Comment #7
larowlanComment #8
alexpottSo let's see if typed data offers us a way out...
Comment #9
alexpottThat's not going to work :( Because
\Drupal\Core\Field\Plugin\Field\FieldType\BooleanItem::getSettableValues
does not return boolean values but getCastedValue()on it's main property would.
Comment #10
alexpottWe need the early return before the type safety.
One thought is do we need to bring
out of the parent implementation so we can do the same type juggling for callbacks. I think we probably do.
Comment #12
alexpottAddressing #10
Comment #14
catchBumping to critical since it's a hard Drupal 9 blocker.
Comment #15
alexpottIt would be good to have test coverage of this move and it's ability to affect types. This change is not required by core but very much might be needed by contrib / custom.
This code is not the prettiest but actually solving the "TypedData not being properly typed" issue is of way bigger scope.
Comment #16
alexpottHere's a test the proves the callback takes precedence to the allowed values and our type coercing works.
Comment #17
catchOK this is really tricky but the comment explains what's going on well enough.
My only question is why not copy over the Symfony 3 non-strict logic that's been deprecated - would that be more/worse code to maintain than what we're adding here?
Comment #18
larowlando we need a comment here
Other than that, this makes sense to me
Comment #19
alexpott@catch I think it is worth doing this because in_array() without strict checking is really hard to predict how it works - there are just so many gotchas. Also this is moving in the direction we should be going with TypedData being typed and using PHP 7's primitive types. So it's a stepping stone. It also keeps us in-line with Symfony so when we doing get round to strciter typing in TypedData we've not got so far to move.
@larowlan we never really agreed a loosening of coding standards for tests - so fixed. One day we'll open a policy issue about that :)
Comment #20
dawehnerWhile reviewing the code I was wondering whether we could reuse the existing parent's code by setting the callback, but yeah it is not. I added a comment about this.
On top of that I adopted the tests to not add additional deprecated assertion calls.
Comment #21
catchI don't think there's anything else left to do here.
Comment #22
mikelutzI've been reviewing this along with other issues in the constraints system for symfony 4. I've been testing it in conjunction with some other patches around the constraint system, and it is working well. The approach makes since given the, ahem, 'constraints' we are facing.
+1 on RTBC
Comment #24
larowlanCommitted 030a9ce and pushed to 8.7.x. Thanks!
Comment #26
Chi CreditAttribution: Chi commentedTechnically it is a BC break. Existing code may rely on non-strict validation.
https://www.drupal.org/pift-ci-job/1200662
If we desperately need this we should at least provide a change record to explain how custom code is supposed to be updated.
Comment #27
Chi CreditAttribution: Chi commentedBesides Double Field this also affects core List (float) field.
#3033120: [Regression] Options select widget does not work when allowed values are a mix of strings and integers
Comment #28
mikelutzFloats can't be array keys, so list_float typecasts keys to a mix of integers or strings. If a float options allowed value list is [0.0, 1.5, 2.0], then the allowed values list is [(int)0, "1.5", (int)2] if we check a value of "1.5" it is being typecast to gettype(0) = (int)1.5 = 1 before being validated and fails.
Comment #29
Gábor HojtsyI rolled this back based on discussion today with @mikelutz. For one the solution to the problem is not trivial. Second, it looks like a redo of the patch and not really a followup. Better to not have -dev include known regressions that we cannot fix quickly. @mikelutz will bring the fix back here from #3033120: [Regression] Options select widget does not work when allowed values are a mix of strings and integers.
Comment #30
mikelutzMerging in some work in the other issue against the new 8.7.x with the revert. Testbot fodder...
Comment #31
mikelutzbugfix in my approach..
Comment #32
mikelutzOkay, so this should work with some cleanup. Basically default AllowedValueConstraint::strict to FALSE, set it to true for the core use cases and handle the typing for Booleans and Integer lists. If we get through there, and strict still hasn't been set to true, then check if the validator passes for non-strict but not strict, and if it does, throw a deprecation error, typecast so it works with strict and send it on its way.
This way we preserve non-strict behavior behind a deprecation error, and take care of the core use cases.
I'll try to clean up the patch and the direct testing tomorrow.
Comment #33
alexpottHere's another approach - kinda going back to #8 but doing an additional couple of twists. Doing the callback ourselves so we can later set the type of the allowed values using the typed data we've been provided. This patch includes the new tests added by @mikelutz to prove what we broke in #20 that was committed and then reverted.
Comment #34
alexpott@mikelutz pointed out I was miss a use - now I've confirmed in debug that when dealing with ListFloatItem we are casting all the values to floats properly.
Comment #35
alexpottFor those wondering why #33 is green - it's because all the things were cast to string because the instanceof PrimitiveInterface always returned false.
Comment #37
alexpottSo the patch in #34 broke
because NULL was being cast to an empty string. So to fix we need to do the casting after this check. Which funnily enough makes the patch a little bit nicer in my opinion.
Comment #38
alexpottSo one thought I have is are we not always dealing with a PrimitiveInterface type at this point and what would it mean if we're not.
Uploading a patch to find out what's happening in HEAD.
Comment #39
mikelutzI suppose we should evaluate gettype($value) outside of the loop.
Comment #40
alexpottGood idea @mikelutz. I tried to make this bit of code more elegant with array_map / array_walk but nothing looked nicer and as easier to grok as the foreach to me.
Comment #42
mikelutzI had ran a speed test earlier, and foreach ran the fastest anyway. array_map was fine when I was only doing it for ListFloatItem and was casting to float, but I think the foreach is cleaner than trying to deal with getting the type in the closure.
Comment #43
Gábor HojtsyLooks good me to me as well. Thanks for working out a better solution.
Comment #44
larowlanBecause we're doing type-casting here, I'd like to see a test where we have string allowed values and test with 0 as the value.
Added that.
Comment #47
Gábor HojtsySuperb, thanks for the additional test coverage :)
Comment #48
larowlanAdding credit for Chi who caught the regression
Comment #49
larowlanCommitted c9dd655 and pushed to 8.7.x. Thanks!
My patch only added an extra test, so I think I'm still eligible to commit this.
Comment #50
larowlanCherry-picked this to 8.8 as the branch is now open and updated my commit tooling to commit to 8.8.x first from here out.