You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
236 lines
8.4 KiB
PHP
236 lines
8.4 KiB
PHP
<?php
|
|
|
|
namespace jrosset\EnvReader;
|
|
|
|
use DateTime;
|
|
use DateTimeInterface;
|
|
use Exception;
|
|
use jrosset\ArrayClasses\IArrayCast;
|
|
use jrosset\ArrayClasses\ImmutableInsensitiveCaseArrayClass;
|
|
use jrosset\ArrayClasses\InsensitiveCaseArrayClass;
|
|
use jrosset\Singleton\TSingleton;
|
|
use RangeException;
|
|
use UnexpectedValueException;
|
|
|
|
/**
|
|
* A generic configuration class
|
|
*
|
|
* Overwrite {@see GenericConfig::initialProperties()} to set initial properties
|
|
*/
|
|
abstract class GenericConfig {
|
|
use TSingleton;
|
|
|
|
/**
|
|
* @var InsensitiveCaseArrayClass Current properties
|
|
*/
|
|
protected InsensitiveCaseArrayClass $properties;
|
|
|
|
/**
|
|
* Initialize initial properties then read ENV file
|
|
*
|
|
* @throws Exception If ENV can't be read
|
|
*/
|
|
protected function __construct () {
|
|
$this->properties = new InsensitiveCaseArrayClass($this->initialProperties());
|
|
$this->readConfig();
|
|
}
|
|
|
|
/**
|
|
* Initial properties
|
|
*
|
|
* @return string[]|IArrayCast Initial properties
|
|
*
|
|
* @noinspection PhpReturnDocTypeMismatchInspection
|
|
*/
|
|
protected function initialProperties () {
|
|
return [];
|
|
}
|
|
/**
|
|
* Read the configuration file
|
|
*
|
|
* @return void
|
|
*
|
|
* @throws Exception If the configuration file is invalid
|
|
*/
|
|
protected abstract function readConfig (): void;
|
|
|
|
/**
|
|
* Get all properties
|
|
*
|
|
* @return ImmutableInsensitiveCaseArrayClass Get all properties (properties' name are in upper case)
|
|
*/
|
|
public function getProperties (): ImmutableInsensitiveCaseArrayClass {
|
|
return $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->has($name);
|
|
}
|
|
/**
|
|
* 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
|
|
*
|
|
* @return mixed The property value
|
|
*
|
|
* @throws UnexpectedValueException If property is not set AND $default is Null
|
|
*/
|
|
public function getProperty (string $name, $default = null) {
|
|
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 {
|
|
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
|
|
* 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*(?<value>[0-9]+)\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*(?<value>[0-9]+(?:\.[0-9]+)?)\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 <b>must</b> 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 === null ? null : $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 : ' . $value);
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
} |