Problem/Motivation
Ran into this while working on #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support.
#3341682: New config schema data type: `required_label` introduced type: required_label, and it looks like this:
required_label:
type: label
label: 'Label'
constraints:
NotBlank: {}
NotBlank has a $allowNull option that defaults to FALSE. In other words: it disallows both NULL and the empty string ''.
Unfortunately, this means that any config property that is explicitly marked required by setting the NotNull constraint, this triggers a double error:
Steps to reproduce
See tests.
Proposed resolution
- Write tests.
Adjust type: required_label to work fine both when NotNull is present and when it is absent. — per @alexpott and @longwave in #16 and #19: automatically detect when both NotNull and NotBlank are present and if so, set NotBlank's allowNull: true option.
Remaining tasks
None.
User interface changes
None.
API changes
None.
Data model changes
None.
Release notes snippet
N/A
Comments
Comment #3
wim leersComment #4
wim leersComment #6
wim leersComment #7
borisson_Looks great, we have sufficient coverage and this is a small bugfix.
Comment #8
alexpottThere are some comments to resolve.
Comment #9
wim leersAddressed!
I'm wondering if at this point a separate test method with
@dataProvideror@testWithwouldn't be clearer though 😅Comment #10
alexpottOne of the kernel tests is failing do to this change... see https://git.drupalcode.org/issue/drupal-3404061/-/pipelines/56281/test_r...
Comment #11
wim leersForgot to update that one. Green again 👍
Comment #13
smustgrave commentedReran the failing javascript test and it passed so it was random.
Ran the test-only feature and got this so test coverage is there.
Crediting @phenaproxima for the MR review but his name wasn't appearing on the ticket.
Seems all feedback has been addressed though.
Comment #14
borisson_Agreeing with @smustgrave, all feedback has been addressed, and this is a good improvement.
Comment #16
alexpott@longwave, @Wim Leers and I have discussed this issue at length. The discussion resulted in wanting to explore some other options, namely:
1. Do it at a different level, for example \Drupal\Core\TypedData\Validation\TypedDataMetadata::getConstraints(), which is what the validation system always calls — and detect presence of both and configure the other one correctly
2. Override NotBlankValidator and just make allowNull: true do nothing.
3. Look into \Symfony\Component\Validator\Constraints\Sequentially
4. Change getDefaultConstraints() to configured NotBlank correctly instead of adding NotNull when $definition->isRequired() and NotBlank is present already.
Comment #17
wim leers👍 Thanks, @alexpott!
Just pushed an implementation of option 1.
Why?
to
— https://symfony.com/doc/current/reference/constraints/Sequentially.html
i.e. if
NotNullis present, run it first, and if it doesn’t pass, don’t execute any of the other constraints; if it does pass, run all other constraints like we do today.But that's a huge change, with unpredictable ripple effects, and there's much more nuance to it than that — there's other validation constraint execution ordering issues, and they have been known for >7 years: #2820364 — see #2820364-85: Entity + Field + Property validation constraints are processed in the incorrect order for a recent update.
IOW: I think special-casing
NotNullonly for now (prior to fixing that entire massive issue) might be okay, but I’m not 100% certain.NotNullandNotBlankare declared simultaneously (like forstring__not_null__not_blankin the test coverage), but @alexpott says we could disallow this and trigger a warning. I'd be fine with that, but it's technically a BC break too, and we historically have no verification whatsoever that data types or config schema types make sense — that's why #3401837: Add basic validation to config schema definitions and #3404431: Filter settings schema types are incorrect exist. I'd definitely be in favor for starting to add validation for them though, that'd be an important first step to improving their DX!Comment #18
wim leersI just tried implementing
Sequentially.Looks like my fear was unfounded: the "unpredictable ripple effects" did not happen, thanks to
\Drupal\Core\TypedData\Validation\RecursiveContextualValidator::validate()being very narrow in what it accepts:… because
\Symfony\Component\Validator\Constraints\SequentiallyValidator::validate()calls Drupal'sRecursiveContextualValidator::validate()(the first ~10 lines of which are displayed above), and$data === 'en'at this point (for the langcode), it throws the exception with theThe passed value must be a typed data object.message.IOW: to adopt Symfony's
Sequentially, we need to revise a lot about how Drupal uses thesymfony/validatorcomponent. For #2820364: Entity + Field + Property validation constraints are processed in the incorrect order we probably will need validation groups, which as you can see above are also explicitly not supported.Comment #19
wim leersWill figure out how to make that work 😊
Comment #20
alexpottRe #18 - I think we'd need our own Sequentially.
Comment #21
wim leersImplemented option 4.
Due to
any change I make in
getDefaultConstraints()gets overwritten automatically.So this change must happen in the quoted code (
\Drupal\Core\TypedData\DataDefinition::getConstraints()).Comment #22
phenaproximaOnly one comment about a comment, but otherwise this looks right to me and I will RTBC it once my feedback is addressed in some way. :)
Comment #23
wim leersDone 😄
Comment #24
phenaproximaShip it!
Comment #25
alexpottCommitted 5cd249e and pushed to 11.x. Thanks!
Comment #27
wim leersThanks!
This unblocked #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support but also simplified #3379091 (see #3379091-25: Make NodeType config entities fully validatable) as well as any future work on adding validation constraints where
NotBlankis relevant! 👍