-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Console] Ease validating input options/arguments #21041
[Console] Ease validating input options/arguments #21041
Conversation
1616f9c
to
5ecbb2c
Compare
Good idea, but usage should be easier, like this: $option = new InputOption('email');
$option->addConstraint(new Email()); |
@maidmaid Thanks for your comment. The point of having callable validators is flexibility. Here validators can come from anywhere: $option = new InputOption('email');
$option->setValidator(['External\EmailValidator', 'validate']); And can process the value after validation: // canonicalize
$option = new InputOption('email');
$option->setValidator(['My\CanonicalEmailGuesser', 'guessCanonical']);
// convert the value to an object
$option = new InputOption('email');
$option->setValidator(function (string $email): User {
// will throw an exception if the user cannot be found
return $this->userRepository->getUserByEmail($email);
});
// dynamic default value (e.g. in addition of a static default value)
$option = new InputOption('uuid');
$option->setValidator(function ($uuid): \Ramsey\UuidInterface {
return \Ramsey\Uuid::isValid($uuid) ? \Ramsey\Uuid::fromString($uuid) : \Ramsey\Uuid::uuid4();
});
// basic type cast
$option = new InputArgument('amount');
$option->setValidator(function ($v): int { return (int) $v; });
// strict check
$option = new InputArgument('service');
$option->setValidator(function ($service) {
if ('service_container' === $service) {
throw new \InvalidArgumentException();
}
}); Yet your proposal is sexy but so less flexible: It would make the feature dependent of the Symfony Validator, which involve that the Mixing validation and processing might not look ideal but imho it doesn't hurt, it's consistent with the QuestionHelper input validation and the Config validation. I do think all that stuff should be done in Edit: All input options and arguments are now passed to validators, allowing to validate an option/argument based on the values of other options/arguments: $argument = new InputArgument('foo');
$option = new InputOption('bar', null, InputOption::VALUE_OPTIONAL);
$option->setValidator(function ($value, $options, $arguments) {
return 'dummy' === $arguments['foo'] ? 'dummy_'.$value : $value;
}); |
Totally agree with @chalasr. However a better integration with the validator component can be proposed after this one is merged IMHO. For instance in order to handle the constraint violation list in a nice output automatically or applying constraints on an option/argument, by providing a base callable making use of the validation component. |
Great 👍 |
5ecbb2c
to
05086cf
Compare
05086cf
to
390dabf
Compare
Actually, I have something else in mind. |
This allows validating input definition from
Command::configure()
using validators instead of doing it manually inexecute()
.InputArgument
/InputOption
would now have asetValidator(callable $validator)
.Validators can throw an exception in case of invalid value or must return the value, modified or not (e.g. prefixed or converted to an object), quite similar to the input validation of the question helper.
Simple example which prefixes a given argument value
Example using the validator component
This is a simpler alternative to #20899 which proposes "form like" commands including support for annotations, param converters, validation constraints... that is a bit too much imho but could still be added later.