Problem/Motivation
Over at #3324140: Convert field_storage_config and field_config's form validation logic to validation constraints, we identified the need for a EntityBundleExists constraint for FieldConfig and BaseFieldOverrideconfig entities.
However, there are at least a few other uses for this:
condition.plugin.entity_bundle:*'sbundlessequence itemsviews.argument_validator_entity`'sbundlessequenceLanguageContentSettingsconfig entity (language.content_settings.*.*`):target_bundlefield- et cetera.
Steps to reproduce
N/A
Proposed resolution
- Extract
EntityBundleExistsConstraint(Validatorfrom that issue - Add explicit test coverage for the new constraint
- Adopt in all config entities in core where it makes sense
- Maybe adopt in some simple config, if there's little doubt about it being valuable
Remaining tasks
- ✅ Constraint + test coverage
- ✅ Adopt in all relevant config entities:
EntityFormDisplay,EntityViewDisplay,ContentLanguageSettingsandFieldConfig - ✅ Update corresponding
ConfigEntityValidationTestBasesubclasses - ✅ Create change record
User interface changes
None.
API changes
None.
Well, sort of. There's an internal class added, \Drupal\Core\Config\Schema\TypeResolver, which contains logic previously in \Drupal\Core\Config\TypedConfigManager concerned with replacing tokens like %parent with actual, fully resolved config names. TypeResolver exposes that logic as public methods so that the constraint can use it for a little dynamism, since it's very possible that you'll want to sometimes specify entity type IDs using dynamic tokens.
Data model changes
None.
Release notes snippet
None.
Issue fork drupal-3382581
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
- 11.x
compare
- 3382581-add-new-entitybundleexists
changes, plain diff MR !4636
Comments
Comment #4
phenaproximaComment #5
phenaproximaComment #6
wim leersLooking great!
AFAICT this is ready once:
FieldConfigalso adopts it 😇Comment #7
phenaproximaComment #8
phenaproximaDrafted a change record: https://www.drupal.org/node/3384086
Comment #9
phenaproximaComment #10
wim leersLooking good!
Only one concern: we can't just make
\Drupal\Core\Config\TypedConfigManager::replaceVariable()public — doing that is a BC break. Posted a proposal on the MR! 😊Comment #11
phenaproximaComment #12
wim leers\Drupal\Core\Entity\Plugin\Validation\Constraint\BundleConstraint(introduced in #1845546: Implement validation for the TypedData API, with a follow-up that I just pushed forward after >10 years of silence: #1905620: Enforce the BundleConstraint "bundle" option to be always an array).I think we should document what the difference is between the (existing)
Bundleand (new)BundleExists.AFAICT
BundleConstraintshould never have existed … it should just have used theChoiceconstraint instead?! It has existed since 2010, so it's not like it wasn't available 😅\Drupal\Core\Config\Schema\TypeResolverand why we do that.[%parent.something]syntax including the square brackets to users of validation constraints. We shouldn't do that IMHO — the resulting YAML is very tricky to misread as an array 😅 Also, we just don't need it!This issue is very close IMHO! 🤩
Comment #13
phenaproximaComment #14
borisson_This looks great, and was ready to rtbc apart from a few things in #12, I think all relevant questions from @Wim Leers have been answered, but leaving it for him to rtbc next week to be sure.
Comment #15
borisson_Comment #16
wim leersSo very close, but this is still missing test coverage for invalid
entityTypeIdoption values to ensure a good DX for developers adopting this validation constraint!Comment #17
phenaproximaOK, I tried to add the requested test coverage. How's this look?
Comment #18
borisson_Back to rtbc, I really love how many of our tests are now more complete/explicit because of this new contraint.
As a sidenote, do we allow % in our schema's for things that are not replaceable? Because if we don't, we could probably throw an error and tell people something like: %paren found in resolved schema, there is a typo in your schema definition..
But that can 100% be a followup to this, what we have in this issue is already an improvement.
Comment #19
wim leers#18: WRT that validation: I said the same thing at #16 3 weeks ago. But I agree that can happen in a follow-up, especially because it's A) a pre-existing problem, B) in pre-existing code.
So, created the necessary follow-up: #3392903: Validate inputs of TypeResolver::resolveExpression(): only allow %parent, %type and %key.
RTBC++
Comment #20
wim leersComment #21
borisson_The follow-up created in #19 already has a patch. As soon as this is in, that one can be rerolled easily.
Comment #22
quietone commentedI read the issue summary, which was complete and easy to follow, and the comments. I didn't find any unanswered questions or other work to do. There are 2 unresolved comments from @Wim Leers in the MR but they have been addressed and @Wim Leers agreed this is RTBC.
The change record is up to date. Although I do wonder how people, for who English is a second language will interprets "There's a new validation constraint in town".
I did some hunting and found this quote from the Content style guide
I am not sure how one is supposed to know that an idiom is common and well-know but we should probably remove that from the change record. It would help is someone changed that. I don't think the use of 'in town' makes the change record unintelligible so I am leaving this at RTBC.
Comment #23
borisson_Rewritten the first two lines based on #22:
Comment #24
borisson_This needs a reroll, it no longer applies.
Comment #25
borisson_Merged 11.x back into this, back to rtbc.
Comment #26
borisson_It looks like I screwed up something with the merge I did. I will try to fix this.
Comment #27
borisson_The typeResolver that was introduced here (in TypedConfigManager), conflicts with other changes that been committed to 11.x in the meanwhile. I'm not sure how to best resolve this.
One of the breaking changes is in #3406487: Consistently use "dynamic type name" and "expression" instead of "variable value" in TypedConfigManager's terminology.
Comment #28
wim leers@borisson_: #3406487: Consistently use "dynamic type name" and "expression" instead of "variable value" in TypedConfigManager's terminology renamed
TypedConfigManager::replaceName()and::replaceVariable()to:: resolveDynamicTypeName()and::resolveExpression(), respectively. But it kept themprotected.This issue was lifting those 2 methods out of that class and making them
public.I think we can still do the exact same thing: just make them
static, move them out ofTypedConfigManagerand intoTypeResolver, and make bothpublic. That allows not breaking backwards compatibility.Comment #29
phenaproximaDid the stuff Wim explained in #28. Since this was basically just fixing merge conflicts, I'm restoring RTBC on the assumption that tests will pass.
Comment #30
borisson_Thanks for fixing that @phenaproxima!
Comment #31
wim leersphpcsandphpstanviolations.TypeResolveandTypedConfigManagerlook solid in the MR though!Comment #32
borisson_Actually, it's not a simple phpstan violation, it's because this entire else branch doesn't return anything, I think this means we are missing test coverage?
else { // Get nested value and continue processing. if ($name == '%parent') { /** @var \Drupal\Core\Config\Schema\ArrayElement $parent */ // Switch replacement values with values from the parent. $parent = $data['%parent']; $data = $parent->getValue(); $data['%type'] = $parent->getDataDefinition()->getDataType(); // The special %parent and %key values now need to point one level up. if ($new_parent = $parent->getParent()) { $data['%parent'] = $new_parent; $data['%key'] = $new_parent->getName(); } } else { $data = $data[$name]; }I fixed the phpcs failures.
Comment #33
phenaproximaThat code is moved directly from the pre-existing methods
\Drupal\Core\Config\TypedConfigManager::resolveDynamicTypeName()and\Drupal\Core\Config\TypedConfigManager::resolveExpression(). I don't think any action is needed; this issue is only exposing those methods in a new class, but not changing them in any other way.IMHO, if PHPStan is complaining about this, the correct approach is probably to shut it up here.
Comment #34
borisson_I agree with @phenaproxima, we can change the phpstan configuration later, or help it figure out what is going in here later, but I think this should just be the move.
I will try to pick this up after work
Comment #35
wim leersAFAICT this means we must update the PHPStan baseline?
Comment #36
phenaproximaI would adjust the baseline but I don't know how to do it. I tried editing the file manually but it doesn't seem to work properly. What am I missing?
Comment #37
phenaproximaOkay, well, after some wrasslin' I was finally able to get PHPStan to ignore that one error. However, once I got the regex correct, PHPStan had this to say:
Well...shit. So I ended up just ignoring that one path entirely, and PHPStan worked for me locally with no errors.
Comment #38
phenaproximaBack to work for the test failures.
Comment #39
phenaproximaComment #40
borisson_This was rtbc in #15 and #18 already, back to rtbc now that this is green again.
Comment #41
larowlanLeft some comments on the MR
Comment #42
phenaproximaComment #43
wim leersAFAICT everything was thoroughly addressed. I'm not a big fan of changing the decade-old logic that we're just lifting from elsewhere and making accessible, but it sure is more readable, and it was requested by core committer @larowlan so 👍 Two birds one stone!
Clarifying that this blocks #3324140: Convert field_storage_config and field_config's form validation logic to validation constraints, which is . It also blocks #2869792: [meta] Add constraints to all config entity types. This priority seems justified IMO.
Comment #44
larowlanIssue credits
Comment #45
larowlanCan we get https://www.drupal.org/node/3408266 updated to reflect the code, the method names haven't been renamed, they've been moved to a new TypeResolver class.
Fine to self RTBC, will keep an eye out for the update.
Comment #46
larowlanAlso left a comment about phpstan changes
Comment #47
phenaproximaTried to answer your questions, @larowlan, and updated the change record.
Comment #48
larowlanAdded a change to fix the missing return type, please put back to RTBC if you're happy
Comment #49
phenaproximaYup, I'm a lot happier without needing to mess with PHPStan's configuration! Thanks @larowlan.
Comment #51
larowlanCommitted to 11.x
Published both change records
Comment #53
wim leersThank you, @larowlan!
Unblocked & rerolled: