The validators of each {@see InputArgument} */ private array $argumentsValidator = []; /** * @var array The validators of each {@see InputOption} */ private array $optionsValidator = []; /** * @inheritDoc * * @throws Throwable If an argument or option is not valid */ protected function interact (InputInterface $input, OutputInterface $output): void { parent::interact($input, $output); $this->validate($input, $output); } /** * Validate the command input * * @param InputInterface $input The input * @param OutputInterface $output The output * * @return void */ protected function validate (InputInterface $input, OutputInterface $output): void { $this->validateArguments($input, $output); $this->validateOptions($input, $output); } /** * Validate values of {@see InputArgument} * * @param InputInterface $input The input * @param OutputInterface $output The output * * @return void * * @noinspection PhpUnusedParameterInspection */ protected function validateArguments (InputInterface $input, OutputInterface $output): void { foreach ($this->argumentsValidator as $argumentName => $argumentValidator) { if ($input->hasArgument($argumentName)) { if (!$argumentValidator->validate($input->getArgument($argumentName))) { throw new InvalidValueException(sprintf('The "%s" argument has not a valid value', $argumentName)); } $input->setArgument($argumentName, $argumentValidator->getValue()); } } } /** * Validate values of {@see InputOption} * * @param InputInterface $input The input * @param OutputInterface $output The output * * @return void * * @noinspection PhpUnusedParameterInspection */ protected function validateOptions (InputInterface $input, OutputInterface $output): void { foreach ($this->optionsValidator as $optionName => $optionValidator) { if ($input->hasOption($optionName)) { if (!$optionValidator->validate($input->getOption($optionName))) { throw new InvalidValueException(sprintf('The "--%s" option has not a valid value', $optionName)); } $input->setOption($optionName, $optionValidator->getValue()); } } } /** * Adds an argument * * @param string $name The argument name * @param int|null $mode The argument mode: InputArgument::REQUIRED or InputArgument::OPTIONAL * @param mixed $default The default value (for InputArgument::OPTIONAL mode only) * @param string $description The argument description * @param IValidator|null $validator The validator or Null if none * @param Closure|array|null $suggestedValues The function or list of suggested values when completing ; Null if none * * @return $this * * @throws InvalidArgumentException When argument mode is not valid */ public function addArgument ( string $name, int $mode = null, string $description = '', mixed $default = null, ?IValidator $validator = null, Closure|array|null $suggestedValues = null ): static { $default = static::treatStringableDefaultValue($default); if ($validator !== null) { $default = $validator->getValidDefault($default); } if ($suggestedValues !== null) { parent::addArgument($name, $mode, $description, $default, $suggestedValues); } else { parent::addArgument($name, $mode, $description, $default); } return $this->setArgumentValidator($name, $validator); } /** * Set the validator for an {@see InputArgument} * * @param string $name The {@see InputArgument} name (must exist) * @param IValidator|null $validator The validator ; Null to remove it * * @return $this * * @throws InvalidArgumentException If the {@see InputArgument} doesn't exist */ public function setArgumentValidator (string $name, ?IValidator $validator): static { if (!$this->getDefinition()->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist', $name)); } if ($validator === null) { unset($this->argumentsValidator[$name]); } else { $this->argumentsValidator[$name] = $validator; } return $this; } /** * Get the validator for an {@see InputArgument} * * @param string $name The {@see InputArgument} name (must exist) * * @return IValidator|null The validator or Null if none */ public function getArgumentValidator (string $name): ?IValidator { if (!$this->getDefinition()->hasArgument($name)) { throw new InvalidArgumentException(sprintf('The "%s" argument does not exist', $name)); } return $this->argumentsValidator[$name] ?? null; } /** * Adds an option * * @param string $name The argument name * @param string|string[]|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts * @param int|null $mode The option mode: One of the InputOption::VALUE_* constants * @param string $description The argument description * @param mixed $default The default value (must be null for InputOption::VALUE_NONE) * @param IValidator|null $validator The validator or Null if none ; ignored if **$mode** = {@see InputOption::VALUE_NONE} * @param Closure|array|null $suggestedValues The function or list of suggested values when completing ; Null if none * * @return $this * * @throws InvalidArgumentException When argument mode is not valid */ public function addOption ( string $name, string|array|null $shortcut = null, int $mode = null, string $description = '', mixed $default = null, ?IValidator $validator = null, Closure|array|null $suggestedValues = null ): static { $default = static::treatStringableDefaultValue($default); if ($validator !== null) { $default = $validator->getValidDefault($default); } if ($suggestedValues !== null) { parent::addOption($name, $shortcut, $mode, $description, $default, $suggestedValues); } else { parent::addOption($name, $shortcut, $mode, $description, $default); } return $this->setOptionValidator($name, $validator); } /** * Set the validator for an {@see InputOption} * * @param string $name The {@see InputOption} name (must exist) * @param IValidator|null $validator The validator ; Null to remove it * * @return $this * * @throws InvalidArgumentException If the {@see InputOption} doesn't exist */ public function setOptionValidator (string $name, ?IValidator $validator): static { if (!$this->getDefinition()->hasOption($name)) { throw new InvalidArgumentException(sprintf('The "--%s" option does not exist', $name)); } if ($validator === null) { unset($this->optionsValidator[$name]); } else { $this->optionsValidator[$name] = $validator; } return $this; } /** * Get the validator for an {@see InputOption} * * @param string $name The {@see InputOption} name (must exist) * * @return IValidator|null The validator or Null if none */ public function getOptionValidator (string $name): ?IValidator { if (!$this->getDefinition()->hasOption($name)) { throw new InvalidArgumentException(sprintf('The "--%s" option does not exist', $name)); } return $this->optionsValidator[$name] ?? null; } /** * If it is the case, transform a {@see Stringable} default value into a string * * @param mixed $default The default value * * @return mixed The default value */ protected static function treatStringableDefaultValue (mixed $default): mixed { if ($default instanceof Stringable) { return $default->__toString(); } return $default; } }