"mysql", "name" => "mysql:host=authdb;dbname=auth;charset=utf8", * "user" => "auth_int", "pass" => "auth" ] * situé au chemin de clé dbs.auth dans le profil prod, on peut par exemple * définir les variables suivantes: * CONFIG_prod_dbs__auth__type="mysql" * CONFIG_prod_dbs__auth__name="mysql:host=authdb;dbname=auth;charset=utf8" * CONFIG_prod_dbs__auth__user="auth_int" * CONFIG_prod_dbs__auth__pass="auth" * ou alternativement: * JSON_CONFIG_prod_dbs__auth='{"type":"mysql","name":"mysql:host=authdb;dbname=auth;charset=utf8","user":"auth_int","pass":"auth"}' * * Les préfixes supportés sont, dans l'ordre de précédence: * - JSON_FILE_CONFIG -- une valeur au format JSON inscrite dans un fichier * - JSON_CONFIG -- une valeur au format JSON * - FILE_CONFIG -- une valeur inscrite dans un fichier * - CONFIG -- une valeur scalaire */ class EnvConfig extends DynConfig { /** @var array */ protected $config; /** analyser $name et retourner [$pkey, $profile] */ private static function parse_pkey_profile($name): array { $i = strpos($name, "_"); if ($i === false) return [false, false]; $profile = substr($name, 0, $i); $name = substr($name, $i + 1); $pkey = str_replace("__", ".", $name); $pkey = str_replace("_", "-", $pkey); return [$pkey, $profile]; } private static function invalid_json_data(string $pkey, string $profile, ?string $prefix, ?Throwable $e): ConfigException { if ($prefix !== null) $prefix = "$prefix: "; return new ConfigException("${prefix}invalid json data for $profile:$pkey", 0, $e); } /** charger la configuration depuis l'environnement */ protected function ensureConfigLoaded() { if ($this->config !== null) return; $config = []; $json_files = []; $jsons = []; $files = []; $vars = []; foreach (getenv() as $name => $value) { if (str::starts_with("JSON_FILE_CONFIG_", $name)) { $json_files[str::without_prefix("JSON_FILE_CONFIG_", $name)] = $value; } elseif (str::starts_with("JSON_CONFIG_", $name)) { $jsons[str::without_prefix("JSON_CONFIG_", $name)] = $value; } elseif (str::starts_with("FILE_CONFIG_", $name)) { $files[str::without_prefix("FILE_CONFIG_", $name)] = $value; } elseif (str::starts_with("CONFIG_", $name)) { $vars[str::without_prefix("CONFIG_", $name)] = $value; } } foreach ($json_files as $name => $file) { [$pkey, $profile] = self::parse_pkey_profile($name); $data = file_get_contents($file); if ($data === false) { throw new ConfigException("$file: unable to read json file for $profile:$pkey"); } try { $value = json_decode($data, true, 512, JSON_THROW_ON_ERROR); } catch (Exception $e) { throw self::invalid_json_data($pkey, $profile, $file, $e); } A::pset($config, "$profile.$pkey", $value); } foreach ($jsons as $name => $data) { [$pkey, $profile] = self::parse_pkey_profile($name); try { $value = json_decode($data, true, 512, JSON_THROW_ON_ERROR); } catch (Exception $e) { throw self::invalid_json_data($pkey, $profile, null, $e); } A::pset($config, "$profile.$pkey", $value); } foreach ($files as $name => $file) { [$pkey, $profile] = self::parse_pkey_profile($name); $value = file_get_contents($file); if ($value === false) { throw new ConfigException("$file: unable to read file for $profile:$pkey"); } A::pset($config, "$profile.$pkey", $value); } foreach ($vars as $name => $value) { [$pkey, $profile] = self::parse_pkey_profile($name); A::pset($config, "$profile.$pkey", $value); } $this->config = $config; } function has(string $pkey, string $profile): bool { $this->ensureConfigLoaded(); return A::phas($this->config, "$profile.$pkey"); } function get(string $pkey, string $profile) { $this->ensureConfigLoaded(); return A::pget($this->config, "$profile.$pkey"); } function set(string $pkey, $value, string $profile): void { $this->ensureConfigLoaded(); A::pset($this->config, "$profile.$pkey", $value); } }