1 
2 #ifdef HAVE_CONFIG_H
3 #include "../ext_config.h"
4 #endif
5 
6 #include <php.h>
7 #include "../php_ext.h"
8 #include "../ext.h"
9 
10 #include <Zend/zend_operators.h>
11 #include <Zend/zend_exceptions.h>
12 #include <Zend/zend_interfaces.h>
13 
14 #include "kernel/main.h"
15 #include "kernel/object.h"
16 #include "kernel/operators.h"
17 #include "kernel/memory.h"
18 #include "kernel/fcall.h"
19 #include "kernel/exception.h"
20 #include "kernel/string.h"
21 #include "kernel/array.h"
22 
23 
24 /**
25  * This file is part of the Phalcon Framework.
26  *
27  * (c) Phalcon Team <team@phalcon.io>
28  *
29  * For the full copyright and license information, please view the LICENSE.txt
30  * file that was distributed with this source code.
31  */
32 /**
33  * `Phalcon\Config` is designed to simplify the access to, and the use of,
34  * configuration data within applications. It provides a nested object property
35  * based user interface for accessing this configuration data within application
36  * code.
37  *
38  *```php
39  * $config = new \Phalcon\Config(
40  *     [
41  *         "database" => [
42  *             "adapter"  => "Mysql",
43  *             "host"     => "localhost",
44  *             "username" => "scott",
45  *             "password" => "cheetah",
46  *             "dbname"   => "test_db",
47  *         ],
48  *         "phalcon" => [
49  *             "controllersDir" => "../app/controllers/",
50  *             "modelsDir"      => "../app/models/",
51  *             "viewsDir"       => "../app/views/",
52  *         ],
53  *     ]
54  * );
55  *```
56  */
ZEPHIR_INIT_CLASS(Phalcon_Config)57 ZEPHIR_INIT_CLASS(Phalcon_Config) {
58 
59 	ZEPHIR_REGISTER_CLASS_EX(Phalcon, Config, phalcon, config, phalcon_collection_ce, phalcon_config_method_entry, 0);
60 
61 	/**
62 	 * @var string
63 	 */
64 	zend_declare_property_null(phalcon_config_ce, SL("pathDelimiter"), ZEND_ACC_PROTECTED);
65 
66 	zephir_declare_class_constant_string(phalcon_config_ce, SL("DEFAULT_PATH_DELIMITER"), ".");
67 
68 	zend_class_implements(phalcon_config_ce, 1, phalcon_config_configinterface_ce);
69 	return SUCCESS;
70 
71 }
72 
73 /**
74  * Gets the default path delimiter
75  *
76  * @return string
77  */
PHP_METHOD(Phalcon_Config,getPathDelimiter)78 PHP_METHOD(Phalcon_Config, getPathDelimiter) {
79 
80 	zval _0, _1$$3;
81 	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
82 	zval *this_ptr = getThis();
83 
84 	ZVAL_UNDEF(&_0);
85 	ZVAL_UNDEF(&_1$$3);
86 
87 	ZEPHIR_MM_GROW();
88 
89 	zephir_read_property(&_0, this_ptr, ZEND_STRL("pathDelimiter"), PH_NOISY_CC | PH_READONLY);
90 	if (UNEXPECTED(!zephir_is_true(&_0))) {
91 		ZEPHIR_INIT_VAR(&_1$$3);
92 		ZEPHIR_INIT_NVAR(&_1$$3);
93 		ZVAL_STRING(&_1$$3, ".");
94 		zephir_update_property_zval(this_ptr, ZEND_STRL("pathDelimiter"), &_1$$3);
95 	}
96 	RETURN_MM_MEMBER(getThis(), "pathDelimiter");
97 
98 }
99 
100 /**
101  * Merges a configuration into the current one
102  *
103  *```php
104  * $appConfig = new \Phalcon\Config(
105  *     [
106  *         "database" => [
107  *             "host" => "localhost",
108  *         ],
109  *     ]
110  * );
111  *
112  * $globalConfig->merge($appConfig);
113  *```
114  */
PHP_METHOD(Phalcon_Config,merge)115 PHP_METHOD(Phalcon_Config, merge) {
116 
117 	zend_bool _0;
118 	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
119 	zend_long ZEPHIR_LAST_CALL_STATUS;
120 	zval *toMerge, toMerge_sub, config, result, source, target;
121 	zval *this_ptr = getThis();
122 
123 	ZVAL_UNDEF(&toMerge_sub);
124 	ZVAL_UNDEF(&config);
125 	ZVAL_UNDEF(&result);
126 	ZVAL_UNDEF(&source);
127 	ZVAL_UNDEF(&target);
128 
129 	ZEPHIR_MM_GROW();
130 	zephir_fetch_params(1, 1, 0, &toMerge);
131 
132 
133 
134 	_0 = Z_TYPE_P(toMerge) == IS_OBJECT;
135 	if (_0) {
136 		_0 = zephir_instance_of_ev(toMerge, phalcon_config_configinterface_ce);
137 	}
138 	if (Z_TYPE_P(toMerge) == IS_ARRAY) {
139 		ZEPHIR_INIT_VAR(&config);
140 		object_init_ex(&config, phalcon_config_ce);
141 		ZEPHIR_CALL_METHOD(NULL, &config, "__construct", NULL, 22, toMerge);
142 		zephir_check_call_status();
143 	} else if (_0) {
144 		ZEPHIR_CPY_WRT(&config, toMerge);
145 	} else {
146 		ZEPHIR_THROW_EXCEPTION_DEBUG_STR(phalcon_config_exception_ce, "Invalid data type for merge.", "phalcon/Config.zep", 89);
147 		return;
148 	}
149 	ZEPHIR_CALL_METHOD(&source, this_ptr, "toarray", NULL, 0);
150 	zephir_check_call_status();
151 	ZEPHIR_CALL_METHOD(&target, &config, "toarray", NULL, 0);
152 	zephir_check_call_status();
153 	ZEPHIR_CALL_METHOD(&result, this_ptr, "internalmerge", NULL, 23, &source, &target);
154 	zephir_check_call_status();
155 	ZEPHIR_CALL_METHOD(NULL, this_ptr, "clear", NULL, 0);
156 	zephir_check_call_status();
157 	ZEPHIR_CALL_METHOD(NULL, this_ptr, "init", NULL, 0, &result);
158 	zephir_check_call_status();
159 	RETURN_THIS();
160 
161 }
162 
163 /**
164  * Returns a value from current config using a dot separated path.
165  *
166  *```php
167  * echo $config->path("unknown.path", "default", ".");
168  *```
169  */
PHP_METHOD(Phalcon_Config,path)170 PHP_METHOD(Phalcon_Config, path) {
171 
172 	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
173 	zephir_fcall_cache_entry *_1 = NULL;
174 	zend_long ZEPHIR_LAST_CALL_STATUS;
175 	zval *path_param = NULL, *defaultValue = NULL, defaultValue_sub, *delimiter = NULL, delimiter_sub, __$null, config, key, keys, _0, _2$$5, _3$$5;
176 	zval path;
177 	zval *this_ptr = getThis();
178 
179 	ZVAL_UNDEF(&path);
180 	ZVAL_UNDEF(&defaultValue_sub);
181 	ZVAL_UNDEF(&delimiter_sub);
182 	ZVAL_NULL(&__$null);
183 	ZVAL_UNDEF(&config);
184 	ZVAL_UNDEF(&key);
185 	ZVAL_UNDEF(&keys);
186 	ZVAL_UNDEF(&_0);
187 	ZVAL_UNDEF(&_2$$5);
188 	ZVAL_UNDEF(&_3$$5);
189 
190 	ZEPHIR_MM_GROW();
191 	zephir_fetch_params(1, 1, 2, &path_param, &defaultValue, &delimiter);
192 
193 	zephir_get_strval(&path, path_param);
194 	if (!defaultValue) {
195 		defaultValue = &defaultValue_sub;
196 		defaultValue = &__$null;
197 	}
198 	if (!delimiter) {
199 		delimiter = &delimiter_sub;
200 		ZEPHIR_CPY_WRT(delimiter, &__$null);
201 	} else {
202 		ZEPHIR_SEPARATE_PARAM(delimiter);
203 	}
204 
205 
206 	ZEPHIR_CALL_METHOD(&_0, this_ptr, "has", NULL, 0, &path);
207 	zephir_check_call_status();
208 	if (zephir_is_true(&_0)) {
209 		ZEPHIR_RETURN_CALL_METHOD(this_ptr, "get", NULL, 0, &path);
210 		zephir_check_call_status();
211 		RETURN_MM();
212 	}
213 	if (EXPECTED(ZEPHIR_IS_EMPTY(delimiter))) {
214 		ZEPHIR_CALL_METHOD(delimiter, this_ptr, "getpathdelimiter", NULL, 0);
215 		zephir_check_call_status();
216 	}
217 	ZEPHIR_INIT_VAR(&config);
218 	if (zephir_clone(&config, this_ptr) == FAILURE) {
219 		RETURN_MM();
220 	}
221 	ZEPHIR_INIT_VAR(&keys);
222 	zephir_fast_explode(&keys, delimiter, &path, LONG_MAX);
223 	while (1) {
224 		if (!(!(ZEPHIR_IS_EMPTY(&keys)))) {
225 			break;
226 		}
227 		ZEPHIR_MAKE_REF(&keys);
228 		ZEPHIR_CALL_FUNCTION(&key, "array_shift", &_1, 24, &keys);
229 		ZEPHIR_UNREF(&keys);
230 		zephir_check_call_status();
231 		ZEPHIR_CALL_METHOD(&_2$$5, &config, "has", NULL, 0, &key);
232 		zephir_check_call_status();
233 		if (!(zephir_is_true(&_2$$5))) {
234 			break;
235 		}
236 		if (ZEPHIR_IS_EMPTY(&keys)) {
237 			ZEPHIR_RETURN_CALL_METHOD(&config, "get", NULL, 0, &key);
238 			zephir_check_call_status();
239 			RETURN_MM();
240 		}
241 		ZEPHIR_CALL_METHOD(&_3$$5, &config, "get", NULL, 0, &key);
242 		zephir_check_call_status();
243 		ZEPHIR_CPY_WRT(&config, &_3$$5);
244 		if (ZEPHIR_IS_EMPTY(&config)) {
245 			break;
246 		}
247 	}
248 	RETVAL_ZVAL(defaultValue, 1, 0);
249 	RETURN_MM();
250 
251 }
252 
253 /**
254  * Sets the default path delimiter
255  */
PHP_METHOD(Phalcon_Config,setPathDelimiter)256 PHP_METHOD(Phalcon_Config, setPathDelimiter) {
257 
258 	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
259 	zval *delimiter_param = NULL;
260 	zval delimiter;
261 	zval *this_ptr = getThis();
262 
263 	ZVAL_UNDEF(&delimiter);
264 
265 	ZEPHIR_MM_GROW();
266 	zephir_fetch_params(1, 0, 1, &delimiter_param);
267 
268 	if (!delimiter_param) {
269 		ZEPHIR_INIT_VAR(&delimiter);
270 		ZVAL_STRING(&delimiter, "");
271 	} else {
272 		zephir_get_strval(&delimiter, delimiter_param);
273 	}
274 
275 
276 	zephir_update_property_zval(this_ptr, ZEND_STRL("pathDelimiter"), &delimiter);
277 	RETURN_THIS();
278 
279 }
280 
281 /**
282  * Converts recursively the object to an array
283  *
284  *```php
285  * print_r(
286  *     $config->toArray()
287  * );
288  *```
289  */
PHP_METHOD(Phalcon_Config,toArray)290 PHP_METHOD(Phalcon_Config, toArray) {
291 
292 	zend_bool _5$$3, _7$$5;
293 	zend_string *_4;
294 	zend_ulong _3;
295 	zval results;
296 	zval data, key, value, *_1, _2, _6$$4, _8$$6;
297 	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
298 	zend_long ZEPHIR_LAST_CALL_STATUS;
299 	zephir_fcall_cache_entry *_0 = NULL;
300 	zval *this_ptr = getThis();
301 
302 	ZVAL_UNDEF(&data);
303 	ZVAL_UNDEF(&key);
304 	ZVAL_UNDEF(&value);
305 	ZVAL_UNDEF(&_2);
306 	ZVAL_UNDEF(&_6$$4);
307 	ZVAL_UNDEF(&_8$$6);
308 	ZVAL_UNDEF(&results);
309 
310 	ZEPHIR_MM_GROW();
311 
312 	ZEPHIR_INIT_VAR(&results);
313 	array_init(&results);
314 	ZEPHIR_CALL_PARENT(&data, phalcon_config_ce, getThis(), "toarray", &_0, 0);
315 	zephir_check_call_status();
316 	zephir_is_iterable(&data, 0, "phalcon/Config.zep", 179);
317 	if (Z_TYPE_P(&data) == IS_ARRAY) {
318 		ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(&data), _3, _4, _1)
319 		{
320 			ZEPHIR_INIT_NVAR(&key);
321 			if (_4 != NULL) {
322 				ZVAL_STR_COPY(&key, _4);
323 			} else {
324 				ZVAL_LONG(&key, _3);
325 			}
326 			ZEPHIR_INIT_NVAR(&value);
327 			ZVAL_COPY(&value, _1);
328 			_5$$3 = Z_TYPE_P(&value) == IS_OBJECT;
329 			if (_5$$3) {
330 				_5$$3 = (zephir_method_exists_ex(&value, ZEND_STRL("toarray")) == SUCCESS);
331 			}
332 			if (_5$$3) {
333 				ZEPHIR_CALL_METHOD(&_6$$4, &value, "toarray", NULL, 0);
334 				zephir_check_call_status();
335 				ZEPHIR_CPY_WRT(&value, &_6$$4);
336 			}
337 			zephir_array_update_zval(&results, &key, &value, PH_COPY | PH_SEPARATE);
338 		} ZEND_HASH_FOREACH_END();
339 	} else {
340 		ZEPHIR_CALL_METHOD(NULL, &data, "rewind", NULL, 0);
341 		zephir_check_call_status();
342 		while (1) {
343 			ZEPHIR_CALL_METHOD(&_2, &data, "valid", NULL, 0);
344 			zephir_check_call_status();
345 			if (!zend_is_true(&_2)) {
346 				break;
347 			}
348 			ZEPHIR_CALL_METHOD(&key, &data, "key", NULL, 0);
349 			zephir_check_call_status();
350 			ZEPHIR_CALL_METHOD(&value, &data, "current", NULL, 0);
351 			zephir_check_call_status();
352 				_7$$5 = Z_TYPE_P(&value) == IS_OBJECT;
353 				if (_7$$5) {
354 					_7$$5 = (zephir_method_exists_ex(&value, ZEND_STRL("toarray")) == SUCCESS);
355 				}
356 				if (_7$$5) {
357 					ZEPHIR_CALL_METHOD(&_8$$6, &value, "toarray", NULL, 0);
358 					zephir_check_call_status();
359 					ZEPHIR_CPY_WRT(&value, &_8$$6);
360 				}
361 				zephir_array_update_zval(&results, &key, &value, PH_COPY | PH_SEPARATE);
362 			ZEPHIR_CALL_METHOD(NULL, &data, "next", NULL, 0);
363 			zephir_check_call_status();
364 		}
365 	}
366 	ZEPHIR_INIT_NVAR(&value);
367 	ZEPHIR_INIT_NVAR(&key);
368 	RETURN_CTOR(&results);
369 
370 }
371 
372 /**
373  * Performs a merge recursively
374  */
PHP_METHOD(Phalcon_Config,internalMerge)375 PHP_METHOD(Phalcon_Config, internalMerge) {
376 
377 	zend_bool _4$$3, _5$$3, _10$$7, _11$$7;
378 	zend_string *_3;
379 	zend_ulong _2;
380 	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
381 	zephir_fcall_cache_entry *_9 = NULL;
382 	zend_long ZEPHIR_LAST_CALL_STATUS;
383 	zval *source_param = NULL, *target_param = NULL, key, value, *_0, _1, _6$$3, _7$$4, _8$$4, _12$$7, _13$$8, _14$$8;
384 	zval source, target;
385 	zval *this_ptr = getThis();
386 
387 	ZVAL_UNDEF(&source);
388 	ZVAL_UNDEF(&target);
389 	ZVAL_UNDEF(&key);
390 	ZVAL_UNDEF(&value);
391 	ZVAL_UNDEF(&_1);
392 	ZVAL_UNDEF(&_6$$3);
393 	ZVAL_UNDEF(&_7$$4);
394 	ZVAL_UNDEF(&_8$$4);
395 	ZVAL_UNDEF(&_12$$7);
396 	ZVAL_UNDEF(&_13$$8);
397 	ZVAL_UNDEF(&_14$$8);
398 
399 	ZEPHIR_MM_GROW();
400 	zephir_fetch_params(1, 2, 0, &source_param, &target_param);
401 
402 	zephir_get_arrval(&source, source_param);
403 	zephir_get_arrval(&target, target_param);
404 
405 
406 	zephir_is_iterable(&target, 0, "phalcon/Config.zep", 199);
407 	if (Z_TYPE_P(&target) == IS_ARRAY) {
408 		ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(&target), _2, _3, _0)
409 		{
410 			ZEPHIR_INIT_NVAR(&key);
411 			if (_3 != NULL) {
412 				ZVAL_STR_COPY(&key, _3);
413 			} else {
414 				ZVAL_LONG(&key, _2);
415 			}
416 			ZEPHIR_INIT_NVAR(&value);
417 			ZVAL_COPY(&value, _0);
418 			_4$$3 = Z_TYPE_P(&value) == IS_ARRAY;
419 			if (_4$$3) {
420 				_4$$3 = zephir_array_isset(&source, &key);
421 			}
422 			_5$$3 = _4$$3;
423 			if (_5$$3) {
424 				ZEPHIR_OBS_NVAR(&_6$$3);
425 				zephir_array_fetch(&_6$$3, &source, &key, PH_NOISY, "phalcon/Config.zep", 190);
426 				_5$$3 = Z_TYPE_P(&_6$$3) == IS_ARRAY;
427 			}
428 			if (_5$$3) {
429 				zephir_array_fetch(&_8$$4, &source, &key, PH_NOISY | PH_READONLY, "phalcon/Config.zep", 191);
430 				ZEPHIR_CALL_METHOD(&_7$$4, this_ptr, "internalmerge", &_9, 23, &_8$$4, &value);
431 				zephir_check_call_status();
432 				zephir_array_update_zval(&source, &key, &_7$$4, PH_COPY | PH_SEPARATE);
433 			} else if (Z_TYPE_P(&key) == IS_LONG) {
434 				zephir_array_append(&source, &value, PH_SEPARATE, "phalcon/Config.zep", 193);
435 			} else {
436 				zephir_array_update_zval(&source, &key, &value, PH_COPY | PH_SEPARATE);
437 			}
438 		} ZEND_HASH_FOREACH_END();
439 	} else {
440 		ZEPHIR_CALL_METHOD(NULL, &target, "rewind", NULL, 0);
441 		zephir_check_call_status();
442 		while (1) {
443 			ZEPHIR_CALL_METHOD(&_1, &target, "valid", NULL, 0);
444 			zephir_check_call_status();
445 			if (!zend_is_true(&_1)) {
446 				break;
447 			}
448 			ZEPHIR_CALL_METHOD(&key, &target, "key", NULL, 0);
449 			zephir_check_call_status();
450 			ZEPHIR_CALL_METHOD(&value, &target, "current", NULL, 0);
451 			zephir_check_call_status();
452 				_10$$7 = Z_TYPE_P(&value) == IS_ARRAY;
453 				if (_10$$7) {
454 					_10$$7 = zephir_array_isset(&source, &key);
455 				}
456 				_11$$7 = _10$$7;
457 				if (_11$$7) {
458 					ZEPHIR_OBS_NVAR(&_12$$7);
459 					zephir_array_fetch(&_12$$7, &source, &key, PH_NOISY, "phalcon/Config.zep", 190);
460 					_11$$7 = Z_TYPE_P(&_12$$7) == IS_ARRAY;
461 				}
462 				if (_11$$7) {
463 					zephir_array_fetch(&_14$$8, &source, &key, PH_NOISY | PH_READONLY, "phalcon/Config.zep", 191);
464 					ZEPHIR_CALL_METHOD(&_13$$8, this_ptr, "internalmerge", &_9, 23, &_14$$8, &value);
465 					zephir_check_call_status();
466 					zephir_array_update_zval(&source, &key, &_13$$8, PH_COPY | PH_SEPARATE);
467 				} else if (Z_TYPE_P(&key) == IS_LONG) {
468 					zephir_array_append(&source, &value, PH_SEPARATE, "phalcon/Config.zep", 193);
469 				} else {
470 					zephir_array_update_zval(&source, &key, &value, PH_COPY | PH_SEPARATE);
471 				}
472 			ZEPHIR_CALL_METHOD(NULL, &target, "next", NULL, 0);
473 			zephir_check_call_status();
474 		}
475 	}
476 	ZEPHIR_INIT_NVAR(&value);
477 	ZEPHIR_INIT_NVAR(&key);
478 	RETURN_CTOR(&source);
479 
480 }
481 
482 /**
483  * Sets the collection data
484  */
PHP_METHOD(Phalcon_Config,setData)485 PHP_METHOD(Phalcon_Config, setData) {
486 
487 	zval _0;
488 	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
489 	zend_long ZEPHIR_LAST_CALL_STATUS;
490 	zval *element = NULL, element_sub, *value, value_sub, data, key, _1;
491 	zval *this_ptr = getThis();
492 
493 	ZVAL_UNDEF(&element_sub);
494 	ZVAL_UNDEF(&value_sub);
495 	ZVAL_UNDEF(&data);
496 	ZVAL_UNDEF(&key);
497 	ZVAL_UNDEF(&_1);
498 	ZVAL_UNDEF(&_0);
499 
500 	ZEPHIR_MM_GROW();
501 	zephir_fetch_params(1, 2, 0, &element, &value);
502 
503 	ZEPHIR_SEPARATE_PARAM(element);
504 
505 
506 	zephir_get_strval(&_0, element);
507 	ZEPHIR_CPY_WRT(element, &_0);
508 	zephir_read_property(&_1, this_ptr, ZEND_STRL("insensitive"), PH_NOISY_CC | PH_READONLY);
509 	if (zephir_is_true(&_1)) {
510 		ZEPHIR_CALL_FUNCTION(&key, "mb_strtolower", NULL, 25, element);
511 		zephir_check_call_status();
512 	} else {
513 		ZEPHIR_CPY_WRT(&key, element);
514 	}
515 	zephir_update_property_array(this_ptr, SL("lowerKeys"), &key, element);
516 	if (Z_TYPE_P(value) == IS_ARRAY) {
517 		ZEPHIR_INIT_VAR(&data);
518 		object_init_ex(&data, phalcon_config_ce);
519 		ZEPHIR_CALL_METHOD(NULL, &data, "__construct", NULL, 22, value);
520 		zephir_check_call_status();
521 	} else {
522 		ZEPHIR_CPY_WRT(&data, value);
523 	}
524 	zephir_update_property_array(this_ptr, SL("data"), element, &data);
525 	ZEPHIR_MM_RESTORE();
526 
527 }
528 
529