D7net
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
psa
/
admin
/
plib
/
vendor
/
laminas
/
laminas-validator
/
src
/
Filename :
DateComparison.php
back
Copy
<?php declare(strict_types=1); namespace Laminas\Validator; use DateTimeImmutable; use DateTimeInterface; use DateTimeZone; use Laminas\Validator\Exception\InvalidArgumentException; use function assert; use function get_debug_type; use function is_string; use function preg_match; /** * @psalm-type OptionsArgument = array{ * min?: string|DateTimeInterface|null, * max?: string|DateTimeInterface|null, * inclusiveMin?: bool, * inclusiveMax?: bool, * inputFormat?: string|null, * } */ final class DateComparison extends AbstractValidator { public const ERROR_INVALID_TYPE = 'invalidType'; public const ERROR_INVALID_DATE = 'invalidDate'; public const ERROR_NOT_GREATER_INCLUSIVE = 'notGreaterInclusive'; public const ERROR_NOT_GREATER = 'notGreater'; public const ERROR_NOT_LESS_INCLUSIVE = 'notLessInclusive'; public const ERROR_NOT_LESS = 'notLess'; /** @var array<string, string> */ protected array $messageTemplates = [ self::ERROR_INVALID_TYPE => 'Expected a string or a date time instance but received "%type"', self::ERROR_INVALID_DATE => 'Invalid date provided', self::ERROR_NOT_GREATER_INCLUSIVE => 'A date equal to or after %min% is required', self::ERROR_NOT_GREATER => 'A date after %min% is required', self::ERROR_NOT_LESS_INCLUSIVE => 'A date equal to or before %max% is required', self::ERROR_NOT_LESS => 'A date before %max% is required', ]; /** @var array<string, string> */ protected array $messageVariables = [ 'type' => 'type', 'min' => 'minString', 'max' => 'maxString', ]; private readonly ?DateTimeInterface $min; private readonly ?DateTimeInterface $max; private readonly bool $inclusiveMin; private readonly bool $inclusiveMax; private readonly ?string $inputFormat; /** Input type used in message variables */ protected ?string $type = null; protected ?string $minString = null; protected ?string $maxString = null; /** @param OptionsArgument $options */ public function __construct(array $options = []) { parent::__construct($options); $this->min = $this->dateInstanceBound($options['min'] ?? null); $this->max = $this->dateInstanceBound($options['max'] ?? null); $this->inclusiveMin = $options['inclusiveMin'] ?? true; $this->inclusiveMax = $options['inclusiveMax'] ?? true; $this->inputFormat = $options['inputFormat'] ?? null; if ($this->min === null && $this->max === null) { throw new InvalidArgumentException( 'At least one date boundary must be supplied', ); } $outputFormat = $this->inputFormat ?? 'jS F Y H:i:s'; if ($this->min !== null) { $this->minString = $this->min->format($outputFormat); } if ($this->max !== null) { $this->maxString = $this->max->format($outputFormat); } } public function isValid(mixed $value): bool { $this->type = get_debug_type($value); $this->value = $value; if (! is_string($value) && ! $value instanceof DateTimeInterface) { $this->error(self::ERROR_INVALID_TYPE); return false; } $date = $this->valueToDate($value); if ($date === null) { $this->error(self::ERROR_INVALID_DATE); return false; } if ($this->min !== null && $this->inclusiveMin && $date < $this->min) { $this->error(self::ERROR_NOT_GREATER_INCLUSIVE); return false; } if ($this->min !== null && ! $this->inclusiveMin && $date <= $this->min) { $this->error(self::ERROR_NOT_GREATER); return false; } if ($this->max !== null && $this->inclusiveMax && $date > $this->max) { $this->error(self::ERROR_NOT_LESS_INCLUSIVE); return false; } if ($this->max !== null && ! $this->inclusiveMax && $date >= $this->max) { $this->error(self::ERROR_NOT_LESS); return false; } return true; } private function valueToDate(string|DateTimeInterface $input): DateTimeInterface|null { if ($input instanceof DateTimeInterface) { return $this->w3cDateFromString($input->format('Y-m-d\TH:i:s')); } if ($this->inputFormat !== null) { $date = DateTimeImmutable::createFromFormat($this->inputFormat, $input, new DateTimeZone('UTC')); if ($date instanceof DateTimeImmutable) { return $date; } } $date = $this->isoDateFromString($input); if ($date !== null) { return $date; } $date = $this->w3cDateFromString($input); if ($date !== null) { return $date; } return null; } private function dateInstanceBound(string|DateTimeInterface|null $dateTime): DateTimeInterface|null { if ($dateTime instanceof DateTimeInterface) { return $this->w3cDateFromString($dateTime->format('Y-m-d\TH:i:s')); } if ($dateTime === null) { return null; } $date = $this->isoDateFromString($dateTime); if ($date !== null) { return $date; } $date = $this->w3cDateFromString($dateTime); if ($date !== null) { return $date; } throw new InvalidArgumentException( 'Min/max date bounds must be either DateTime instances, or a string in one of the formats: ' . '"Y-m-d" for a date or "Y-m-d\TH:i:s" for date time', ); } private function isoDateFromString(string $input): DateTimeImmutable|null { if (! preg_match('/^\d{4}-[0-1]\d-[0-3]\d$/', $input)) { return null; } $date = DateTimeImmutable::createFromFormat('!Y-m-d', $input, new DateTimeZone('UTC')); assert($date !== false); return $date; } private function w3cDateFromString(string $input): DateTimeImmutable|null { if (! preg_match('/^\d{4}-[0-1]\d-[0-3]\dT\d{1,2}:[0-5]\d:[0-5]\d$/', $input)) { return null; } $date = DateTimeImmutable::createFromFormat('Y-m-d\TH:i:s', $input, new DateTimeZone('UTC')); assert($date !== false); return $date; } }