Validation: add AssociativeListValidator

+ fix template declarations
master 3.13.0
Julien Rosset 1 week ago
parent ba27ae5963
commit 761067e48a

@ -7,7 +7,7 @@ use DateTimeInterface;
/**
* An argument/option value validator expecting a date and/or time
*
* @template-implements BasedValidator<RegexValidator>
* @extends BasedValidator<DateTimeInterface, RegexValidator>
*/
abstract class AbstractDateTimeValidator extends BasedValidator {
/**

@ -0,0 +1,75 @@
<?php
namespace jrosset\CliProgram\Validation\Validators;
use Arrayy\Type\StringCollection;
use Closure;
/**
* An argument/option value validator based on an associative list of value
*
* Key = User input
* <br>Value = Real value (see {@see IValidator::getValue() getValue()})
*
* @implements IValidatorWithSuggestions<string>
*/
class AssociativeListValidator implements IValidatorWithSuggestions {
use TIdenticalValidDefaultValidator;
/**
* @use TInternalValueValidator<string>
*/
use TInternalValueValidator;
/**
* @var StringCollection The list of allowed values
*/
private StringCollection $allowedValues;
/**
* Create a validator
*
* @param StringCollection|null $allowedValues The list of allowed values
*/
public function __construct (?StringCollection $allowedValues = null) {
$this->setAllowedValues($allowedValues ?? new StringCollection());
}
/**
* @inheritDoc
*/
public function validate (mixed $value): bool {
if ($this->allowedValues->keyExists($value)) {
$this->setValue($this->allowedValues->get($value));
return true;
}
return false;
}
/**
* The list of allowed values
*
* @return StringCollection The list of allowed values
*/
public function getAllowedValues (): StringCollection {
return $this->allowedValues;
}
/**
* Set the list of allowed values
*
* @param StringCollection $allowedValues The list of allowed values
*
* @return $this
*/
public function setAllowedValues (StringCollection $allowedValues): self {
$this->allowedValues = $allowedValues;
return $this;
}
/**
* @inheritDoc
*/
public function getSuggestions (): Closure|array {
return $this->getAllowedValues()->getKeys()->toArray();
}
}

@ -5,7 +5,10 @@ namespace jrosset\CliProgram\Validation\Validators;
/**
* An argument/option value validator based on another, internal, validator
*
* @template TValidator of IValidator
* @template TValue of mixed The type of the returned value
* @template TValidator of IValidator The type of the internal validator
*
* @extends IValidator<TValue>
*/
abstract class BasedValidator implements IValidator {
/**

@ -7,8 +7,6 @@ use DateTimeInterface;
/**
* An argument/option value validator expecting a date and time
*
* @template-implements BasedValidator<RegexValidator>
*/
class DateTimeValidator extends AbstractDateTimeValidator {
/**

@ -7,8 +7,6 @@ use DateTimeInterface;
/**
* An argument/option value validator expecting a date (without time)
*
* @template-implements BasedValidator<RegexValidator>
*/
class DateValidator extends AbstractDateTimeValidator {
/**

@ -7,11 +7,14 @@ use InvalidArgumentException;
/**
* An argument/option value validator expecting a decimal
*
* @template-implements BasedValidator<RegexValidator>
* @template-implements TInternalValueValidator<float>
* @extends BasedValidator<float, RegexValidator>
*/
class DecimalValidator extends BasedValidator {
use TIdenticalValidDefaultValidator;
/**
* @use TInternalValueValidator<float>
*/
use TInternalValueValidator;
/**
@ -47,8 +50,8 @@ class DecimalValidator extends BasedValidator {
parent::__construct(
new RegexValidator(
/** @lang PhpRegExp */ '/^(?<int>[+-]?(?:\d{1,3}' . $this->thousandsSeparator . '?(?:\d{3}' . $this->thousandsSeparator . '?)*\d{3}|\d{1,3}))(?:' . $this->decimalSeparator
. '(?<dec>\d+))?$/'
/** @lang PhpRegExp */
"/^(?<int>[+-]?(?:\\d{1,3}$this->thousandsSeparator?(?:\\d{3}$this->thousandsSeparator?)*\\d{3}|\\d{1,3}))(?:$this->decimalSeparator(?<dec>\\d+))?\$/"
)
);
}

@ -11,8 +11,13 @@ use Symfony\Component\Console\Completion\CompletionInput;
/**
* An argument/option value validator for a directory path
*
* @implements IValidatorWithSuggestions<string>
*/
class DirectoryValidator implements IValidatorWithSuggestions {
/**
* @use TInternalValueValidator<string>
*/
use TInternalValueValidator;
/**
@ -80,7 +85,7 @@ class DirectoryValidator implements IValidatorWithSuggestions {
return false;
}
$this->setValue($value);
$this->setValue((string)$value);
return true;
}

@ -4,11 +4,17 @@ namespace jrosset\CliProgram\Validation\Validators;
/**
* An argument/option value validator expecting an email address
*
* @implements IValidator<string>
*/
class EmailValidator implements IValidator {
use TInternalValueValidator;
use TIdenticalValidDefaultValidator;
/**
* @use TInternalValueValidator<string>
*/
use TInternalValueValidator;
/**
* @inheritDoc
*/

@ -13,8 +13,9 @@ use UnitEnum;
* An argument/option value validator based on an enumeration
*
* @template TEnum of UnitEnum
* @template-implements IValidator<TEnum>
* @template-implements TInternalValueValidator<TEnum>
*
* @extends BasedValidator<TEnum, ListValidator>
* @implements IValidatorWithSuggestions<TEnum>
*/
class EnumValidator extends BasedValidator implements IValidatorWithSuggestions {
/**
@ -53,10 +54,14 @@ class EnumValidator extends BasedValidator implements IValidatorWithSuggestions
/**
* @inheritDoc
*
* @return TEnum|null The value
*
* @throws ReflectionException
*/
public function getValue (): UnitEnum {
$enumCase = $this->getInternalValidator()->getValue();
public function getValue (): ?UnitEnum {
if (($enumCase = $this->getInternalValidator()->getValue()) === null) {
return null;
}
return $this->enum->getCase($enumCase)->getValue();
}

@ -5,7 +5,7 @@ namespace jrosset\CliProgram\Validation\Validators;
use Arrayy\Collection\AbstractCollection;
/**
* A list of options of a filesystem based validator
* A list of options of a filesystem-based validator
*
* @extends AbstractCollection<FilesystemValidationOption>
*/

@ -5,7 +5,7 @@ namespace jrosset\CliProgram\Validation\Validators;
/**
* An argument/option value validator
*
* @template TValue The Type of the returned value
* @template TValue of mixed The type of the returned value
*/
interface IValidator {
/**
@ -26,9 +26,9 @@ interface IValidator {
*/
public function validate (mixed $value): bool;
/**
* Get the value, after it's validation
* Get the value, after the validation
*
* @return TValue|null The value
*/
public function getValue ();
public function getValue (): mixed;
}

@ -10,7 +10,8 @@ use Symfony\Component\Console\Completion\Suggestion;
/**
* An argument/option value validator
*
* @template TValue The Type of the returned value
* @template TValue of mixed The type of the returned value
*
* @extends IValidator<TValue>
*/
interface IValidatorWithSuggestions extends IValidator {

@ -7,11 +7,14 @@ use InvalidArgumentException;
/**
* An argument/option value validator expecting an integer
*
* @template-implements BasedValidator<RegexValidator>
* @template-implements TInternalValueValidator<int>
* @extends BasedValidator<int, RegexValidator>
*/
class IntegerValidator extends BasedValidator {
use TIdenticalValidDefaultValidator;
/**
* @use TInternalValueValidator<int>
*/
use TInternalValueValidator;
/**
@ -42,7 +45,7 @@ class IntegerValidator extends BasedValidator {
parent::__construct(
new RegexValidator(
/** @lang PhpRegExp */ '/^[+-]?(?:\d{1,3}' . $this->thousandsSeparator . '?(?:\d{3}' . $this->thousandsSeparator . '?)*\d{3}|\d{1,3})$/'
/** @lang PhpRegExp */ "/^[+-]?(?:\\d{1,3}$this->thousandsSeparator?(?:\\d{3}$this->thousandsSeparator?)*\\d{3}|\\d{1,3})\$/"
)
);
}

@ -3,68 +3,25 @@
namespace jrosset\CliProgram\Validation\Validators;
use Arrayy\Type\StringCollection;
use Closure;
/**
* An argument/option value validator based on a list of value
*
* @template TValue
* @template-implements IValidator<TValue>
* @template-implements TInternalValueValidator<TValue>
*/
class ListValidator implements IValidatorWithSuggestions {
use TIdenticalValidDefaultValidator;
use TInternalValueValidator;
/**
* @var StringCollection The list of allowed values
*/
private StringCollection $allowedValues;
class ListValidator extends AssociativeListValidator {
/**
* Create a validator
*
* @param StringCollection|null $allowedValues The list of allowed values
*/
public function __construct (?StringCollection $allowedValues = null) {
$this->setAllowedValues($allowedValues ?? new StringCollection());
}
/**
* @inheritDoc
*/
public function validate (mixed $value): bool {
if ($this->getAllowedValues()->contains($value)) {
$this->setValue($value);
return true;
}
return false;
}
/**
* The list of allowed values
*
* @return StringCollection The list of allowed values
*/
public function getAllowedValues (): StringCollection {
return $this->allowedValues;
//region Rebuild the allowed values collection with key = value
$realAllowedValues = new StringCollection();
if ($allowedValues !== null) {
foreach ($allowedValues as $value) {
$realAllowedValues->add($value, $value);
}
/**
* Set the list of allowed values
*
* @param StringCollection $allowedValues The list of allowed values
*
* @return $this
*/
public function setAllowedValues (StringCollection $allowedValues): self {
$this->allowedValues = $allowedValues;
return $this;
}
/**
* @inheritDoc
*/
public function getSuggestions (): Closure|array {
return $this->getAllowedValues()->toArray();
//endregion
parent::__construct($realAllowedValues);
}
}

@ -4,6 +4,8 @@ namespace jrosset\CliProgram\Validation\Validators;
/**
* An argument/option value validator based on a regex
*
* @implements IValidator<string>
*/
class RegexValidator implements IValidator {
use TIdenticalValidDefaultValidator;
@ -87,6 +89,8 @@ class RegexValidator implements IValidator {
/**
* @inheritDoc
*
* @return string|null The value or Null if not set
*/
public function getValue (): ?string {
return $this->getMatch(static::GROUP_VALUE) ?? $this->getMatch(0);

@ -8,31 +8,30 @@ namespace jrosset\CliProgram\Validation\Validators;
*
* Call {@see self::setValue()} to set the value
*
* @template TValue
* @template-implements IValidator<TValue>
* @template TValue of mixed
*/
trait TInternalValueValidator {
/**
* @var TValue|null The current value, after it's validation
* @var TValue|null The current value, after the validation
*/
private $value = null;
private mixed $value = null;
/**
* Get the value, after it's validation
* Get the value, after the validation
*
* @return TValue|null The value
*/
public function getValue () {
public function getValue (): mixed {
return $this->value;
}
/**
* Set the value
*
* @param TValue $value The value (after it's validation)
* @param TValue $value The value (after the validation)
*
* @return $this
*/
protected function setValue ($value): static {
protected function setValue (mixed $value): static {
$this->value = $value;
return $this;
}

@ -7,8 +7,6 @@ use DateTimeInterface;
/**
* An argument/option value validator expecting a date (without time)
*
* @template-implements BasedValidator<RegexValidator>
*/
class TimeValidator extends AbstractDateTimeValidator {
/**

Loading…
Cancel
Save