diff --git a/composer.json b/composer.json
index 504609a..01efdb1 100644
--- a/composer.json
+++ b/composer.json
@@ -9,15 +9,15 @@
},
"extra": {
"branch-alias": {
- "dev-master": "2.x-dev"
+ "dev-master": "3.x-dev"
}
},
"minimum-stability": "stable",
"require": {
- "php": "^7.4 || ^8.0",
- "jrosset/singleton": "^1.5",
- "jrosset/collections": "^2.3 || ^3.0"
+ "php": "^8.1",
+ "jrosset/singleton": "^2.0",
+ "jrosset/collections": "^3.5"
},
"autoload": {
"psr-4": {
diff --git a/src/EnvReader/GenericConfig.php b/src/EnvReader/GenericConfig.php
index cc10bd5..209b63c 100644
--- a/src/EnvReader/GenericConfig.php
+++ b/src/EnvReader/GenericConfig.php
@@ -5,13 +5,18 @@ 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
@@ -40,10 +45,8 @@ abstract class GenericConfig implements ISingleton {
* Initial properties
*
* @return string[]|IArrayCast Initial properties
- *
- * @noinspection PhpReturnDocTypeMismatchInspection
*/
- protected function initialProperties () {
+ protected function initialProperties (): array|IArrayCast {
return [];
}
/**
@@ -76,15 +79,15 @@ abstract class GenericConfig implements ISingleton {
/**
* Get a property value
*
- * @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
+ * @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, $default = 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');
@@ -100,7 +103,7 @@ abstract class GenericConfig implements ISingleton {
*
* @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
+ *
Raise an exception if property is not set AND $default is Null
*
* @return string The property value
*
@@ -122,7 +125,7 @@ abstract class GenericConfig implements ISingleton {
*
* @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
+ *
Raise an exception if property is not set AND $default is Null
*
* @return bool The property value
*
@@ -132,25 +135,18 @@ abstract class GenericConfig implements ISingleton {
* @noinspection PhpUnused
*/
public function getPropertyAsBool (string $name, ?bool $default = null): bool {
- 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);
- }
+ 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
+ *
Raise an exception if property is not set AND $default is Null
*
* @return int The property value
*
@@ -171,7 +167,7 @@ abstract class GenericConfig implements ISingleton {
*
* @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
+ *
Raise an exception if property is not set AND $default is Null
*
* @return float The property value
*
@@ -194,7 +190,7 @@ abstract class GenericConfig implements ISingleton {
*
* @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
+ *
Raise an exception if property is not set AND $default is Null
*
* @return DateTime The property value
*
@@ -206,7 +202,7 @@ abstract class GenericConfig implements ISingleton {
public function getPropertyAsDateTime (string $name, ?DateTime $default = null): DateTime {
$value = DateTime::createFromFormat(
DateTimeInterface::RFC3339,
- $this->getProperty($name, $default === null ? null : $default->format(DateTimeInterface::RFC3339))
+ $this->getProperty($name, $default?->format(DateTimeInterface::RFC3339))
);
$errors = DateTime::getLastErrors();
@@ -234,4 +230,60 @@ abstract class GenericConfig implements ISingleton {
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
+ }
}
\ No newline at end of file
diff --git a/src/EnvReader/TMultiLevelProperties.php b/src/EnvReader/TMultiLevelProperties.php
index e284ed1..c43c293 100644
--- a/src/EnvReader/TMultiLevelProperties.php
+++ b/src/EnvReader/TMultiLevelProperties.php
@@ -43,14 +43,14 @@ trait TMultiLevelProperties {
* Get a property value
*
* @param string|string[]|IArrayCast $name The property name
- * @param mixed $default The default value if property is not set
+ * @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 ($name, $default = null) {
+ public function getProperty ($name, mixed $default = null) {
if (!$this->hasProperty($name)) {
if ($default === null) {
throw new UnexpectedValueException('The "' . $name . '" property is not set');
diff --git a/tests/.env b/tests/.env
index 53f4747..e382a12 100644
--- a/tests/.env
+++ b/tests/.env
@@ -2,4 +2,6 @@ WEBSITE_NAME="Foo Bar"
DB_NAME=Bar
DB_LOGIN=Bar
-DB_PASS=*****
\ No newline at end of file
+DB_PASS=*****
+
+TEST=Test2
\ No newline at end of file
diff --git a/tests/TestEnum.php b/tests/TestEnum.php
new file mode 100644
index 0000000..c87151d
--- /dev/null
+++ b/tests/TestEnum.php
@@ -0,0 +1,7 @@
+getProperties());
-var_dump(Env::getInstance()->getProperty('db_host', 'localhost'));
\ No newline at end of file
+var_dump(Env::getInstance()->getProperty('db_host', 'localhost'));
+var_dump(Env::getInstance()->getPropertyAsEnum('test', TestEnum::class, TestEnum::Test1));
\ No newline at end of file