chore: complete update
This commit is contained in:
18
src/Framework/Config/AppConfig.php
Normal file
18
src/Framework/Config/AppConfig.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Config;
|
||||
|
||||
use App\Framework\DateTime\Timezone;
|
||||
|
||||
final readonly class AppConfig
|
||||
{
|
||||
public function __construct(
|
||||
public string $name = 'Framework App',
|
||||
public string $version = '1.0.0',
|
||||
public string $environment = 'production',
|
||||
public bool $debug = false,
|
||||
public Timezone $timezone = Timezone::DEFAULT,
|
||||
public string $locale = 'en',
|
||||
public EnvironmentType $type = EnvironmentType::DEV
|
||||
) {}
|
||||
}
|
||||
117
src/Framework/Config/Configuration.php
Normal file
117
src/Framework/Config/Configuration.php
Normal file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Config;
|
||||
|
||||
class Configuration
|
||||
{
|
||||
private array $config = [];
|
||||
|
||||
/**
|
||||
* Lädt Konfigurationen aus einer oder mehreren Quellen
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
$this->config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt Konfigurationen aus PHP-Dateien
|
||||
*/
|
||||
public function loadFromFile(string $path): self
|
||||
{
|
||||
if (file_exists($path) && is_readable($path)) {
|
||||
$fileConfig = require $path;
|
||||
if (is_array($fileConfig)) {
|
||||
$this->config = array_merge($this->config, $fileConfig);
|
||||
}
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lädt Konfigurationen aus einem Verzeichnis
|
||||
*/
|
||||
public function loadFromDirectory(string $directory): self
|
||||
{
|
||||
if (!is_dir($directory)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
foreach (glob($directory . '/*.php') as $file) {
|
||||
$this->loadFromFile($file);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt einen Konfigurationswert zurück
|
||||
*/
|
||||
public function get(string $key, mixed $default = null): mixed
|
||||
{
|
||||
$keys = explode('.', $key);
|
||||
$value = $this->config;
|
||||
|
||||
foreach ($keys as $segment) {
|
||||
if (!is_array($value) || !array_key_exists($segment, $value)) {
|
||||
return $default;
|
||||
}
|
||||
$value = $value[$segment];
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setzt einen Konfigurationswert
|
||||
*/
|
||||
public function set(string $key, mixed $value): self
|
||||
{
|
||||
$keys = explode('.', $key);
|
||||
$config = &$this->config;
|
||||
|
||||
foreach ($keys as $i => $segment) {
|
||||
if ($i === count($keys) - 1) {
|
||||
$config[$segment] = $value;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isset($config[$segment]) || !is_array($config[$segment])) {
|
||||
$config[$segment] = [];
|
||||
}
|
||||
|
||||
$config = &$config[$segment];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prüft, ob ein Konfigurationswert existiert
|
||||
*/
|
||||
public function has(string $key): bool
|
||||
{
|
||||
$keys = explode('.', $key);
|
||||
$config = $this->config;
|
||||
|
||||
foreach ($keys as $segment) {
|
||||
if (!is_array($config) || !array_key_exists($segment, $config)) {
|
||||
return false;
|
||||
}
|
||||
$config = $config[$segment];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle Konfigurationswerte zurück
|
||||
*/
|
||||
public function all(): array
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
}
|
||||
11
src/Framework/Config/EnvKey.php
Normal file
11
src/Framework/Config/EnvKey.php
Normal file
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Config;
|
||||
|
||||
enum EnvKey: string
|
||||
{
|
||||
case APP_DEBUG = 'APP_DEBUG';
|
||||
case APP_ENV = 'APP_ENV';
|
||||
case APP_TIMEZONE = 'APP_TIMEZONE';
|
||||
case APP_LOCALE = 'APP_LOCALE';
|
||||
}
|
||||
143
src/Framework/Config/Environment.php
Normal file
143
src/Framework/Config/Environment.php
Normal file
@@ -0,0 +1,143 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Config;
|
||||
|
||||
use App\Framework\Config\Exceptions\RequiredEnvironmentVariableException;
|
||||
|
||||
final readonly class Environment
|
||||
{
|
||||
public function __construct(
|
||||
private array $variables = []
|
||||
){}
|
||||
|
||||
public function get(EnvKey|string $key, mixed $default = null): mixed
|
||||
{
|
||||
$key = $this->keyToString($key);
|
||||
// Priorität: 1. System ENV, 2. Loaded variables, 3. Default
|
||||
return $_ENV[$key] ?? $_SERVER[$key] ?? getenv($key) ?: $this->variables[$key] ?? $default;
|
||||
}
|
||||
|
||||
public function getRequired(EnvKey|string $key): mixed
|
||||
{
|
||||
$key = $this->keyToString($key);
|
||||
$value = $this->get($key);
|
||||
if ($value === null) {
|
||||
throw new RequiredEnvironmentVariableException($key);
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function getInt(EnvKey|string $key, int $default = 0): int
|
||||
{
|
||||
$key = $this->keyToString($key);
|
||||
return (int) $this->get($key, $default);
|
||||
}
|
||||
|
||||
public function getBool(EnvKey|string $key, bool $default = false): bool
|
||||
{
|
||||
$key = $this->keyToString($key);
|
||||
$value = $this->get($key, $default);
|
||||
if (is_string($value)) {
|
||||
return match (strtolower($value)) {
|
||||
'true', '1', 'yes', 'on' => true,
|
||||
'false', '0', 'no', 'off' => false,
|
||||
default => $default
|
||||
};
|
||||
}
|
||||
return (bool) $value;
|
||||
}
|
||||
|
||||
public function getString(EnvKey|string $key, string $default = ''): string
|
||||
{
|
||||
$key = $this->keyToString($key);
|
||||
return (string) $this->get($key, $default);
|
||||
}
|
||||
|
||||
public function getEnum(EnvKey|string $key, string $enumClass, \BackedEnum $default):object
|
||||
{
|
||||
$key = $this->keyToString($key);
|
||||
return forward_static_call([$enumClass, 'tryFrom'], $this->get($key, $default));
|
||||
#$enumClass::tryFrom($this->get($key, $default));
|
||||
}
|
||||
|
||||
public function has(EnvKey|string $key): bool
|
||||
{
|
||||
$key = $this->keyToString($key);
|
||||
return $this->get($key) !== null;
|
||||
}
|
||||
|
||||
public function all(): array
|
||||
{
|
||||
return array_merge(
|
||||
$_ENV,
|
||||
$_SERVER,
|
||||
$this->variables
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method für .env file loading
|
||||
*/
|
||||
public static function fromFile(string $envPath): self
|
||||
{
|
||||
$variables = [];
|
||||
|
||||
if (file_exists($envPath) && is_readable($envPath)) {
|
||||
$lines = file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
|
||||
foreach ($lines as $line) {
|
||||
if (str_starts_with(trim($line), '#') || !str_contains($line, '=')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
[$name, $value] = explode('=', $line, 2);
|
||||
$name = trim($name);
|
||||
$value = trim($value);
|
||||
|
||||
// Remove quotes
|
||||
if (str_starts_with($value, '"') && str_ends_with($value, '"')) {
|
||||
$value = substr($value, 1, -1);
|
||||
}
|
||||
|
||||
$variables[$name] = self::castValue($value);
|
||||
}
|
||||
}
|
||||
|
||||
return new self($variables);
|
||||
}
|
||||
|
||||
private static function castValue(string $value): mixed
|
||||
{
|
||||
return match (strtolower($value)) {
|
||||
'true' => true,
|
||||
'false' => false,
|
||||
'null' => null,
|
||||
default => is_numeric($value) ? (str_contains($value, '.') ? (float) $value : (int) $value) : $value
|
||||
};
|
||||
}
|
||||
|
||||
public function keyToString(EnvKey|string $key):string
|
||||
{
|
||||
if(is_string($key)) {
|
||||
return $key;
|
||||
}
|
||||
return $key->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Für Tests
|
||||
*/
|
||||
public function withVariable(string $key, mixed $value): self
|
||||
{
|
||||
$variables = $this->variables;
|
||||
$variables[$key] = $value;
|
||||
return new self($variables);
|
||||
}
|
||||
|
||||
public function withVariables(array $variables): self
|
||||
{
|
||||
return new self(array_merge($this->variables, $variables));
|
||||
}
|
||||
}
|
||||
9
src/Framework/Config/EnvironmentType.php
Normal file
9
src/Framework/Config/EnvironmentType.php
Normal file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Config;
|
||||
|
||||
enum EnvironmentType: string
|
||||
{
|
||||
case DEV = 'development';
|
||||
case PROD = 'production';
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Config\Exceptions;
|
||||
|
||||
use App\Framework\Exception\FrameworkException;
|
||||
|
||||
class RequiredEnvironmentVariableException extends FrameworkException
|
||||
{
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*/
|
||||
public function __construct(string $key)
|
||||
{
|
||||
parent::__construct("Required environment variable '$key' is not set.");
|
||||
}
|
||||
}
|
||||
47
src/Framework/Config/TypedConfigInitializer.php
Normal file
47
src/Framework/Config/TypedConfigInitializer.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Config;
|
||||
|
||||
use App\Framework\Context\ContextType;
|
||||
use App\Framework\DateTime\Timezone;
|
||||
use App\Framework\DI\Container;
|
||||
|
||||
final readonly class TypedConfigInitializer
|
||||
{
|
||||
public function __construct(
|
||||
private Environment $env,
|
||||
){
|
||||
#debug($env->getEnum('APP_ENV', EnvironmentType::class, EnvironmentType::PROD));
|
||||
}
|
||||
|
||||
public function __invoke(Container $container): TypedConfiguration
|
||||
{
|
||||
$appConfig = $this->createAppConfig();
|
||||
|
||||
$container->instance(AppConfig::class, $appConfig);
|
||||
|
||||
return new TypedConfiguration(
|
||||
app: $appConfig,
|
||||
);
|
||||
}
|
||||
|
||||
private function createAppConfig(): AppConfig
|
||||
{
|
||||
return new AppConfig(
|
||||
environment: $this->env->getString(
|
||||
key: EnvKey::APP_ENV,
|
||||
default: 'production'
|
||||
),
|
||||
|
||||
debug: $this->env->getBool(EnvKey::APP_DEBUG),
|
||||
|
||||
timezone: $this->env->getEnum(
|
||||
key: EnvKey::APP_TIMEZONE,
|
||||
enumClass: Timezone::class,
|
||||
default: Timezone::EuropeBerlin
|
||||
),
|
||||
|
||||
locale: $this->env->getString(EnvKey::APP_LOCALE, 'de'),
|
||||
);
|
||||
}
|
||||
}
|
||||
15
src/Framework/Config/TypedConfiguration.php
Normal file
15
src/Framework/Config/TypedConfiguration.php
Normal file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace App\Framework\Config;
|
||||
|
||||
use App\Framework\Database\Config\DatabaseConfig;
|
||||
|
||||
final readonly class TypedConfiguration
|
||||
{
|
||||
public function __construct(
|
||||
#public DatabaseConfig $database,
|
||||
public AppConfig $app,
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user