Skip to content

Instantly share code, notes, and snippets.

@poison
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save poison/27e1ffb71fc682ee4ec4 to your computer and use it in GitHub Desktop.
Save poison/27e1ffb71fc682ee4ec4 to your computer and use it in GitHub Desktop.
This patch enables you to loop over structures. See the test for more details
From 84b8814377c18e8ccdc3e6f1e4eb1e9d1828b212 Mon Sep 17 00:00:00 2001
From: Nicolas Van Eenaeme <nicolas@netlog.com>
Date: Tue, 13 May 2014 19:55:18 +0200
Subject: [PATCH] Enabled iteration over objects!
Fixed the test to check for mixed array contents
Added test for new loop
---
blitz.c | 32 +++++++++++++++++++++-----------
tests/loop.phpt | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 69 insertions(+), 11 deletions(-)
create mode 100644 tests/loop.phpt
diff --git a/blitz.c b/blitz.c
index f4d57ab..3f684f7 100644
--- a/blitz.c
+++ b/blitz.c
@@ -1262,11 +1262,11 @@ static inline void blitz_parse_call (char *text, unsigned int len_text, blitz_no
BLITZ_SKIP_BLANK(c,i_pos,pos);
i_len = i_pos = ok = 0;
p = buf;
- BLITZ_SCAN_ALNUM(c,p,i_len,i_symb);
+ BLITZ_SCAN_VAR(c,p,i_len,i_symb,is_path);
if (i_len!=0) {
ok = 1;
pos += i_len;
- ADD_CALL_ARGS(buf, i_len, i_type);
+ ADD_CALL_ARGS(buf, i_len, is_path ? BLITZ_ARG_TYPE_VAR_PATH : i_type);
state = BLITZ_CALL_STATE_FINISHED;
} else {
state = BLITZ_CALL_STATE_ERROR;
@@ -1276,7 +1276,7 @@ static inline void blitz_parse_call (char *text, unsigned int len_text, blitz_no
i_pos = 0;
BLITZ_SKIP_BLANK(c,i_pos,pos); i_pos = 0; symb = *c;
if (BLITZ_IS_ALPHA(symb)) {
- BLITZ_SCAN_ALNUM(c,p,i_pos,i_symb); pos += i_pos; i_pos = 0;
+ BLITZ_SCAN_VAR(c,p,i_pos,i_symb,is_path); pos += i_pos; i_pos = 0;
}
state = BLITZ_CALL_STATE_FINISHED;
break;
@@ -2327,7 +2327,11 @@ static inline unsigned int blitz_fetch_var_by_path(zval ***zparam, const char *l
/* try to get data by the key */
if (0 == root_found) { /* globals or params? */
- root_found = (params && (SUCCESS == zend_hash_find(Z_ARRVAL_P(params), key, key_len + 1, (void **) zparam)));
+ root_found = (params && (
+ (IS_ARRAY == Z_TYPE_P(params) && SUCCESS == zend_hash_find(Z_ARRVAL_P(params), key, key_len + 1, (void **) zparam)) ||
+ (IS_OBJECT == Z_TYPE_P(params) && SUCCESS == zend_hash_find(Z_OBJPROP_P(params), key, key_len + 1, (void **) zparam))
+ ));
+
if (!root_found) {
root_found = (tpl->hash_globals && (SUCCESS == zend_hash_find(tpl->hash_globals, key, key_len + 1, (void**)zparam)));
if (!root_found) {
@@ -2941,7 +2945,8 @@ static void blitz_exec_context(blitz_tpl *tpl, blitz_node *node, zval *parent_pa
char *key = NULL;
unsigned int key_len = 0;
unsigned long key_index = 0;
- int check_key = 0, not_empty = 0;
+ int check_key = 0, not_empty = 0, first_type = -1;
+ long predefined = -1;
zval **ctx_iterations = NULL;
zval **ctx_data = NULL;
call_arg *arg = node->args;
@@ -2962,8 +2967,7 @@ static void blitz_exec_context(blitz_tpl *tpl, blitz_node *node, zval *parent_pa
php_printf("checking key %s in parent_params...\n", arg->name);
}
- check_key = zend_hash_find(Z_ARRVAL_P(parent_params), arg->name, arg->len + 1, (void**)&ctx_iterations);
- if (check_key == FAILURE) {
+ if (blitz_extract_var(tpl, arg->name, arg->len, (arg->type == BLITZ_ARG_TYPE_VAR_PATH), parent_params, &predefined, &ctx_iterations TSRMLS_CC) == 0) {
if (BLITZ_DEBUG) {
php_printf("failed to find key %s in parent params\n", arg->name);
}
@@ -3009,14 +3013,16 @@ static void blitz_exec_context(blitz_tpl *tpl, blitz_node *node, zval *parent_pa
} else if (HASH_KEY_IS_LONG == check_key) {
if (BLITZ_DEBUG) php_printf("KEY_CHECK: %d <long>\n", key_index);
BLITZ_LOOP_INIT(tpl, zend_hash_num_elements(Z_ARRVAL_PP(ctx_iterations)));
+ first_type = -1;
while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(ctx_iterations),(void**) &ctx_data, NULL) == SUCCESS) {
+ if (first_type == -1) first_type = Z_TYPE_PP(ctx_data);
if (BLITZ_DEBUG) {
php_printf("GO subnode, params:\n");
php_var_dump(ctx_data,0 TSRMLS_CC);
}
/* mix of num/str errors: array(0=>array(), 'key' => 'val') */
- if (IS_ARRAY != Z_TYPE_PP(ctx_data)) {
+ if (first_type != Z_TYPE_PP(ctx_data)) {
blitz_error(tpl TSRMLS_CC, E_WARNING,
"ERROR: You have a mix of numerical and non-numerical keys in the iteration set "
"(context: %s, line %lu, pos %lu), key was ignored",
@@ -3066,8 +3072,12 @@ static inline unsigned int blitz_extract_var (
if (is_path) {
return blitz_fetch_var_by_path(z, name, len, params, tpl TSRMLS_CC);
} else {
- if (params && SUCCESS == zend_hash_find(Z_ARRVAL_P(params), name, len_p1, (void**)z)) {
- return 1;
+ if (params) {
+ if (IS_ARRAY == Z_TYPE_P(params) && SUCCESS == zend_hash_find(Z_ARRVAL_P(params), name, len_p1, (void**)z)) {
+ return 1;
+ } else if (IS_OBJECT == Z_TYPE_P(params) && SUCCESS == zend_hash_find(Z_OBJPROP_P(params), name, len_p1, (void**)z)) {
+ return 1;
+ }
}
if (tpl->hash_globals && (SUCCESS == zend_hash_find(tpl->hash_globals, name, len_p1, (void**)z))) {
@@ -3391,7 +3401,7 @@ static int blitz_exec_nodes(blitz_tpl *tpl, blitz_node *first_child,
/* check parent data (once in the beginning) - user could put non-array here. */
/* if we use hash_find on non-array - we get segfaults. */
- if (parent_ctx_data && Z_TYPE_P(parent_ctx_data) == IS_ARRAY) {
+ if (parent_ctx_data && (Z_TYPE_P(parent_ctx_data) == IS_ARRAY || Z_TYPE_P(parent_ctx_data) == IS_OBJECT)) {
parent_params = parent_ctx_data;
}
diff --git a/tests/loop.phpt b/tests/loop.phpt
new file mode 100644
index 0000000..c03aeca
--- /dev/null
+++ b/tests/loop.phpt
@@ -0,0 +1,48 @@
+--TEST--
+looping over struct
+--FILE--
+<?php
+
+include('common.inc');
+ini_set('blitz.remove_spaces_around_context_tags', 1);
+
+$body = <<<BODY
+Hi, I'm {{ user.name }}, and my friends are:
+{{ BEGIN user.friends }}
+ {{ name }}
+{{ END }}
+BODY;
+
+class User {
+ var $name;
+ var $friends;
+
+ function __construct($name) {
+ $this->name = $name;
+ }
+}
+
+$u = new User("Nicolas");
+$u->friends = array(new User("Maurus"), new User("Thibaut"));
+
+$T = new Blitz();
+$T->load($body);
+$T->set(array('user' => $u));
+var_dump($T->getStruct());
+$T->display();
+
+?>
+--EXPECT--
+array(4) {
+ [0]=>
+ string(10) "/user.name"
+ [1]=>
+ string(14) "/user.friends/"
+ [2]=>
+ string(18) "/user.friends/name"
+ [3]=>
+ string(17) "/user.friends/END"
+}
+Hi, I'm Nicolas, and my friends are:
+ Maurus
+ Thibaut
--
1.8.5.2 (Apple Git-48)+GitX
From 3c7cf6c3debe757abe874da76131981442fb9c0a Mon Sep 17 00:00:00 2001
From: Nicolas Van Eenaeme <nicolas@netlog.com>
Date: Wed, 21 May 2014 22:40:37 +0200
Subject: [PATCH] Fix segfault with scope_lookup if the item is an object +
added test
---
blitz.c | 3 ++-
tests/scope3.phpt | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 1 deletion(-)
create mode 100644 tests/scope3.phpt
diff --git a/blitz.c b/blitz.c
index 3f684f7..011c708 100644
--- a/blitz.c
+++ b/blitz.c
@@ -2297,7 +2297,8 @@ static inline int blitz_scope_stack_find(blitz_tpl *tpl, char *key, unsigned lon
while (i <= lookup_limit) {
data = tpl->scope_stack[tpl->scope_stack_pos - i - 1];
- if (SUCCESS == zend_hash_find(Z_ARRVAL_P(data), key, key_len, (void **) zparam)) {
+ if ((IS_ARRAY == Z_TYPE_P(data) && SUCCESS == zend_hash_find(Z_ARRVAL_P(data), key, key_len, (void **) zparam)) ||
+ (IS_OBJECT == Z_TYPE_P(data) && SUCCESS == zend_hash_find(Z_OBJPROP_P(data), key, key_len, (void **) zparam))) {
return i;
}
i++;
diff --git a/tests/scope3.phpt b/tests/scope3.phpt
new file mode 100644
index 0000000..a48449c
--- /dev/null
+++ b/tests/scope3.phpt
@@ -0,0 +1,51 @@
+--TEST--
+scope lookup test #3 (with objects)
+--FILE--
+<?php
+
+$T = new Blitz();
+
+$body = <<<BODY
+{{ BEGIN items }}
+flat variable lookup: {{ \$upper }}
+{{ BEGIN inner }}
+1-level lookup: {{ \$upper }}
+method if with 1-level lookup: {{ if(\$upper, 'OK', 'FAILED') }}
+context if with 1-level lookup: {{ IF \$upper }}OK{{ ELSE }}FAILED{{ END }}
+{{ END inner }}
+{{ END items }}
+===================================================================
+
+BODY;
+
+$T->load($body);
+
+$item = new stdClass();
+$item->upper = 'OK';
+$item->inner = array(
+ 'value' => true
+);
+
+$data = array(
+ 'items' => array(
+ $item
+ )
+);
+
+ini_set('blitz.scope_lookup_limit', 0);
+$T->display($data);
+ini_set('blitz.scope_lookup_limit', 1);
+$T->display($data);
+
+?>
+--EXPECT--
+flat variable lookup: OK
+1-level lookup:
+method if with 1-level lookup: FAILED
+context if with 1-level lookup: FAILED
+===================================================================
+flat variable lookup: OK
+1-level lookup: OK
+method if with 1-level lookup: OK
+context if with 1-level lookup: OK
+===================================================================
--
1.8.5.2 (Apple Git-48)+GitX
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment