mirror of
https://github.com/twigphp/Twig.git
synced 2026-09-21 07:37:43 +00:00
merged branch Tobion/patch-1 (PR #1030)
This PR was merged into the master branch. Discussion ---------- fix numeric & boolean & float keys in array Reopened PR of #878 Commits -------2c56b70Merge pull request #3 from tucksaun/patch-117d6cc7[ext] fixed tabs46012ce[ext] improvements21f8062[ext] code cleaning9347c52[ext] updated PHP code documenting C codeb41ce60updated C extension accordinglye5291e1rename item to attribute in the exception message because that's the term that is used in twig, e.g. the functiona93f0dcfurther improved exception message and distinguish array_call and any_call access26bac14added tests for array access with confusable keysdb744d5fix test that that would not fail if no exception is thrown9ea16ecrefactored getAttribute6fb5afaimproved error message for non-existent or invalid attributesfdfd506added changelog entry about fixed boolean array accessda616c5fixed getAttribute for array access with a boolean or float keyb6acf9dupdated CHANGELOGc4d5b3fadded some unit tests for previous mergee84448bfix numeric keys in array
This commit is contained in:
@@ -11,6 +11,8 @@
|
|||||||
* fixed fatal error that should be an exception when adding a filter/function/test too late
|
* fixed fatal error that should be an exception when adding a filter/function/test too late
|
||||||
* added a batch filter
|
* added a batch filter
|
||||||
* added support for encoding an array as query string in the url_encode filter
|
* added support for encoding an array as query string in the url_encode filter
|
||||||
|
* fixed getting a numeric-like item on a variable ('09' for instance)
|
||||||
|
* fixed getting a boolean or float key on an array, so it is consistent with PHP's array access: `{{ array[false] }}` behaves the same as `echo $array[false];` (equals `$array[0]`)
|
||||||
|
|
||||||
* 1.12.2 (2013-02-09)
|
* 1.12.2 (2013-02-09)
|
||||||
|
|
||||||
|
|||||||
+124
-102
@@ -76,12 +76,29 @@ zend_module_entry twig_module_entry = {
|
|||||||
ZEND_GET_MODULE(twig)
|
ZEND_GET_MODULE(twig)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int TWIG_ARRAY_KEY_EXISTS(zval *array, char* key, int key_len)
|
int TWIG_ARRAY_KEY_EXISTS(zval *array, zval *key)
|
||||||
{
|
{
|
||||||
|
zval temp;
|
||||||
|
int result;
|
||||||
|
|
||||||
if (Z_TYPE_P(array) != IS_ARRAY) {
|
if (Z_TYPE_P(array) != IS_ARRAY) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return zend_symtable_exists(Z_ARRVAL_P(array), key, key_len + 1);
|
|
||||||
|
switch (Z_TYPE_P(key)) {
|
||||||
|
case IS_NULL:
|
||||||
|
return zend_hash_exists(Z_ARRVAL_P(array), "", 1);
|
||||||
|
|
||||||
|
case IS_BOOL:
|
||||||
|
case IS_DOUBLE:
|
||||||
|
convert_to_long(key);
|
||||||
|
case IS_LONG:
|
||||||
|
return zend_hash_index_exists(Z_ARRVAL_P(array), Z_LVAL_P(key));
|
||||||
|
|
||||||
|
default:
|
||||||
|
convert_to_string(key);
|
||||||
|
return zend_symtable_exists(Z_ARRVAL_P(array), Z_STRVAL_P(key), Z_STRLEN_P(key) + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
|
int TWIG_INSTANCE_OF(zval *object, zend_class_entry *interface TSRMLS_DC)
|
||||||
@@ -106,23 +123,23 @@ int TWIG_INSTANCE_OF_USERLAND(zval *object, char *interface TSRMLS_DC)
|
|||||||
|
|
||||||
zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
|
zval *TWIG_GET_ARRAYOBJECT_ELEMENT(zval *object, zval *offset TSRMLS_DC)
|
||||||
{
|
{
|
||||||
zend_class_entry *ce = Z_OBJCE_P(object);
|
zend_class_entry *ce = Z_OBJCE_P(object);
|
||||||
zval *retval;
|
zval *retval;
|
||||||
|
|
||||||
if (Z_TYPE_P(object) == IS_OBJECT) {
|
if (Z_TYPE_P(object) == IS_OBJECT) {
|
||||||
SEPARATE_ARG_IF_REF(offset);
|
SEPARATE_ARG_IF_REF(offset);
|
||||||
zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
|
zend_call_method_with_1_params(&object, ce, NULL, "offsetget", &retval, offset);
|
||||||
|
|
||||||
zval_ptr_dtor(&offset);
|
zval_ptr_dtor(&offset);
|
||||||
|
|
||||||
if (!retval) {
|
if (!retval) {
|
||||||
if (!EG(exception)) {
|
if (!EG(exception)) {
|
||||||
zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
|
zend_error(E_ERROR, "Undefined offset for object of type %s used as array", ce->name);
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -245,7 +262,7 @@ zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
|
|||||||
zval **tmp_zval;
|
zval **tmp_zval;
|
||||||
char *tmp_name;
|
char *tmp_name;
|
||||||
|
|
||||||
if (class == NULL || Z_TYPE_P(class) != IS_ARRAY || Z_TYPE_P(prop_name) != IS_STRING) {
|
if (class == NULL || Z_TYPE_P(class) != IS_ARRAY) {
|
||||||
if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
|
if (class != NULL && Z_TYPE_P(class) == IS_OBJECT && TWIG_INSTANCE_OF(class, zend_ce_arrayaccess TSRMLS_CC)) {
|
||||||
// array access object
|
// array access object
|
||||||
return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC);
|
return TWIG_GET_ARRAYOBJECT_ELEMENT(class, prop_name TSRMLS_CC);
|
||||||
@@ -253,11 +270,23 @@ zval *TWIG_GET_ARRAY_ELEMENT_ZVAL(zval *class, zval *prop_name TSRMLS_DC)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
convert_to_string(prop_name);
|
switch(Z_TYPE_P(prop_name)) {
|
||||||
tmp_name = Z_STRVAL_P(prop_name);
|
case IS_NULL:
|
||||||
if (zend_symtable_find(HASH_OF(class), tmp_name, strlen(tmp_name)+1, (void**) &tmp_zval) == SUCCESS) {
|
zend_hash_find(HASH_OF(class), "", 1, (void**) &tmp_zval);
|
||||||
return *tmp_zval;
|
return *tmp_zval;
|
||||||
|
|
||||||
|
case IS_BOOL:
|
||||||
|
case IS_DOUBLE:
|
||||||
|
convert_to_long(prop_name);
|
||||||
|
case IS_LONG:
|
||||||
|
zend_hash_index_find(HASH_OF(class), Z_LVAL_P(prop_name), (void **) &tmp_zval);
|
||||||
|
return *tmp_zval;
|
||||||
|
|
||||||
|
case IS_STRING:
|
||||||
|
zend_symtable_find(HASH_OF(class), Z_STRVAL_P(prop_name), Z_STRLEN_P(prop_name) + 1, (void**) &tmp_zval);
|
||||||
|
return *tmp_zval;
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -717,7 +746,7 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
zval *object;
|
zval *object;
|
||||||
char *item;
|
char *item;
|
||||||
int item_len;
|
int item_len;
|
||||||
zval zitem;
|
zval *zitem, ztmpitem;
|
||||||
zval *arguments = NULL;
|
zval *arguments = NULL;
|
||||||
zval *ret = NULL;
|
zval *ret = NULL;
|
||||||
char *type = NULL;
|
char *type = NULL;
|
||||||
@@ -728,22 +757,17 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
zval *tmp_self_cache;
|
zval *tmp_self_cache;
|
||||||
|
|
||||||
|
|
||||||
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozs|asbb", &template, &object, &item, &item_len, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) {
|
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ozz|asbb", &template, &object, &zitem, &arguments, &type, &type_len, &isDefinedTest, &ignoreStrictCheck) == FAILURE) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
INIT_PZVAL(&zitem);
|
// convert the item to a string
|
||||||
ZVAL_STRINGL(&zitem, item, item_len, 0);
|
ztmpitem = *zitem;
|
||||||
|
zval_copy_ctor(&ztmpitem);
|
||||||
switch (is_numeric_string(item, item_len, &Z_LVAL(zitem), &Z_DVAL(zitem), 0)) {
|
convert_to_string(&ztmpitem);
|
||||||
case IS_LONG:
|
item_len = Z_STRLEN(ztmpitem);
|
||||||
Z_TYPE(zitem) = IS_LONG;
|
item = estrndup(Z_STRVAL(ztmpitem), item_len);
|
||||||
break;
|
zval_dtor(&ztmpitem);
|
||||||
case IS_DOUBLE:
|
|
||||||
Z_TYPE(zitem) = IS_DOUBLE;
|
|
||||||
convert_to_long(&zitem);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!type) {
|
if (!type) {
|
||||||
type = "any";
|
type = "any";
|
||||||
@@ -752,28 +776,31 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
/*
|
/*
|
||||||
// array
|
// array
|
||||||
if (Twig_TemplateInterface::METHOD_CALL !== $type) {
|
if (Twig_TemplateInterface::METHOD_CALL !== $type) {
|
||||||
if ((is_array($object) && array_key_exists($item, $object))
|
$arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
|
||||||
|| ($object instanceof ArrayAccess && isset($object[$item]))
|
|
||||||
|
if ((is_array($object) && array_key_exists($arrayItem, $object))
|
||||||
|
|| ($object instanceof ArrayAccess && isset($object[$arrayItem]))
|
||||||
) {
|
) {
|
||||||
if ($isDefinedTest) {
|
if ($isDefinedTest) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $object[$item];
|
return $object[$arrayItem];
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
if (strcmp("method", type) != 0) {
|
if (strcmp("method", type) != 0) {
|
||||||
// printf("XXXmethod: %s\n", type);
|
if ((TWIG_ARRAY_KEY_EXISTS(object, zitem))
|
||||||
if ((TWIG_ARRAY_KEY_EXISTS(object, item, item_len))
|
|| (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, zitem TSRMLS_CC))
|
||||||
|| (TWIG_INSTANCE_OF(object, zend_ce_arrayaccess TSRMLS_CC) && TWIG_ISSET_ARRAYOBJECT_ELEMENT(object, &zitem TSRMLS_CC))
|
|
||||||
) {
|
) {
|
||||||
zval *ret;
|
|
||||||
|
|
||||||
if (isDefinedTest) {
|
if (isDefinedTest) {
|
||||||
RETURN_TRUE;
|
RETURN_TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = TWIG_GET_ARRAY_ELEMENT(object, item, item_len TSRMLS_CC);
|
ret = TWIG_GET_ARRAY_ELEMENT_ZVAL(object, zitem TSRMLS_CC);
|
||||||
|
|
||||||
if (!ret) {
|
if (!ret) {
|
||||||
ret = &EG(uninitialized_zval);
|
ret = &EG(uninitialized_zval);
|
||||||
}
|
}
|
||||||
@@ -792,7 +819,7 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (strcmp("array", type) == 0) {
|
if (strcmp("array", type) == 0 || Z_TYPE_P(object) != IS_OBJECT) {
|
||||||
if (isDefinedTest) {
|
if (isDefinedTest) {
|
||||||
RETURN_FALSE;
|
RETURN_FALSE;
|
||||||
}
|
}
|
||||||
@@ -801,11 +828,13 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
if (is_object($object)) {
|
if (is_object($object)) {
|
||||||
throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
|
throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
|
||||||
} elseif (is_array($object)) {
|
} elseif (is_array($object)) {
|
||||||
throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $item, implode(', ', array_keys($object))), -1, $this->getTemplateName());
|
throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName());
|
||||||
|
} elseif (Twig_TemplateInterface::ARRAY_CALL === $type) {
|
||||||
|
throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
|
||||||
} else {
|
} else {
|
||||||
throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a "%s" variable', $item, gettype($object)), -1, $this->getTemplateName());
|
throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -815,7 +844,15 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
} else if (Z_TYPE_P(object) == IS_ARRAY) {
|
} else if (Z_TYPE_P(object) == IS_ARRAY) {
|
||||||
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
|
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Key \"%s\" for array with keys \"%s\" does not exist", item, TWIG_IMPLODE_ARRAY_KEYS(", ", object TSRMLS_CC));
|
||||||
} else {
|
} else {
|
||||||
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to access a key (\"%s\") on a \"%s\" variable", item, zend_zval_type_name(object));
|
char *type_name = zend_zval_type_name(object);
|
||||||
|
Z_ADDREF_P(object);
|
||||||
|
convert_to_string(object);
|
||||||
|
TWIG_RUNTIME_ERROR(template TSRMLS_CC,
|
||||||
|
(strcmp("array", type) == 0)
|
||||||
|
? "Impossible to access a key (\"%s\") on a %s variable (\"%s\")"
|
||||||
|
: "Impossible to access an attribute (\"%s\") on a %s variable (\"%s\")",
|
||||||
|
item, type_name, Z_STRVAL_P(object));
|
||||||
|
zval_ptr_dtor(&object);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -836,58 +873,47 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, implode(', ', array_keys($object))));
|
throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
|
if (ignoreStrictCheck || !TWIG_CALL_BOOLEAN(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "isStrictVariables" TSRMLS_CC)) {
|
||||||
RETURN_FALSE;
|
return;
|
||||||
}
|
|
||||||
if (Z_TYPE_P(object) == IS_ARRAY) {
|
|
||||||
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Item \"%s\" for \"Array\" does not exist", item);
|
|
||||||
} else {
|
|
||||||
Z_ADDREF_P(object);
|
|
||||||
convert_to_string_ex(&object);
|
|
||||||
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Item \"%s\" for \"%s\" does not exist", item, Z_STRVAL_P(object));
|
|
||||||
zval_ptr_dtor(&object);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *type_name = zend_zval_type_name(object);
|
||||||
|
Z_ADDREF_P(object);
|
||||||
|
convert_to_string_ex(&object);
|
||||||
|
|
||||||
|
TWIG_RUNTIME_ERROR(template TSRMLS_CC, "Impossible to invoke a method (\"%s\") on a %s variable (\"%s\")", item, type_name, Z_STRVAL_P(object));
|
||||||
|
|
||||||
|
zval_ptr_dtor(&object);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
// get some information about the object
|
|
||||||
$class = get_class($object);
|
$class = get_class($object);
|
||||||
if (!isset(self::$cache[$class])) {
|
|
||||||
$r = new ReflectionClass($class);
|
|
||||||
self::$cache[$class] = array('methods' => array(), 'properties' => array());
|
|
||||||
foreach ($r->getMethods(ReflectionMethod::IS_PUBLIC) as $method) {
|
|
||||||
self::$cache[$class]['methods'][strtolower($method->getName())] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($r->getProperties(ReflectionProperty::IS_PUBLIC) as $property) {
|
|
||||||
self::$cache[$class]['properties'][$property->getName()] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
if (Z_TYPE_P(object) == IS_OBJECT) {
|
char *class_name = NULL;
|
||||||
char *class_name = NULL;
|
zval *tmp_class;
|
||||||
|
|
||||||
class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC);
|
class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC);
|
||||||
tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC);
|
tmp_self_cache = TWIG_GET_STATIC_PROPERTY(template, "cache" TSRMLS_CC);
|
||||||
|
tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
|
||||||
|
|
||||||
if (!TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC)) {
|
if (!tmp_class) {
|
||||||
twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC);
|
twig_add_class_to_cache(tmp_self_cache, object, class_name TSRMLS_CC);
|
||||||
}
|
tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
|
||||||
efree(class_name);
|
|
||||||
}
|
}
|
||||||
|
efree(class_name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// object property
|
// object property
|
||||||
if (Twig_TemplateInterface::METHOD_CALL !== $type) {
|
if (Twig_TemplateInterface::METHOD_CALL !== $type) {
|
||||||
if (isset(self::$cache[$class]['properties'][$item])
|
if (isset($object->$item) || array_key_exists((string) $item, $object)) {
|
||||||
|| isset($object->$item) || array_key_exists($item, $object)
|
|
||||||
) {
|
|
||||||
if ($isDefinedTest) {
|
if ($isDefinedTest) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->env->hasExtension('sandbox')) {
|
if ($this->env->hasExtension('sandbox')) {
|
||||||
$this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
|
$this->env->getExtension('sandbox')->checkPropertyAllowed($object, $item);
|
||||||
}
|
}
|
||||||
@@ -897,42 +923,41 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (strcmp("method", type) != 0) {
|
if (strcmp("method", type) != 0) {
|
||||||
zval *tmp_class, *tmp_properties, *tmp_item;
|
zval *tmp_properties, *tmp_item;
|
||||||
char *class_name = NULL;
|
|
||||||
|
|
||||||
class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC);
|
|
||||||
tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
|
|
||||||
tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC);
|
tmp_properties = TWIG_GET_ARRAY_ELEMENT(tmp_class, "properties", strlen("properties") TSRMLS_CC);
|
||||||
tmp_item = TWIG_GET_ARRAY_ELEMENT(tmp_properties, item, item_len TSRMLS_CC);
|
tmp_item = TWIG_GET_ARRAY_ELEMENT(tmp_properties, item, item_len TSRMLS_CC);
|
||||||
|
|
||||||
efree(class_name);
|
if (tmp_item || TWIG_HAS_PROPERTY(object, zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
|
||||||
|
|
||||||
if (tmp_item || TWIG_HAS_PROPERTY(object, &zitem TSRMLS_CC) || TWIG_HAS_DYNAMIC_PROPERTY(object, item, item_len TSRMLS_CC)) {
|
|
||||||
if (isDefinedTest) {
|
if (isDefinedTest) {
|
||||||
RETURN_TRUE;
|
RETURN_TRUE;
|
||||||
}
|
}
|
||||||
if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
|
if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
|
||||||
TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, &zitem TSRMLS_CC);
|
TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkPropertyAllowed", object, zitem TSRMLS_CC);
|
||||||
}
|
}
|
||||||
if (EG(exception)) {
|
if (EG(exception)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = TWIG_PROPERTY(object, &zitem TSRMLS_CC);
|
ret = TWIG_PROPERTY(object, zitem TSRMLS_CC);
|
||||||
RETURN_ZVAL(ret, 1, 0);
|
RETURN_ZVAL(ret, 1, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
// object method
|
// object method
|
||||||
|
if (!isset(self::$cache[$class]['methods'])) {
|
||||||
|
self::$cache[$class]['methods'] = array_change_key_case(array_flip(get_class_methods($object)));
|
||||||
|
}
|
||||||
|
|
||||||
$lcItem = strtolower($item);
|
$lcItem = strtolower($item);
|
||||||
if (isset(self::$cache[$class]['methods'][$lcItem])) {
|
if (isset(self::$cache[$class]['methods'][$lcItem])) {
|
||||||
$method = $item;
|
$method = (string) $item;
|
||||||
} elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
|
} elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
|
||||||
$method = 'get'.$item;
|
$method = 'get'.$item;
|
||||||
} elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
|
} elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
|
||||||
$method = 'is'.$item;
|
$method = 'is'.$item;
|
||||||
} elseif (isset(self::$cache[$class]['methods']['__call'])) {
|
} elseif (isset(self::$cache[$class]['methods']['__call'])) {
|
||||||
$method = $item;
|
$method = (string) $item;
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
char *lcItem = TWIG_STRTOLOWER(item, item_len);
|
char *lcItem = TWIG_STRTOLOWER(item, item_len);
|
||||||
@@ -940,10 +965,8 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
char *method = NULL;
|
char *method = NULL;
|
||||||
char *tmp_method_name_get;
|
char *tmp_method_name_get;
|
||||||
char *tmp_method_name_is;
|
char *tmp_method_name_is;
|
||||||
zval *tmp_class, *tmp_methods;
|
zval *tmp_methods;
|
||||||
char *class_name = NULL;
|
|
||||||
|
|
||||||
class_name = TWIG_GET_CLASS_NAME(object TSRMLS_CC);
|
|
||||||
lcItem_length = strlen(lcItem);
|
lcItem_length = strlen(lcItem);
|
||||||
tmp_method_name_get = emalloc(4 + lcItem_length);
|
tmp_method_name_get = emalloc(4 + lcItem_length);
|
||||||
tmp_method_name_is = emalloc(3 + lcItem_length);
|
tmp_method_name_is = emalloc(3 + lcItem_length);
|
||||||
@@ -951,9 +974,7 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
sprintf(tmp_method_name_get, "get%s", lcItem);
|
sprintf(tmp_method_name_get, "get%s", lcItem);
|
||||||
sprintf(tmp_method_name_is, "is%s", lcItem);
|
sprintf(tmp_method_name_is, "is%s", lcItem);
|
||||||
|
|
||||||
tmp_class = TWIG_GET_ARRAY_ELEMENT(tmp_self_cache, class_name, strlen(class_name) TSRMLS_CC);
|
|
||||||
tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC);
|
tmp_methods = TWIG_GET_ARRAY_ELEMENT(tmp_class, "methods", strlen("methods") TSRMLS_CC);
|
||||||
efree(class_name);
|
|
||||||
|
|
||||||
if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) {
|
if (TWIG_GET_ARRAY_ELEMENT(tmp_methods, lcItem, lcItem_length TSRMLS_CC)) {
|
||||||
method = item;
|
method = item;
|
||||||
@@ -968,11 +989,14 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
if ($isDefinedTest) {
|
if ($isDefinedTest) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
if ($ignoreStrictCheck || !$this->env->isStrictVariables()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)));
|
|
||||||
|
throw new Twig_Error_Runtime(sprintf('Method "%s" for object "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($isDefinedTest) {
|
if ($isDefinedTest) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1004,7 +1028,7 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
|
if (TWIG_CALL_SB(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "hasExtension", "sandbox" TSRMLS_CC)) {
|
||||||
TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, &zitem TSRMLS_CC);
|
TWIG_CALL_ZZ(TWIG_CALL_S(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getExtension", "sandbox" TSRMLS_CC), "checkMethodAllowed", object, zitem TSRMLS_CC);
|
||||||
}
|
}
|
||||||
if (EG(exception)) {
|
if (EG(exception)) {
|
||||||
efree(tmp_method_name_get);
|
efree(tmp_method_name_get);
|
||||||
@@ -1015,15 +1039,15 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
/*
|
/*
|
||||||
$ret = call_user_func_array(array($object, $method), $arguments);
|
$ret = call_user_func_array(array($object, $method), $arguments);
|
||||||
*/
|
*/
|
||||||
if (Z_TYPE_P(object) == IS_OBJECT) {
|
ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
|
||||||
ret = TWIG_CALL_USER_FUNC_ARRAY(object, method, arguments TSRMLS_CC);
|
free_ret = 1;
|
||||||
free_ret = 1;
|
|
||||||
}
|
|
||||||
efree(tmp_method_name_get);
|
efree(tmp_method_name_get);
|
||||||
efree(tmp_method_name_is);
|
efree(tmp_method_name_is);
|
||||||
efree(lcItem);
|
efree(lcItem);
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
|
// useful when calling a template method from a template
|
||||||
|
// this is not supported but unfortunately heavily used in the Symfony profiler
|
||||||
if ($object instanceof Twig_TemplateInterface) {
|
if ($object instanceof Twig_TemplateInterface) {
|
||||||
return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
|
return $ret === '' ? '' : new Twig_Markup($ret, $this->env->getCharset());
|
||||||
}
|
}
|
||||||
@@ -1033,9 +1057,7 @@ PHP_FUNCTION(twig_template_get_attributes)
|
|||||||
// ret can be null, if e.g. the called method throws an exception
|
// ret can be null, if e.g. the called method throws an exception
|
||||||
if (ret) {
|
if (ret) {
|
||||||
if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {
|
if (TWIG_INSTANCE_OF_USERLAND(object, "Twig_TemplateInterface" TSRMLS_CC)) {
|
||||||
if (Z_STRLEN_P(ret) == 0) {
|
if (Z_STRLEN_P(ret) != 0) {
|
||||||
free_ret = 1;
|
|
||||||
} else {
|
|
||||||
zval *charset = TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getCharset", NULL TSRMLS_CC);
|
zval *charset = TWIG_CALL_USER_FUNC_ARRAY(TWIG_PROPERTY_CHAR(template, "env" TSRMLS_CC), "getCharset", NULL TSRMLS_CC);
|
||||||
TWIG_NEW(return_value, "Twig_Markup", ret, charset TSRMLS_CC);
|
TWIG_NEW(return_value, "Twig_Markup", ret, charset TSRMLS_CC);
|
||||||
zval_ptr_dtor(&charset);
|
zval_ptr_dtor(&charset);
|
||||||
|
|||||||
+15
-13
@@ -336,21 +336,21 @@ abstract class Twig_Template implements Twig_TemplateInterface
|
|||||||
*/
|
*/
|
||||||
protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
|
protected function getAttribute($object, $item, array $arguments = array(), $type = Twig_TemplateInterface::ANY_CALL, $isDefinedTest = false, $ignoreStrictCheck = false)
|
||||||
{
|
{
|
||||||
$item = ctype_digit((string) $item) ? (int) $item : (string) $item;
|
|
||||||
|
|
||||||
// array
|
// array
|
||||||
if (Twig_TemplateInterface::METHOD_CALL !== $type) {
|
if (Twig_TemplateInterface::METHOD_CALL !== $type) {
|
||||||
if ((is_array($object) && array_key_exists($item, $object))
|
$arrayItem = is_bool($item) || is_float($item) ? (int) $item : $item;
|
||||||
|| ($object instanceof ArrayAccess && isset($object[$item]))
|
|
||||||
|
if ((is_array($object) && array_key_exists($arrayItem, $object))
|
||||||
|
|| ($object instanceof ArrayAccess && isset($object[$arrayItem]))
|
||||||
) {
|
) {
|
||||||
if ($isDefinedTest) {
|
if ($isDefinedTest) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $object[$item];
|
return $object[$arrayItem];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Twig_TemplateInterface::ARRAY_CALL === $type) {
|
if (Twig_TemplateInterface::ARRAY_CALL === $type || !is_object($object)) {
|
||||||
if ($isDefinedTest) {
|
if ($isDefinedTest) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -360,11 +360,13 @@ abstract class Twig_Template implements Twig_TemplateInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_object($object)) {
|
if (is_object($object)) {
|
||||||
throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $item, get_class($object)), -1, $this->getTemplateName());
|
throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
|
||||||
} elseif (is_array($object)) {
|
} elseif (is_array($object)) {
|
||||||
throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $item, implode(', ', array_keys($object))), -1, $this->getTemplateName());
|
throw new Twig_Error_Runtime(sprintf('Key "%s" for array with keys "%s" does not exist', $arrayItem, implode(', ', array_keys($object))), -1, $this->getTemplateName());
|
||||||
|
} elseif (Twig_TemplateInterface::ARRAY_CALL === $type) {
|
||||||
|
throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
|
||||||
} else {
|
} else {
|
||||||
throw new Twig_Error_Runtime(sprintf('Impossible to access a key ("%s") on a "%s" variable', $item, gettype($object)), -1, $this->getTemplateName());
|
throw new Twig_Error_Runtime(sprintf('Impossible to access an attribute ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -378,14 +380,14 @@ abstract class Twig_Template implements Twig_TemplateInterface
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Twig_Error_Runtime(sprintf('Item "%s" for "%s" does not exist', $item, is_array($object) ? 'Array' : $object), -1, $this->getTemplateName());
|
throw new Twig_Error_Runtime(sprintf('Impossible to invoke a method ("%s") on a %s variable ("%s")', $item, gettype($object), $object), -1, $this->getTemplateName());
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = get_class($object);
|
$class = get_class($object);
|
||||||
|
|
||||||
// object property
|
// object property
|
||||||
if (Twig_TemplateInterface::METHOD_CALL !== $type) {
|
if (Twig_TemplateInterface::METHOD_CALL !== $type) {
|
||||||
if (isset($object->$item) || array_key_exists($item, $object)) {
|
if (isset($object->$item) || array_key_exists((string) $item, $object)) {
|
||||||
if ($isDefinedTest) {
|
if ($isDefinedTest) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -405,13 +407,13 @@ abstract class Twig_Template implements Twig_TemplateInterface
|
|||||||
|
|
||||||
$lcItem = strtolower($item);
|
$lcItem = strtolower($item);
|
||||||
if (isset(self::$cache[$class]['methods'][$lcItem])) {
|
if (isset(self::$cache[$class]['methods'][$lcItem])) {
|
||||||
$method = $item;
|
$method = (string) $item;
|
||||||
} elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
|
} elseif (isset(self::$cache[$class]['methods']['get'.$lcItem])) {
|
||||||
$method = 'get'.$item;
|
$method = 'get'.$item;
|
||||||
} elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
|
} elseif (isset(self::$cache[$class]['methods']['is'.$lcItem])) {
|
||||||
$method = 'is'.$item;
|
$method = 'is'.$item;
|
||||||
} elseif (isset(self::$cache[$class]['methods']['__call'])) {
|
} elseif (isset(self::$cache[$class]['methods']['__call'])) {
|
||||||
$method = $item;
|
$method = (string) $item;
|
||||||
} else {
|
} else {
|
||||||
if ($isDefinedTest) {
|
if ($isDefinedTest) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -34,19 +34,22 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
$template->render($context);
|
$template->render($context);
|
||||||
|
$this->fail('Accessing an invalid attribute should throw an exception.');
|
||||||
} catch (Twig_Error_Runtime $e) {
|
} catch (Twig_Error_Runtime $e) {
|
||||||
$this->assertEquals(sprintf($message, $name), $e->getMessage());
|
$this->assertSame(sprintf($message, $name), $e->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getAttributeExceptions()
|
public function getAttributeExceptions()
|
||||||
{
|
{
|
||||||
$tests = array(
|
$tests = array(
|
||||||
array('{{ string["a"] }}', 'Impossible to access a key ("a") on a "string" variable in "%s" at line 1', false),
|
array('{{ string["a"] }}', 'Impossible to access a key ("a") on a string variable ("foo") in "%s" at line 1', false),
|
||||||
array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
|
array('{{ array["a"] }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
|
||||||
array('{{ array_access["a"] }}', 'Key "a" in object (with ArrayAccess) of type "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
|
array('{{ array_access["a"] }}', 'Key "a" in object (with ArrayAccess) of type "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
|
||||||
array('{{ string.a }}', 'Item "a" for "foo" does not exist in "%s" at line 1', false),
|
array('{{ string.a }}', 'Impossible to access an attribute ("a") on a string variable ("foo") in "%s" at line 1', false),
|
||||||
array('{{ array.a }}', 'Item "a" for "Array" does not exist in "%s" at line 1', false),
|
array('{{ string.a() }}', 'Impossible to invoke a method ("a") on a string variable ("foo") in "%s" at line 1', false),
|
||||||
|
array('{{ array.a }}', 'Key "a" for array with keys "foo" does not exist in "%s" at line 1', false),
|
||||||
|
array('{{ attribute(array, -10) }}', 'Key "-10" for array with keys "foo" does not exist in "%s" at line 1', false),
|
||||||
array('{{ array_access.a }}', 'Method "a" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
|
array('{{ array_access.a }}', 'Method "a" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
|
||||||
array('{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ _self.foo(array_access) }}', 'Method "missing_method" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
|
array('{% macro foo(obj) %}{{ obj.missing_method() }}{% endmacro %}{{ _self.foo(array_access) }}', 'Method "missing_method" for object "Twig_TemplateArrayAccessObject" does not exist in "%s" at line 1', false),
|
||||||
);
|
);
|
||||||
@@ -139,6 +142,46 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
|
|||||||
return $bools;
|
return $bools;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider getTestsDependingOnExtensionAvailability
|
||||||
|
*/
|
||||||
|
public function testGetAttributeOnArrayWithConfusableKey($useExt = false)
|
||||||
|
{
|
||||||
|
$template = new Twig_TemplateTest(
|
||||||
|
new Twig_Environment(),
|
||||||
|
$useExt
|
||||||
|
);
|
||||||
|
|
||||||
|
$array = array('Zero', 'One', -1 => 'MinusOne', '' => 'EmptyString', '1.5' => 'FloatButString', '01' => 'IntegerButStringWithLeadingZeros');
|
||||||
|
|
||||||
|
$this->assertSame('Zero', $array[false]);
|
||||||
|
$this->assertSame('One', $array[true]);
|
||||||
|
$this->assertSame('One', $array[1.5]);
|
||||||
|
$this->assertSame('One', $array['1']);
|
||||||
|
$this->assertSame('MinusOne', $array[-1.5]);
|
||||||
|
$this->assertSame('FloatButString', $array['1.5']);
|
||||||
|
$this->assertSame('IntegerButStringWithLeadingZeros', $array['01']);
|
||||||
|
$this->assertSame('EmptyString', $array[null]);
|
||||||
|
|
||||||
|
$this->assertSame('Zero', $template->getAttribute($array, false), 'false is treated as 0 when accessing an array (equals PHP behavior)');
|
||||||
|
$this->assertSame('One', $template->getAttribute($array, true), 'true is treated as 1 when accessing an array (equals PHP behavior)');
|
||||||
|
$this->assertSame('One', $template->getAttribute($array, 1.5), 'float is casted to int when accessing an array (equals PHP behavior)');
|
||||||
|
$this->assertSame('One', $template->getAttribute($array, '1'), '"1" is treated as integer 1 when accessing an array (equals PHP behavior)');
|
||||||
|
$this->assertSame('MinusOne', $template->getAttribute($array, -1.5), 'negative float is casted to int when accessing an array (equals PHP behavior)');
|
||||||
|
$this->assertSame('FloatButString', $template->getAttribute($array, '1.5'), '"1.5" is treated as-is when accessing an array (equals PHP behavior)');
|
||||||
|
$this->assertSame('IntegerButStringWithLeadingZeros', $template->getAttribute($array, '01'), '"01" is treated as-is when accessing an array (equals PHP behavior)');
|
||||||
|
$this->assertSame('EmptyString', $template->getAttribute($array, null), 'null is treated as "" when accessing an array (equals PHP behavior)');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTestsDependingOnExtensionAvailability()
|
||||||
|
{
|
||||||
|
if (function_exists('twig_template_get_attributes')) {
|
||||||
|
return array(array(false), array(true));
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(array(false));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @dataProvider getGetAttributeTests
|
* @dataProvider getGetAttributeTests
|
||||||
*/
|
*/
|
||||||
@@ -199,6 +242,8 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
|
|||||||
'null' => null,
|
'null' => null,
|
||||||
'1' => 1,
|
'1' => 1,
|
||||||
'bar' => true,
|
'bar' => true,
|
||||||
|
'09' => '09',
|
||||||
|
'+4' => '+4',
|
||||||
);
|
);
|
||||||
|
|
||||||
$objectArray = new Twig_TemplateArrayAccessObject();
|
$objectArray = new Twig_TemplateArrayAccessObject();
|
||||||
@@ -224,6 +269,8 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
|
|||||||
array(true, 1, 1.0),
|
array(true, 1, 1.0),
|
||||||
array(true, null, 'null'),
|
array(true, null, 'null'),
|
||||||
array(true, true, 'bar'),
|
array(true, true, 'bar'),
|
||||||
|
array(true, '09', '09'),
|
||||||
|
array(true, '+4', '+4'),
|
||||||
);
|
);
|
||||||
$testObjects = array(
|
$testObjects = array(
|
||||||
// array(object, type of fetch)
|
// array(object, type of fetch)
|
||||||
@@ -243,6 +290,10 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
|
|||||||
foreach ($basicTests as $test) {
|
foreach ($basicTests as $test) {
|
||||||
// properties cannot be numbers
|
// properties cannot be numbers
|
||||||
if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) {
|
if (($testObject[0] instanceof stdClass || $testObject[0] instanceof Twig_TemplatePropertyObject) && is_numeric($test[2])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('+4' === $test[2] && $methodObject === $testObject[0]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,9 +344,9 @@ class Twig_Tests_TemplateTest extends PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
// tests when input is not an array or object
|
// tests when input is not an array or object
|
||||||
$tests = array_merge($tests, array(
|
$tests = array_merge($tests, array(
|
||||||
array(false, null, 42, 'a', array(), $anyType, false, 'Item "a" for "42" does not exist'),
|
array(false, null, 42, 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a integer variable ("42")'),
|
||||||
array(false, null, "string", 'a', array(), $anyType, false, 'Item "a" for "string" does not exist'),
|
array(false, null, "string", 'a', array(), $anyType, false, 'Impossible to access an attribute ("a") on a string variable ("string")'),
|
||||||
array(false, null, array(), 'a', array(), $anyType, false, 'Item "a" for "Array" does not exist'),
|
array(false, null, array(), 'a', array(), $anyType, false, 'Key "a" for array with keys "" does not exist'),
|
||||||
));
|
));
|
||||||
|
|
||||||
// add twig_template_get_attributes tests
|
// add twig_template_get_attributes tests
|
||||||
@@ -380,6 +431,8 @@ class Twig_TemplateArrayAccessObject implements ArrayAccess
|
|||||||
'null' => null,
|
'null' => null,
|
||||||
'1' => 1,
|
'1' => 1,
|
||||||
'bar' => true,
|
'bar' => true,
|
||||||
|
'09' => '09',
|
||||||
|
'+4' => '+4',
|
||||||
);
|
);
|
||||||
|
|
||||||
public function offsetExists($name)
|
public function offsetExists($name)
|
||||||
@@ -410,6 +463,8 @@ class Twig_TemplateMagicPropertyObject
|
|||||||
'null' => null,
|
'null' => null,
|
||||||
'1' => 1,
|
'1' => 1,
|
||||||
'bar' => true,
|
'bar' => true,
|
||||||
|
'09' => '09',
|
||||||
|
'+4' => '+4',
|
||||||
);
|
);
|
||||||
|
|
||||||
protected $protected = 'protected';
|
protected $protected = 'protected';
|
||||||
@@ -478,6 +533,11 @@ class Twig_TemplateMethodObject
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get09()
|
||||||
|
{
|
||||||
|
return '09';
|
||||||
|
}
|
||||||
|
|
||||||
public function getZero()
|
public function getZero()
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user