diff --git a/ext/kernel/object.c b/ext/kernel/object.c index e0584e1c510..3b55a91f7ee 100644 --- a/ext/kernel/object.c +++ b/ext/kernel/object.c @@ -44,6 +44,135 @@ int phalcon_get_class_constant(zval *return_value, const zend_class_entry *ce, c return SUCCESS; } +/* + * Multiple array-offset update + */ +int zephir_update_static_property_array_multi_ce(zend_class_entry *ce, const char *property, zend_uint property_length, zval *value TSRMLS_DC, const char *types, int types_length, int types_count, ...) { + + int i, l, ll; char *s; + va_list ap; + zval *fetched, *tmp_arr, *tmp, *p, *item; + int separated = 0; + + phalcon_read_static_property_ce(&tmp_arr, ce, property, property_length TSRMLS_CC); + + Z_DELREF_P(tmp_arr); + + /** Separation only when refcount > 1 */ + if (Z_REFCOUNT_P(tmp_arr) > 1) { + zval *new_zv; + ALLOC_ZVAL(new_zv); + INIT_PZVAL_COPY(new_zv, tmp_arr); + tmp_arr = new_zv; + zval_copy_ctor(new_zv); + Z_SET_REFCOUNT_P(tmp_arr, 0); + separated = 1; + } + + /** Convert the value to array if not is an array */ + if (Z_TYPE_P(tmp_arr) != IS_ARRAY) { + if (separated) { + convert_to_array(tmp_arr); + } else { + zval *new_zv; + ALLOC_ZVAL(new_zv); + INIT_PZVAL_COPY(new_zv, tmp_arr); + tmp_arr = new_zv; + zval_copy_ctor(new_zv); + Z_SET_REFCOUNT_P(tmp_arr, 0); + array_init(tmp_arr); + separated = 1; + } + } + + va_start(ap, types_count); + + p = tmp_arr; + for (i = 0; i < types_length; ++i) { + switch (types[i]) { + + case 's': + s = va_arg(ap, char*); + l = va_arg(ap, int); + if (phalcon_array_isset_string_fetch(&fetched, p, s, l + 1)) { + if (Z_TYPE_P(fetched) == IS_ARRAY) { + if (i == (types_length - 1)) { + phalcon_array_update_string(&fetched, s, l, value, PH_COPY | PH_SEPARATE); + } else { + p = fetched; + } + continue; + } + } + if (i == (types_length - 1)) { + phalcon_array_update_string(&p, s, l, value, PH_COPY | PH_SEPARATE); + } else { + MAKE_STD_ZVAL(tmp); + array_init(tmp); + phalcon_array_update_string(&p, s, l, &tmp, PH_SEPARATE); + p = tmp; + } + break; + + case 'l': + ll = va_arg(ap, long); + if (phalcon_array_isset_long_fetch(&fetched, p, ll)) { + if (Z_TYPE_P(fetched) == IS_ARRAY) { + if (i == (types_length - 1)) { + phalcon_array_update_long(&fetched, ll, value, PH_COPY | PH_SEPARATE); + } else { + p = fetched; + } + continue; + } + } + if (i == (types_length - 1)) { + phalcon_array_update_long(&p, ll, value, PH_COPY | PH_SEPARATE); + } else { + MAKE_STD_ZVAL(tmp); + array_init(tmp); + phalcon_array_update_long(&p, ll, tmp, PH_SEPARATE); + p = tmp; + } + break; + + case 'z': + item = va_arg(ap, zval*); + if (phalcon_array_isset_fetch(&fetched, p, item)) { + if (Z_TYPE_P(fetched) == IS_ARRAY) { + if (i == (types_length - 1)) { + phalcon_array_update_zval(&fetched, item, value, PH_COPY | PH_SEPARATE); + } else { + p = fetched; + } + continue; + } + } + if (i == (types_length - 1)) { + phalcon_array_update_zval(&p, item, value, PH_COPY | PH_SEPARATE); + } else { + MAKE_STD_ZVAL(tmp); + array_init(tmp); + phalcon_array_update_zval(&p, item, tmp, PH_SEPARATE); + p = tmp; + } + break; + + case 'a': + phalcon_array_append(&p, value, PH_SEPARATE); + break; + } + } + + va_end(ap); + + if (separated) { + phalcon_update_static_property_ce(ce, property, property_length, tmp_arr TSRMLS_CC); + } + + return SUCCESS; +} + /** * Returns a class name into a zval result */ diff --git a/ext/kernel/object.h b/ext/kernel/object.h index 0974378c774..d70b3a910d1 100644 --- a/ext/kernel/object.h +++ b/ext/kernel/object.h @@ -205,6 +205,7 @@ int phalcon_unset_property_array(zval *object, const char *property, zend_uint p /** Static properties */ int phalcon_read_static_property(zval **result, const char *class_name, zend_uint class_length, const char *property_name, zend_uint property_length TSRMLS_DC) PHALCON_ATTR_NONNULL; int phalcon_read_class_property(zval **result, int type, const char *property, zend_uint len TSRMLS_DC) PHALCON_ATTR_NONNULL; +int phalcon_update_static_property_array_multi_ce(zend_class_entry *ce, const char *property, zend_uint property_length, zval **value TSRMLS_DC, const char *types, int types_length, int types_count, ...); PHALCON_ATTR_NONNULL static inline zval* phalcon_fetch_static_property_ce(zend_class_entry *ce, const char *property, zend_uint len TSRMLS_DC) { diff --git a/ext/tag.c b/ext/tag.c index 04b34036cbb..a246154671d 100644 --- a/ext/tag.c +++ b/ext/tag.c @@ -556,8 +556,7 @@ PHP_METHOD(Phalcon_Tag, setAutoescape){ */ PHP_METHOD(Phalcon_Tag, setDefault){ - zval *id, *value, *t0; - int separate = 0; + zval *id, *value; phalcon_fetch_params(0, 2, 0, &id, &value); @@ -568,24 +567,7 @@ PHP_METHOD(Phalcon_Tag, setDefault){ } } - t0 = phalcon_fetch_static_property_ce(phalcon_tag_ce, SL("_displayValues") TSRMLS_CC); - if (Z_REFCOUNT_P(t0) > 1) { - separate = 1; - ALLOC_INIT_ZVAL(t0); - Z_DELREF_P(t0); - } - - if (Z_TYPE_P(t0) == IS_NULL) { - array_init_size(t0, 1); - } - else if (Z_TYPE_P(t0) != IS_ARRAY) { - convert_to_array(t0); - } - - phalcon_array_update_zval(&t0, id, value, PH_COPY); - if (separate) { - phalcon_update_static_property_ce(phalcon_tag_ce, SL("_displayValues"), t0 TSRMLS_CC); - } + zephir_update_static_property_array_multi_ce(phalcon_tag_ce, SL("_displayValues"), value TSRMLS_CC, SL("z"), 1, id); } /** diff --git a/unit-tests/TagTest.php b/unit-tests/TagTest.php index d9167b00985..c7cc99e58b5 100644 --- a/unit-tests/TagTest.php +++ b/unit-tests/TagTest.php @@ -62,6 +62,26 @@ public function testSelect() $this->assertEquals($ret, $html); } + /** + * @see 2402 issue + * @link https://github.com/phalcon/cphalcon/issues/2402 + * @throws Exception + */ + public function testDisplayValues() + { + Tag::setDefault('property1', 'testVal1'); + Tag::setDefault('property2', 'testVal2'); + Tag::setDefault('property3', 'testVal3'); + + $this->assertTrue(Tag::hasValue('property1')); + $this->assertTrue(Tag::hasValue('property2')); + $this->assertTrue(Tag::hasValue('property3')); + + $this->assertEquals('testVal1', Tag::getValue('property1')); + $this->assertEquals('testVal2', Tag::getValue('property2')); + $this->assertEquals('testVal3', Tag::getValue('property3')); + } + public function testSetTitleSeparator() {