properties = new InsensitiveCaseKeyCollection($this->initialProperties()); $this->readConfig(); } /** * Initial properties * * @return string[]|IArrayCast Initial properties */ protected function initialProperties (): array|IArrayCast { return []; } /** * Read the configuration file * * @return void * * @throws Exception If the configuration file is invalid */ protected abstract function readConfig (): void; /** * Get all properties * * @return InsensitiveCaseKeyImmutableCollection Get all properties (properties' name are in upper case) */ public function getProperties (): InsensitiveCaseKeyImmutableCollection { return new InsensitiveCaseKeyImmutableCollection($this->properties); } /** * Check if a property id defined * * @param string $name The property name * * @return bool Is the property defined ? */ public function hasProperty (string $name): bool { return $this->properties->exists($name); } /** * Get a property value * * @param string $name The property name * @param mixed|null $default The default value if property is not set *
Raise an exception if property is not set AND $default is Null * * @return mixed The property value * * @throws UnexpectedValueException If property is not set AND $default is Null */ public function getProperty (string $name, mixed $default = null): mixed { if (!$this->hasProperty($name)) { if ($default === null) { throw new UnexpectedValueException('The "' . $name . '" property is not set'); } return $default; } return $this->properties->get($name); } /** * Get a property value as a string * * @param string $name The property name * @param string|null $default The default value if property is not set *
Raise an exception if property is not set AND $default is Null * * @return string The property value * * @throws UnexpectedValueException If property is not set AND $default is Null * @throws RangeException If the property can't be cast to a boolean * * @noinspection PhpUnused */ public function getPropertyAsString (string $name, ?string $default = null): string { $value = $this->getProperty($name, $default); if (!is_string($value) && !is_object($value) && !method_exists($value, '__ToString')) { throw new RangeException('The "' . $name . '" property is not a valid string : ' . $value); } return (string)$value; } /** * Get a property value as a boolean * * @param string $name The property name * @param bool|null $default The default value if property is not set *
Raise an exception if property is not set AND $default is Null * * @return bool The property value * * @throws UnexpectedValueException If property is not set AND $default is Null * @throws RangeException If the property can't be cast to a boolean * * @noinspection PhpUnused */ public function getPropertyAsBool (string $name, ?bool $default = null): bool { return match ($value = $this->getProperty($name, $default === null ? null : ($default === true ? '1' : '0'))) { '1', 'true' => true, '0', 'false' => false, default => throw new RangeException('The "' . $name . '" property is not a valid boolean : ' . $value), }; } /** * Get a property value as an integer * * @param string $name The property name * @param int|null $default The default value if property is not set *
Raise an exception if property is not set AND $default is Null * * @return int The property value * * @throws UnexpectedValueException If property is not set AND $default is Null * @throws RangeException If the property can't be cast to an integer * * @noinspection PhpUnused */ public function getPropertyAsInt (string $name, ?int $default = null): int { $value = $this->getProperty($name, $default === null ? null : (string)$default); if (preg_match('#^\s*(?\d+)\s*$#', $value, $match) !== 1) { throw new RangeException('The "' . $name . '" property is not a valid integer : ' . $value); } return (int)$match['value']; } /** * Get a property value as a float value (the decimal separator is dot) * * @param string $name The property name * @param float|null $default The default value if property is not set *
Raise an exception if property is not set AND $default is Null * * @return float The property value * * @throws UnexpectedValueException If property is not set AND $default is Null * @throws RangeException If the property can't be cast to a float value * * @noinspection PhpUnused */ public function getPropertyAsReal (string $name, ?float $default = null): float { $value = $this->getProperty($name, $default === null ? null : (string)$default); if (preg_match('#^\s*(?\d+(?:\.\d+)?)\s*$#', $value, $match) !== 1) { throw new RangeException('The "' . $name . '" property is not a valid float value : ' . $value); } return (float)$match['value']; } /** * Get a property value as a date and time ({@link https://www.php.net/manual/book.datetime.php DateTime}) * * The date must respect {@link https://datatracker.ietf.org/doc/html/rfc3339 RFC339} norm * * @param string $name The property name * @param DateTime|null $default The default value if property is not set *
Raise an exception if property is not set AND $default is Null * * @return DateTime The property value * * @throws UnexpectedValueException If property is not set AND $default is Null * @throws RangeException If the property can't be cast to a date and time * * @noinspection PhpUnused */ public function getPropertyAsDateTime (string $name, ?DateTime $default = null): DateTime { $value = DateTime::createFromFormat( DateTimeInterface::RFC3339, $this->getProperty($name, $default?->format(DateTimeInterface::RFC3339)) ); $errors = DateTime::getLastErrors(); if ($errors !== false) { $messages = []; if (($nb_error = $errors['error_count']) > 0) { foreach ($errors['errors'] as $idx => $error) { $messages[] = 'ERREUR #' . $idx . ' : ' . $error; } } if (($nb_warning = $errors['warning_count']) > 0) { foreach ($errors['warnings'] as $idx => $warning) { $messages[] = 'ALERTE #' . $idx . ' : ' . $warning; } } if ($nb_error + $nb_warning > 0) { throw new RangeException('The "' . $name . '" property is not a valid date and time : ' . $value . "\n\n" . implode("\n", $messages)); } } if ($value === false) { throw new RangeException('The "' . $name . '" property is not a valid date and time'); } return $value; } /** * Get a property value as an enum * * @param string $name The property name * @param class-string $enumClass The enum class name * @param UnitEnum|null $default The default value if property is not set *
Raise an exception if not $enumClass enum *
Raise an exception if property is not set AND $default is Null *
Raise an exception if property is set but not valid (not an enum) * * @return UnitEnum The enum * * @throws ReflectionException If $enumClass is not a valid enum class * @throws InvalidArgumentException If $default is not a $enumClass enum */ public function getPropertyAsEnum (string $name, string $enumClass, ?UnitEnum $default = null): UnitEnum { $enumReflection = new ReflectionEnum($enumClass); //region Check default value type if ($default !== null && !$default instanceof $enumClass) { throw new InvalidArgumentException('The default property type must be an ' . $enumClass); } //endregion //region Return default value (or raise exception) if property is not set if (!$this->hasProperty($name)) { if ($default === null) { throw new UnexpectedValueException('The "' . $name . '" property is not set'); } return $default; } //endregion //region Try to find the enum through a case name $propertyValue = $this->getPropertyAsString($name); if ($enumReflection->hasCase($propertyValue)) { return $enumReflection->getCase($propertyValue)->getValue(); } //endregion //region Try to find enum through the value (if BackedEnum) if ($enumReflection->isBacked()) { if (((string)$enumReflection->getBackingType()) === 'int') { $propertyValue = $this->getPropertyAsInt($name); } /** @var ReflectionEnumBackedCase $enumBackedCase */ foreach ($enumReflection->getCases() as $enumBackedCase) { if ($enumBackedCase->getBackingValue() === $propertyValue) { return $enumBackedCase->getValue(); } } } //endregion //region Unable to find valid enum → raise exception throw new UnexpectedValueException('The "' . $name . '" property is not a valid enum ' . $enumClass); //endregion } }