Problem/Motivation

In order to add validation constraints to all user role configuration #3445215: Add validation constraints to user.role.*, it was necessary to add a new public static function (getAllValidPermissions() it was necessary to add a convenience callback to be used as a choice validator that only called one method on a Drupal service:

return array_keys(\Drupal::service('user.permissions')->getPermissions());

This isn't the only place where will need to create additional functions that only return valid choices. If we want to make all configuration in Drupal fully validatable then there are many places where we need to do something similar.

For instance, the same thing was done in /core/modules/editor/src/Entity/Editor.php:

 /**
  * Computes all valid choices for the "image_upload.scheme" setting.
  *
  * @see editor.schema.yml
  *
  * @return string[]
  *   All valid choices.
  *
  * @internal
  */
 public static function getValidStreamWrappers(): array {
   return array_keys(\Drupal::service('stream_wrapper_manager')->getNames(StreamWrapperInterface::WRITE_VISIBLE));
 }

We don't have many other examples at this point, but there is still of a lot of configuration to validate and there may be more places where we need to add these functions that might not be useful for anything other than constraint validation.

Proposed resolution

As discussed with @xjm, @wim-leers, @carsoncho, and @jcorrao, we thought it might be useful to override Symfony's Choice Constraint doing something like this pseudo code:


namespace Drupal\Core\Validation\Plugin\Validation\Constraint;

use Drupal\Core\StringTranslation\TranslatableMarkup;
use Symfony\Component\Validator\Constraints\Choice;

#[Constraint(
  id: 'Choice',
  label: new TranslatableMarkup('Choice', [], ['context' => 'Validation'])
)]
class ChoiceConstraint extends Choice {

  public $callbackArgs = [];

}
 

and extend the ChoiceValidator:


namespace Drupal\Core\Validation\Plugin\Validation\Constraint;

use Symfony\Component\Validator\Constraints\ChoiceValidator;

/**
 * Validates complex data.
 */
class ChoiceConstraintValidator extends ChoiceValidator {

  /**
   * {@inheritdoc}
   */
  public function validate(mixed $value, Constraint $constraint) {
    assert($constraint instanceof ChoiceConstraint);
    if ($constraint->callbackArgs) {
      $callback = function() {
        // @todo;
      };
    }
    $constraint->callback = $callback;
    parent::validate($value, $constraint);
  }

}

Remaining tasks

Decide if this would be useful.

User interface changes

None.

API changes

New Choice validator that would allow us to do something like this is /core/modules/user/config/schema/user.schema.yml:

user.role.*:
  ...
  mapping:
    ...
    permissions:
      sequence:
        type: string
        label: 'Permission'
+         constraints:
+           Choice:
+             callback: user.permissions:getPermissions
+             transform: array_keys

Issue fork drupal-3446364

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

mtift created an issue. See original summary.

mtift’s picture

Issue summary: View changes
longwave’s picture

This does seem like it would be useful but should this replace the Symfony constraint or just be a new Drupal specific one that extends Choice?

carsoncho’s picture

[#3] The idea would be to extend Symfony's Constraint rather than copy and duplicate. Extending it would then allow for us to have the generic functionality and would be BC.

mtift’s picture

Status: Active » Needs work
narendrar’s picture

mtift’s picture

Assigned: mtift » Unassigned
mtift’s picture

Status: Needs work » Needs review
mtift’s picture

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs change record

Re-ran the failing test and it was random.

Looking at the change though I imagine it would need a change record for contrib/custom modules to be able to leverage it. Tagging for that.

mtift’s picture

Status: Needs work » Needs review
Related issues: -#2323301: Deprecate the "two double colons" check in Renderer::doCallback()

Good call. I added the change record.

mtift’s picture

Issue tags: -Needs change record
borisson_’s picture

Status: Needs review » Reviewed & tested by the community

I think this looks great, this makes it easier for other issues to land. Marking as rtbc.

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

alexpott’s picture

Oh I thought we had landed #2951046: Allow parsing and writing PHP class constants and enums in YAML files... we really should get that done.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

We can update the user role constraint to use this.

narendrar’s picture

Title: Override Symfony's Choice Constraint » [PP-1] Override Symfony's Choice Constraint
Status: Needs work » Postponed
Related issues: +#2951046: Allow parsing and writing PHP class constants and enums in YAML files

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.