* @template-implements TInternalValueValidator */ class DecimalValidator extends BasedValidator { use TIdenticalValidDefaultValidator; use TInternalValueValidator; /** * @var string The locale thousands separator */ private string $decimalSeparator; /** * @var string The locale thousands separator */ private string $thousandsSeparator; /** * @var float|null The minimal value allowed, Null if none */ private ?float $minAllowedValue = null; /** * @var float|null The maximal value allowed, Null if none */ private ?float $maxAllowedValue = null; /** * Create a validator * * @param float|null $minAllowedValue The minimal value allowed, Null if none * @param float|null $maxAllowedValue The maximal value allowed, Null if none */ public function __construct (?float $minAllowedValue, ?float $maxAllowedValue) { $locale = localeconv(); $this->decimalSeparator = preg_quote($locale['decimal_point'], '/'); $this->thousandsSeparator = preg_quote($locale['thousands_sep'], '/'); $this->setMinAllowedValue($minAllowedValue); $this->setMaxAllowedValue($maxAllowedValue); $this->value = 0; parent::__construct( new RegexValidator( /** @lang PhpRegExp */ '/^(?[+-]?(?:\d{1,3}' . $this->thousandsSeparator . '?(?:\d{3}' . $this->thousandsSeparator . '?)*\d{3}|\d{1,3}))(?:' . $this->decimalSeparator . '(?\d+))?$/' ) ); } /** * @inheritDoc */ public function validate (mixed $value): bool { if (!parent::validate($value)) { return false; } $this->setValue( (float)( preg_replace( [ '/^+/', '/' . $this->thousandsSeparator . '/', ], [ '', '', ], $this->getInternalValidator()->getMatch('int') ) . '.' . $this->getInternalValidator()->getMatch('dex') ) ); if ($this->getMinAllowedValue() !== null && $value < $this->getMinAllowedValue()) { return false; } if ($this->getMaxAllowedValue() !== null && $value > $this->getMaxAllowedValue()) { return false; } return true; } /** * The minimal value allowed, Null if none * * @return float|null The minimal value allowed, Null if none */ public function getMinAllowedValue (): ?float { return $this->minAllowedValue; } /** * Set the minimal value allowed * * @param float|null $minAllowedValue The minimal value allowed, Null if none * * @return $this */ public function setMinAllowedValue (?float $minAllowedValue): self { if ($minAllowedValue !== null && $this->getMaxAllowedValue() !== null && $minAllowedValue > $this->getMaxAllowedValue()) { throw new InvalidArgumentException('The minimal allowed value must be null or lesser than the maximal allowed value'); } $this->minAllowedValue = $minAllowedValue; return $this; } /** * The maximal value allowed, Null if none * * @return float|null The maximal value allowed, Null if none */ public function getMaxAllowedValue (): ?float { return $this->maxAllowedValue; } /** * Set the maximal value allowed * * @param float|null $maxAllowedValue The maximal value allowed, Null if none * * @return $this */ public function setMaxAllowedValue (?float $maxAllowedValue): self { if ($maxAllowedValue !== null && $this->getMinAllowedValue() !== null && $maxAllowedValue < $this->getMinAllowedValue()) { throw new InvalidArgumentException('The maximal allowed value must be null or greater than the minimal allowed value'); } $this->maxAllowedValue = $maxAllowedValue; return $this; } }