File modules/configuration/ConfigurationLoader.class.php

Last commit: Sat Jun 25 00:29:01 2022 +0200	Jan Dankert	Documentation...
1 <?php 2 3 namespace configuration; 4 5 use util\text\variables\VariableResolver; 6 use util\YAML; 7 8 9 /** 10 * Configuration Loader. 11 * 12 * Loades the configuration values from a YAML file. 13 * 14 * @author Jan Dankert 15 */ 16 class ConfigurationLoader 17 { 18 public $configFile; 19 20 21 /** 22 */ 23 public function __construct($configFile) 24 { 25 $this->configFile = $configFile; 26 } 27 28 29 /** 30 * Gets the last timestamp from the configuration file. 31 * 32 * @return int timestamp of last change as unix-timestamp 33 */ 34 public function lastModificationTime() 35 { 36 return filemtime($this->configFile); 37 } 38 39 40 /** 41 * Loads the custom configuration file. 42 * 43 * @return array Configuration 44 */ 45 public function load() 46 { 47 $customConfig = ConfigurationLoader::loadCustomConfig($this->configFile); 48 49 // Den Dateinamen der Konfigurationsdatei in die Konfiguration schreiben. 50 $customConfig['config']['filename'] = $this->configFile; 51 $customConfig['config']['last_modification_time'] = filemtime($this->configFile); 52 $customConfig['config']['last_modification'] = date('r', filemtime($this->configFile)); 53 $customConfig['config']['read'] = date('r'); 54 55 return $customConfig; 56 } 57 58 59 /** 60 * Loads the configuration file and resolves all include-commands. 61 * 62 * @return array Configuration 63 */ 64 private function loadCustomConfig($configFile) 65 { 66 if (!is_file($configFile) && !is_link($configFile)) { 67 error_log('Warning: Configuration file ' . $configFile . ' not found'); 68 return array(); 69 } 70 71 // Parse the YAML config to a hierarchical array 72 $customConfig = YAML::parse(file_get_contents($configFile)); 73 74 // resolve variables 75 $customConfig = self::resolveVariables($customConfig); 76 77 // enrich with environment variables 78 $customConfig = self::enrichEnvironmentVariables($customConfig, getenv('CMS_CONFIG_PREFIX')?:'CMS'); 79 80 // Does we have includes? 81 if (isset($customConfig['include'])) { 82 83 // 'include' must be an array 84 if (is_string($customConfig['include'])) 85 $customConfig['include'] = array($customConfig['include']); 86 87 // Load include files. 88 foreach ($customConfig['include'] as $key => $file) { 89 90 if ($file[0] == '/') // File begins with '?' 91 ; // File has an absolute path - do not change. 92 else 93 // Prepend file path with our config directory. 94 $file = __DIR__ . '/../../config/' . $file; 95 96 if (substr($file, -4) == '.yml' || 97 substr($file, -5) == '.yaml' || 98 substr($file, -8) == '.yml.php') 99 $customConfig = array_replace_recursive($customConfig, self::loadCustomConfig($file)); 100 else 101 error_log('Warning: ' . $file . ' is no .yml file - not loaded'); 102 103 } 104 } 105 106 return $customConfig; 107 } 108 109 /** 110 * Evaluates variables in a config array. 111 * Examples: 112 * - config-${http:host}.yml => config-yourdomain.yml 113 * - config-${server:http-host}.yml => config-yourdomain.yml 114 * - config-${env:myvar}.yml => config-myvalue.yml 115 * - config-${env:myxyz?default}.yml => config-default.yml 116 * @param $config array Configuration 117 * @return array 118 */ 119 private function resolveVariables($config) 120 { 121 $resolver = new VariableResolver(); 122 $resolver->namespaceSeparator = ':'; 123 $resolver->defaultSeparator = '?'; 124 125 $resolver->addResolver('env',function ($var) { 126 return getenv(strtoupper($var)); 127 }); 128 129 // http:... is a shortcut for server:http-... 130 $resolver->addResolver('http', function ($var) { 131 return @$_SERVER['HTTP_' . strtoupper($var)]; 132 }); 133 134 $resolver->addResolver('server',function ($var) { 135 return @$_SERVER[strtoupper($var)]; 136 }); 137 138 return $resolver->resolveVariablesInArray($config); 139 } 140 141 142 143 /** 144 * Walk through an array and search for pleasant environment variables. 145 * 146 * Example input: 147 * 148 * ['fruits' => 149 * [ 'red' => 'apple' ] 150 * ] 151 * 152 * would search for the environment variable "PREFIX_FRUITS_RED" and, 153 * if present, replaces the value "apple". 154 * 155 * @param $data array data array 156 * @param $prefix string|array prefix 157 * @return array 158 */ 159 private function enrichEnvironmentVariables($data, $prefix) 160 { 161 foreach ($data as $key=> $value ) { 162 163 $newKey = array_merge( (array)$prefix,[$key] ); 164 165 if ( is_array($value) ) { 166 $value = $this->enrichEnvironmentVariables($value,$newKey ); // recursive call 167 } else { 168 $environmentKey = strtoupper( implode('_',$newKey ) ); 169 170 // replace with value from environment 171 // if present, otherwise leave it untouched 172 $value = getenv( $environmentKey ) ?: $value; 173 174 // string-based boolean flags must be converted to real booleans 175 if ( in_array(strtolower($value),['true ','on' ]) ) 176 $value = true; 177 if ( in_array(strtolower($value),['false','off']) ) 178 $value = false; 179 } 180 181 $data[ $key ] = $value; 182 } 183 184 return $data; 185 } 186 187 } 188
Download modules/configuration/ConfigurationLoader.class.php
History Sat, 25 Jun 2022 00:29:01 +0200 Jan Dankert Documentation... Fri, 15 Apr 2022 21:36:28 +0200 dankert New: Configuration values may be overridden by environment variables. Fri, 15 Apr 2022 12:50:31 +0200 dankert Code cleanup... Wed, 13 May 2020 23:29:44 +0200 Jan Dankert Refactoring: New Variable Resolver with support for namespaces, default values and nested value expressions. Sun, 23 Feb 2020 00:38:18 +0100 Jan Dankert Refactoring: Namespaces for modules 'security' and 'configuration' Sat, 22 Feb 2020 23:58:02 +0100 Jan Dankert Refactoring: Namespacing for module 'util'. Thu, 21 Nov 2019 23:52:14 +0100 Jan Dankert New: VariableResolver in its own class. Keeps other code more tidy. Sat, 16 Nov 2019 00:46:46 +0100 Jan Dankert Fix: YAML-Parser should not load files. Fri, 15 Nov 2019 22:57:50 +0100 Jan Dankert Refactoring: Wrapping the Spyc YAML implementation. Mon, 11 Nov 2019 00:42:26 +0100 Jan Dankert Refactoring: Resolver config variables with a separate variable resolver. Mon, 20 May 2019 00:34:19 +0200 Jan Dankert Refactoring: Datenbankverbindung im Dispatcher erstellen. Bisher wurde in der Loginaction die DB-Verbindung aufgebaut, was dort falsch aufgehoben war. Wed, 12 Dec 2018 22:51:14 +0100 Jan Dankert Die Include-Konfigurationsdateien aus dem korrekten Ordner lesen. Das war bei API-Requests ein Problem. Tue, 23 Oct 2018 00:31:38 +0200 Jan Dankert Punkt-Notation ist in der YAML-Konfiguration nicht mehr möglich. Alle Konfigurationsdateien müssen umgestellt werden auf das echte YAML-Format. Thu, 6 Sep 2018 00:12:48 +0200 Jan Dankert array_replace_recursive passt hier besser, da es rekursiv funktioniert. Wed, 5 Sep 2018 23:51:21 +0200 Jan Dankert Um die Werte aus der config.yml überschreiben zu können, muss array_merge() benutzt werden. Tue, 4 Sep 2018 22:54:39 +0200 Jan Dankert Der Language-Loader ist jetzt nicht-statisch, damit die Initialisierung der Variablen im Konstruktur geschehen kann. Tue, 4 Sep 2018 22:39:36 +0200 Jan Dankert Der ConfigurationLoader bekommt die Konfigurationsdatei von außen reingereicht, damit das Modul unabhängig wird. Thu, 23 Aug 2018 00:27:01 +0200 Jan Dankert Funktion config() in das Modul 'configuration' verschoben sowie Fluent Interface eingebaut. ElementAction um Flags und Format ergänzt.