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
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
Comment #2
mtiftComment #3
longwaveThis 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?
Comment #4
carsoncho commented[#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.
Comment #6
mtiftComment #7
narendrarComment #8
mtiftComment #9
mtiftComment #10
mtiftComment #11
smustgrave commentedRe-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.
Comment #12
mtiftGood call. I added the change record.
Comment #13
mtiftComment #14
borisson_I think this looks great, this makes it easier for other issues to land. Marking as rtbc.
Comment #16
alexpottOh I thought we had landed #2951046: Allow parsing and writing PHP class constants and enums in YAML files... we really should get that done.
Comment #17
alexpottWe can update the user role constraint to use this.
Comment #18
narendrarPP on #2951046: Allow parsing and writing PHP class constants and enums in YAML files