Problem/Motivation

Let's start with a very useful constraint: Sequentially. Which allows us to layer constraints. Which could help in only reporting errors which are useful instead of walking through all the constraints.

Steps to reproduce

Proposed resolution

We need our recursive validator to support Symfony's composite constraints.

Remaining tasks

User interface changes

None

Introduced terminology

N/a

API changes

Added support for Sequentially
Added \Drupal\Core\Validation\ExecutionContext::getConstraint() as an internal method to allow us to traverse the constraints correctly.

Data model changes

None

Release notes snippet

N/a

Issue fork drupal-3521131

Command icon 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:

Comments

bbrala created an issue. See original summary.

bbrala’s picture

Status: Active » Needs review

Wow, am i dreaming. This little trick might make it possible to support those symfony constraints without weirdness.

Everything is green... It cant be that easy right?

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs Review Queue Initiative

Left some small comments and a question

If you are another contributor eager to jump in, please allow the previous poster(s) at least 48 hours to respond to feedback first, so they have the opportunity to finish what they started!

bbrala’s picture

Status: Needs work » Needs review
Issue tags: +Needs subsystem maintainer review

Fixed issues, but kinda need someone into validation to review this since it feels weird this works at face value. It might overlook issues.

bbrala’s picture

Removing tag since committer who will review this seems to be the subsystem maintainer.

bbrala’s picture

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Going to mark because I believe all feedback has been addressed on this one, thank you for adding the CR.

quietone’s picture

Status: Reviewed & tested by the community » Needs work

I did not do a code review but I left a question about the name of the constraint and then made some minor suggestions.

This should have another opinion about the name, not just mine.

bbrala’s picture

Status: Needs work » Reviewed & tested by the community

Thanks quietone for the review. Since it was all style/wording ill set it back to RTBC

borisson_’s picture

While this is great, we don't usually add new features if they don't have an immediate usecase in core. Do you know where we could be using this? Or is this just about exposing all the symfony constraints?

bbrala’s picture

Valid point. As per parent Wim said he had a quite a few places where this was usefull, but he didnt say where. When i look at core i see a few places where this might be quite usefull. Few examples:

# file: block.schema.yml
    theme:
      type: string
      label: 'Theme'
      constraints:
        NotBlank: []
        ExtensionName: []
        ExtensionExists: theme

Here it could first say "Should not be blank", then if that is true "Invalid extension name", when "Extension does not exist".

This is way better than doing them all.

Same here:

# file: block.schema.yml
    region:
      type: string
      label: 'Region'
      constraints:
        NotBlank: []
        Callback: ['\Drupal\block\Entity\Block', validateRegion]

or

# Plugin \Drupal\ckeditor5\Plugin\CKEditor5Plugin\Language
ckeditor5.plugin.ckeditor5_language:
  type: mapping
  label: 'Language'
  constraints:
    FullyValidatable: ~
  mapping:
    language_list:
      type: string
      label: 'Language list ID'
      constraints:
        # Configuring this does not make sense without the corresponding button.
        CKEditor5ToolbarItemDependencyConstraint:
          toolbarItem: textPartLanguage
        # Only the following values are accepted.
        Choice:
          # United Nations "official languages".
          - un
          # Drupal's predefined language list.
          - all
          # Languages configured at /admin/config/regional/language for the site.
          - site_configured

I think a lot of the places where more than one constraint is defined we should use this. Should we pick one or perhaps just do follow ups? What do you think.

wim leers’s picture

#12++

borisson_’s picture

I think a lot of the places where more than one constraint is defined we should use this. Should we pick one or perhaps just do follow ups? What do you think.

I think doing followups makes most sense here.

bbrala’s picture

dcam made their first commit to this issue’s fork.

dcam’s picture

I'm checking all RTBC issues to ensure their new tests use attributes. Because these changes are minor and the tests are passing I'm going to leave the issue at RTBC.

dcam’s picture

The MR for this issue was identified as having a new Kernel/Functional test class that did not have the #[RunTestsInSeparateProcesses] attribute. A deprecation warning is now issued in the case of these omissions. I've rebased the MR added the attribute to prevent this from being committed as-is and accidentally breaking tests on HEAD. Because this is a minor change to test metadata and the tests are passing I am leaving the issue's status as RTBC.

alexpott’s picture

Issue tags: +PHP 8.5

Need this to fix a PHP 8.5 issue! Will merge once we're out of the commit freeze.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

I think we should convert the block region constraint here because it is where the PHP 8.5 deprecation is AND it shows we've got an implementation problem somewhere because the test is unable to get the correct violation property path...

alexpott’s picture

bbrala’s picture

alexpott’s picture

Issue summary: View changes
bbrala’s picture

Status: Needs work » Needs review

Ok, with the help of @alexpott the issue has been fixed and we can easily support all the Composite constratiants now.

I've fixed the tests, which also seem to proove sequentially is doing its work, which is awesome :)

godotislate’s picture

Status: Needs review » Needs work

Some comments on the MR.

bbrala’s picture

Status: Needs work » Needs review

Think i adressed all issues, setting NR (tests are running, sorry)

godotislate’s picture

Test failure seems unrelated, but should be re-run to make sure.
Otherwise looks good for RTBC.

bbrala’s picture

Status: Needs review » Reviewed & tested by the community

As per 27 rtbc

longwave’s picture

Status: Reviewed & tested by the community » Needs work

Looks good, I like the fact we are reusing the Symfony code directly now. Added a question about BC, and a possible followup - if we don't think the BC Is worth it this can go back to RTBC.

longwave’s picture

Status: Needs work » Reviewed & tested by the community

All threads resolved, back to RTBC.

bbrala’s picture

I know this is rtbc, but when working on https://www.drupal.org/project/drupal/issues/3535734 i ran into wanting "Required" also a composite constraint. Then i realized, why don't we initialize the nested constraints (first level ) in the ConstraintManager?

   public function create($name, $options) {
     if (!is_array($options)) {
       // Plugins need an array as configuration, so make sure we have one.
       // The constraint classes support passing the options as part of the
       // 'value' key also.
       $options = isset($options) ? ['value' => $options] : [];
     }
     $instance = $this->createInstance($name, $options);
     // @todo If instance of Composite, initialize nested constraints?
     return $instance;
   }

Then i wouldnt have to overwrite the Required constraint to add extra logic to the create method... and it might be able to just load composites without any overwriting?

benjifisher’s picture

Issue summary: View changes

The change record is pretty minimal. I think it would help to add "before and after" code snippets. You could use the changes to core/modules/block/config/schema/block.schema.yml in the current MR or use one of the examples from Comment #12.

I think that removing core/lib/Drupal/Core/Validation/Plugin/Validation/Constraint/AtLeastOneOfConstraintValidator.php counts as an API change. If so, then it should be listed in the issue summary and also in the change record (or a new, separate change record). It looks as though that class was added in Drupal 11.2.

I fixed some typos in the issue summary.

bbrala’s picture

Updated the change record and added a new one.

It is kinda an API change, but the chance of breakage is pretty much zero.

bbrala’s picture

Note about #13

Seems kinda hard. Not all composite constraints use the same property. The method to find out which property is the constraints is protected unfortunately which means we cannot know at that point which to use. A trait will work, but unless the method becomes pu b lic in symfony it's a no go without some bad magic.

alexpott’s picture

@bbrala there's another problem - \Symfony\Component\Validator\Constraints\Composite::getCompositeOption() is not static but we need to call it in \Drupal\Core\Validation\Plugin\Validation\Constraint\AtLeastOneOfConstraint::create() which is. A trait would be possible if we get them to change the method to a static but I feel that that is unlikely. Let's open a follow-up because I think we can achieve your idea of doing this in the ConstraintManager with just a little bit of work.

alexpott’s picture

Status: Reviewed & tested by the community » Needs review

Proved too easy to add the interface to support construction of the nested constraints in the manager... so did it here because this issue has become sort out nested constraints so they are nice to work with...

bbrala’s picture

Status: Needs review » Reviewed & tested by the community

Added comments, but only as indication of review. This looks very good, happy to see we don't need create anymore this way and we can add the symfony contraints easily. Still needs an overwrite of the existing constraint, which is unfortunate (and might proove very annoying when trying to implement the Collection constraint which hard codes new Required() sometimes. But it's a big upgrade on how this works.

Awesome, im happy. LGTM :D

bbrala’s picture

Issue tags: +blocker

Note, this blockes kinda blocks #3535734: Make block.settings.inline_block:* fully validatable, although maybe a soft block.

bbrala’s picture

Status: Reviewed & tested by the community » Needs work

Found a possible issue when passing other options than constrainst to Composite contraints.

bbrala’s picture

Status: Needs work » Reviewed & tested by the community

Talked to alex, creating a follow up.

bbrala’s picture

bbrala’s picture

catch’s picture

Version: 11.x-dev » 11.3.x-dev
Status: Reviewed & tested by the community » Fixed

Had a couple of questions but they were already answered by discussion in the MR.

Committed/pushed to 11.x and cherry-picked to 11.3.x, thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • catch committed d4441514 on 11.x
    feat: #3521131 Add support for Sequentially constraint
    
    By: @bbrala
    By...

bbrala’s picture

Awesome! Thanks

  • longwave committed 177fc79d on 11.3.x authored by catch
    feat: #3521131 Add support for Sequentially constraint
    
    By: @bbrala
    By...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.