|
|
|
@ -5,18 +5,13 @@ namespace jrosset\EnvReader;
|
|
|
|
|
use DateTime;
|
|
|
|
|
use DateTimeInterface;
|
|
|
|
|
use Exception;
|
|
|
|
|
use InvalidArgumentException;
|
|
|
|
|
use jrosset\Collections\IArrayCast;
|
|
|
|
|
use jrosset\Collections\InsensitiveCaseKeyCollection;
|
|
|
|
|
use jrosset\Collections\InsensitiveCaseKeyImmutableCollection;
|
|
|
|
|
use jrosset\Singleton\ISingleton;
|
|
|
|
|
use jrosset\Singleton\TSingleton;
|
|
|
|
|
use RangeException;
|
|
|
|
|
use ReflectionEnum;
|
|
|
|
|
use ReflectionEnumBackedCase;
|
|
|
|
|
use ReflectionException;
|
|
|
|
|
use UnexpectedValueException;
|
|
|
|
|
use UnitEnum;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A generic configuration class
|
|
|
|
@ -45,8 +40,10 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
* Initial properties
|
|
|
|
|
*
|
|
|
|
|
* @return string[]|IArrayCast Initial properties
|
|
|
|
|
*
|
|
|
|
|
* @noinspection PhpReturnDocTypeMismatchInspection
|
|
|
|
|
*/
|
|
|
|
|
protected function initialProperties (): array|IArrayCast {
|
|
|
|
|
protected function initialProperties () {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
@ -79,15 +76,15 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
/**
|
|
|
|
|
* Get a property value
|
|
|
|
|
*
|
|
|
|
|
* @param string $name The property name
|
|
|
|
|
* @param mixed|null $default The default value if property is not set
|
|
|
|
|
* <br>Raise an exception if property is not set AND $default is Null
|
|
|
|
|
* @param string $name The property name
|
|
|
|
|
* @param mixed $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 {
|
|
|
|
|
public function getProperty (string $name, $default = null) {
|
|
|
|
|
if (!$this->hasProperty($name)) {
|
|
|
|
|
if ($default === null) {
|
|
|
|
|
throw new UnexpectedValueException('The "' . $name . '" property is not set');
|
|
|
|
@ -103,7 +100,7 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
*
|
|
|
|
|
* @param string $name The property name
|
|
|
|
|
* @param string|null $default The default value if property is not set
|
|
|
|
|
* <br>Raise an exception if property is not set AND $default is Null
|
|
|
|
|
* Raise an exception if property is not set AND $default is Null
|
|
|
|
|
*
|
|
|
|
|
* @return string The property value
|
|
|
|
|
*
|
|
|
|
@ -125,7 +122,7 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
*
|
|
|
|
|
* @param string $name The property name
|
|
|
|
|
* @param bool|null $default The default value if property is not set
|
|
|
|
|
* <br>Raise an exception if property is not set AND $default is Null
|
|
|
|
|
* Raise an exception if property is not set AND $default is Null
|
|
|
|
|
*
|
|
|
|
|
* @return bool The property value
|
|
|
|
|
*
|
|
|
|
@ -135,18 +132,25 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
* @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),
|
|
|
|
|
};
|
|
|
|
|
switch ($value = $this->getProperty($name, $default === null ? null : ($default === true ? '1' : '0'))) {
|
|
|
|
|
case '1':
|
|
|
|
|
case 'true':
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
case '0':
|
|
|
|
|
case 'false':
|
|
|
|
|
return 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
|
|
|
|
|
* <br>Raise an exception if property is not set AND $default is Null
|
|
|
|
|
* Raise an exception if property is not set AND $default is Null
|
|
|
|
|
*
|
|
|
|
|
* @return int The property value
|
|
|
|
|
*
|
|
|
|
@ -167,7 +171,7 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
*
|
|
|
|
|
* @param string $name The property name
|
|
|
|
|
* @param float|null $default The default value if property is not set
|
|
|
|
|
* <br>Raise an exception if property is not set AND $default is Null
|
|
|
|
|
* Raise an exception if property is not set AND $default is Null
|
|
|
|
|
*
|
|
|
|
|
* @return float The property value
|
|
|
|
|
*
|
|
|
|
@ -190,7 +194,7 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
*
|
|
|
|
|
* @param string $name The property name
|
|
|
|
|
* @param DateTime|null $default The default value if property is not set
|
|
|
|
|
* <br>Raise an exception if property is not set AND $default is Null
|
|
|
|
|
* Raise an exception if property is not set AND $default is Null
|
|
|
|
|
*
|
|
|
|
|
* @return DateTime The property value
|
|
|
|
|
*
|
|
|
|
@ -202,7 +206,7 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
public function getPropertyAsDateTime (string $name, ?DateTime $default = null): DateTime {
|
|
|
|
|
$value = DateTime::createFromFormat(
|
|
|
|
|
DateTimeInterface::RFC3339,
|
|
|
|
|
$this->getProperty($name, $default?->format(DateTimeInterface::RFC3339))
|
|
|
|
|
$this->getProperty($name, $default === null ? null : $default->format(DateTimeInterface::RFC3339))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
$errors = DateTime::getLastErrors();
|
|
|
|
@ -230,60 +234,4 @@ abstract class GenericConfig implements ISingleton {
|
|
|
|
|
|
|
|
|
|
return $value;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* Get a property value as an enum
|
|
|
|
|
*
|
|
|
|
|
* @param string $name The property name
|
|
|
|
|
* @param class-string<UnitEnum> $enumClass The enum class name
|
|
|
|
|
* @param UnitEnum|null $default The default value if property is not set
|
|
|
|
|
* <br>Raise an exception if not <b>$enumClass</b> enum
|
|
|
|
|
* <br>Raise an exception if property is not set AND $default is Null
|
|
|
|
|
* <br>Raise an exception if property is set but not valid (not an enum)
|
|
|
|
|
*
|
|
|
|
|
* @return UnitEnum The enum
|
|
|
|
|
*
|
|
|
|
|
* @throws ReflectionException If <b>$enumClass</b> is not a valid enum class
|
|
|
|
|
* @throws InvalidArgumentException If <b>$default</b> is not a <b>$enumClass</b> 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
|
|
|
|
|
}
|
|
|
|
|
}
|