1: <?php
  2: 
  3: namespace Mini\Config;
  4: 
  5: use ArrayAccess;
  6: use JsonSerializable;
  7: 
  8:   9:  10:  11:  12:  13: 
 14: class Config implements ArrayAccess, JsonSerializable, \Serializable {
 15: 
 16:      17:  18:  19:  20: 
 21:     protected $config;
 22: 
 23:      24:  25:  26:  27: 
 28:     protected $directories = [];
 29: 
 30:      31:  32:  33:  34: 
 35:     protected $files = [];
 36: 
 37:      38:  39:  40:  41: 
 42:     protected $handlers;
 43: 
 44:      45:  46:  47:  48:  49:  50:  51: 
 52:     public function __construct($options = null) {
 53:         if (isset($options)) {
 54:             if (isset($options['targets'])) {
 55:                 if (is_array($options['targets'])) {
 56:                     foreach ($options['targets'] as $path) {
 57:                         $this->addTarget($path);
 58:                     }
 59:                 } else {
 60:                     $this->addTarget($options['targets']);
 61:                 }
 62:             }
 63:             if (isset($options['handlers'])) {
 64:                 foreach (array_keys($options['handlers']) as $ext) {
 65:                     $this->registerHandler($ext, $options['handlers'][$ext]);
 66:                 }
 67:             }
 68:         }
 69:         $this->registerDefaultHandlers();
 70:         $this->refresh();
 71:     }
 72: 
 73:      74:  75:  76:  77: 
 78:     public function addTarget($target) {
 79:         if (is_array($target)) {
 80:             foreach ($target as $p) {
 81:                 $this->addTarget($p);
 82:             }
 83:             return;
 84:         }
 85:         if (is_dir($target)) {
 86:             $this->directories[] = rtrim($target, '/');
 87:         } elseif (is_file($target)) {
 88:             $this->files[] = $target;
 89:         }
 90:     }
 91: 
 92:      93:  94:  95:  96:  97:  98: 
 99:     public function registerHandler($extension, $handler) {
100:         if (is_array($extension)) {
101:             foreach ($extension as $ext) {
102:                 $this->handlers[$ext] = $handler;
103:             }
104:         } else {
105:             $this->handlers[$extension] = $handler;
106:         }
107:     }
108: 
109:     110: 111: 
112:     private function registerDefaultHandlers() {
113:         $this->registerHandler('xml', function ($file) {
114:             $xml2array = function ($xmlObject, $out = array()) use (&$xml2array) {
115:                 foreach ((array)$xmlObject as $index => $node) {
116:                     $out[$index] = (is_object($node)) ? $xml2array($node) : $node;
117:                 }
118:                 return $out;
119:             };
120:             return $xml2array(simplexml_load_string(file_get_contents($file)));
121:         });
122:         $this->registerHandler('php', function ($file) {
123:             $data = include($file);
124:             if ($data != null && is_array($data)) {
125:                 return $data;
126:             }
127:             return;
128:         });
129:         $this->registerHandler('ini', function ($file) {
130:             return parse_ini_file($file, true);
131:         });
132:         $this->registerHandler('json', function ($file) {
133:             return json_decode(file_get_contents($file), true);
134:         });
135:     }
136: 
137:     138: 139: 
140:     public function refresh() {
141:         $this->config = [];
142:         foreach ($this->directories as $dir) {
143:             foreach ($this->handlers as $ext => $function) {
144:                 foreach (glob($dir . "/*." . $ext, GLOB_NOSORT) as $file) {
145:                     $this->config = array_merge_recursive($this->config, $function($file));
146:                 }
147:             }
148:         }
149:         foreach ($this->files as $file) {
150:             $pathinfo = pathinfo($file);
151:             if (isset($pathinfo['extension'])) {
152:                 $ext = $pathinfo['extension'];
153:                 if (in_array($ext, array_keys($this->handlers))) {
154:                     $this->config = array_merge_recursive($this->config, $this->handlers[$ext]($file));
155:                 }
156:             }
157:         }
158:     }
159: 
160:     161: 162: 163: 164: 
165:     public function merge(array $config) {
166:         $this->config = array_merge_recursive($this->config, $config);
167:     }
168: 
169:     170: 171: 172: 173: 
174:     public function removeHandler($extension) {
175:         unset($this->handlers[$extension]);
176:     }
177: 
178:     179: 180: 181: 
182:     public function offsetExists($offset) {
183:         return $this->__isset($offset);
184:     }
185: 
186:     187: 188: 189: 
190:     public function __isset($key) {
191:         return isset($this->config[$key]);
192:     }
193: 
194:     195: 196: 197: 
198:     public function offsetGet($offset) {
199:         return $this->__get($offset);
200:     }
201: 
202:     203: 204: 205: 
206:     public function __get($key) {
207:         if (isset($this->config[$key])) {
208:             return $this->config[$key];
209:         } else {
210:             return null;
211:         }
212:     }
213: 
214:     215: 216: 217: 
218:     public function __set($key, $value) {
219:         if ($key === null) {
220:             $this->config[] = $value;
221:         } else {
222:             $this->config[$key] = $value;
223:         }
224:     }
225: 
226:     227: 228: 229: 
230:     public function offsetSet($offset, $data) {
231:         $this->__set($offset, $data);
232:     }
233: 
234:     235: 236: 
237:     public function offsetUnset($offset) {
238:         unset($this->config[$offset]);
239:     }
240: 
241:     242: 243: 
244:     public function __unset($name) {
245:         if (isset($this->config[$name])) {
246:             unset($this->config[$name]);
247:         }
248:     }
249: 
250:     251: 252: 253: 254: 255: 
256:     public function serialize() {
257:         return $this->jsonSerialize();
258:     }
259: 
260:     261: 262: 263: 264: 265: 266: 
267:     function jsonSerialize() {
268:         return $this->config;
269:     }
270: 
271:     272: 273: 274: 275: 276: 277: 278: 279: 
280:     public function unserialize($serialized) {
281:         $this->config = json_decode($serialized, true);
282:     }
283: }
284: 
285: 286: 287: 288: 289: 
290: class Utils {
291:     292: 293: 294: 295: 296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307: 308: 309: 310: 311: 312: 313: 314: 315: 316: 317: 
318:     public static function merge($array1, $array2, $overwrite = false) {
319:         $array = $array1;
320:         foreach (array_keys($array2) as $key) {
321:             if (!isset($array1[$key])) {
322:                 $array[$key] = $array2[$key];
323:                 continue;
324:             }
325:             if (is_array($array1[$key])) {
326:                 $array[$key] = self::Merge($array1[$key], $array2[$key], $overwrite);
327:                 continue;
328:             }
329:             if ($overwrite) {
330:                 $array[$key] = $array2[$key];
331:             } else {
332:                 $array[$key] = [$array[$key], $array2[$key]];
333:             }
334:         }
335:         return $array;
336:     }
337: 
338: }
339: