From cff57f9076dd160b2185895f7298d4acbc5b5bb3 Mon Sep 17 00:00:00 2001 From: javiexin Date: Wed, 28 Dec 2016 12:55:26 +0100 Subject: [PATCH 1/4] [ticket/14944] Add possibility to search for template loop indexes by key Adds a new function to the template interface, and implements it in the context class. The function returns the ordinal index for a specified key, with the same structure that the key for alter_block_array. Reuses same code. PHPBB3-14944 --- phpBB/phpbb/template/base.php | 8 ++++ phpBB/phpbb/template/context.php | 71 +++++++++++++++++++++++++++++++ phpBB/phpbb/template/template.php | 17 ++++++++ 3 files changed, 96 insertions(+) diff --git a/phpBB/phpbb/template/base.php b/phpBB/phpbb/template/base.php index 9a40702ba8..bc0f022cc4 100644 --- a/phpBB/phpbb/template/base.php +++ b/phpBB/phpbb/template/base.php @@ -132,6 +132,14 @@ abstract class base implements template return $this->context->alter_block_array($blockname, $vararray, $key, $mode); } + /** + * {@inheritdoc} + */ + public function find_key_index($blockname, $key = false) + { + return $this->context->find_key_index($blockname, $key); + } + /** * Calls hook if any is defined. * diff --git a/phpBB/phpbb/template/context.php b/phpBB/phpbb/template/context.php index 4ee48205c8..e390c5a677 100644 --- a/phpBB/phpbb/template/context.php +++ b/phpBB/phpbb/template/context.php @@ -263,6 +263,77 @@ class context return true; } + /** + * Find the index for a specified key in the innermost specified block + * + * @param string $blockname the blockname, for example 'loop' + * @param mixed $key Key to search for + * + * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] + * + * int: Position [the position to search for] + * + * If key is false the position is set to 0 + * If key is true the position is set to the last entry + * + * @return mixed false if not found, index position otherwise; be sure to test with === + */ + public function find_key_index($blockname, $key = false) + { + // For nested block, $blockcount > 0, for top-level block, $blockcount == 0 + $blocks = explode('.', $blockname); + $blockcount = sizeof($blocks) - 1; + + $block = &$this->tpldata; + for ($i = 0; $i < $blockcount; $i++) + { + if (($pos = strpos($blocks[$i], '[')) !== false) + { + $name = substr($blocks[$i], 0, $pos); + + if (strpos($blocks[$i], '[]') === $pos) + { + $index = sizeof($block[$name]) - 1; + } + else + { + $index = min((int) substr($blocks[$i], $pos + 1, -1), sizeof($block[$name]) - 1); + } + } + else + { + $name = $blocks[$i]; + $index = sizeof($block[$name]) - 1; + } + $block = &$block[$name]; + $block = &$block[$index]; + } + + $block = &$block[$blocks[$i]]; // Traverse the last block + + // Change key to zero (change first position) if false and to last position if true + if ($key === false || $key === true) + { + return ($key === false) ? 0 : sizeof($block); + } + + // Get correct position if array given + if (is_array($key)) + { + // Search array to get correct position + list($search_key, $search_value) = @each($key); + foreach ($block as $i => $val_ary) + { + if ($val_ary[$search_key] === $search_value) + { + return $i; + } + } + } + + return false; + } + /** * Change already assigned key variable pair (one-dimensional - single loop entry) * diff --git a/phpBB/phpbb/template/template.php b/phpBB/phpbb/template/template.php index 041ecb12e4..b5a6ab32dc 100644 --- a/phpBB/phpbb/template/template.php +++ b/phpBB/phpbb/template/template.php @@ -172,6 +172,23 @@ interface template */ public function alter_block_array($blockname, array $vararray, $key = false, $mode = 'insert'); + /** + * Find the index for a specified key in the innermost specified block + * + * @param string $blockname the blockname, for example 'loop' + * @param mixed $key Key to search for + * + * array: KEY => VALUE [the key/value pair to search for within the loop to determine the correct position] + * + * int: Position [the position to search for] + * + * If key is false the position is set to 0 + * If key is true the position is set to the last entry + * + * @return mixed false if not found, index position otherwise; be sure to test with === + */ + public function find_key_index($blockname, $key = false); + /** * Get path to template for handle (required for BBCode parser) * From c656bd60ef99218a710882b6f640fea099e9c6e2 Mon Sep 17 00:00:00 2001 From: javiexin Date: Fri, 30 Dec 2016 18:03:09 +0100 Subject: [PATCH 2/4] [ticket/14944] Add possibility to search for template loop indexes by key Adds a new function to the template interface, and implements it in the context class. The function returns the ordinal index for a specified key, with the same structure that the key for alter_block_array. Reuses same code. Remove unneeded references, do nothing for int keys. PHPBB3-14944 --- phpBB/phpbb/template/context.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/phpBB/phpbb/template/context.php b/phpBB/phpbb/template/context.php index e390c5a677..1617ca3d19 100644 --- a/phpBB/phpbb/template/context.php +++ b/phpBB/phpbb/template/context.php @@ -284,7 +284,7 @@ class context $blocks = explode('.', $blockname); $blockcount = sizeof($blocks) - 1; - $block = &$this->tpldata; + $block = $this->tpldata; for ($i = 0; $i < $blockcount; $i++) { if (($pos = strpos($blocks[$i], '[')) !== false) @@ -305,11 +305,11 @@ class context $name = $blocks[$i]; $index = sizeof($block[$name]) - 1; } - $block = &$block[$name]; - $block = &$block[$index]; + $block = $block[$name]; + $block = $block[$index]; } - $block = &$block[$blocks[$i]]; // Traverse the last block + $block = $block[$blocks[$i]]; // Traverse the last block // Change key to zero (change first position) if false and to last position if true if ($key === false || $key === true) @@ -331,7 +331,7 @@ class context } } - return false; + return is_int($key) ? $key : false; } /** From 20c03cccdde2302412d1e14adda370e7eb57b8e8 Mon Sep 17 00:00:00 2001 From: javiexin Date: Sun, 8 Jan 2017 00:00:47 +0100 Subject: [PATCH 3/4] [ticket/14944] Add possibility to search for template loop indexes by key Adds a new function to the template interface, and implements it in the context class. The function returns the ordinal index for a specified key, with the same structure that the key for alter_block_array. Reuses same code. Remove unneeded references, do nothing for int keys. Check out of bounds or wrong blockname errors. Added tests. PHPBB3-14944 --- phpBB/phpbb/template/context.php | 16 ++++++++++++-- tests/template/template_test.php | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/phpBB/phpbb/template/context.php b/phpBB/phpbb/template/context.php index 1617ca3d19..8bfbd73f1a 100644 --- a/phpBB/phpbb/template/context.php +++ b/phpBB/phpbb/template/context.php @@ -305,16 +305,28 @@ class context $name = $blocks[$i]; $index = sizeof($block[$name]) - 1; } + if (!isset($block[$name])) + { + return false; + } $block = $block[$name]; + if (!isset($block[$index])) + { + return false; + } $block = $block[$index]; } + if (!isset($block[$blocks[$i]])) + { + return false; + } $block = $block[$blocks[$i]]; // Traverse the last block // Change key to zero (change first position) if false and to last position if true if ($key === false || $key === true) { - return ($key === false) ? 0 : sizeof($block); + return ($key === false) ? 0 : sizeof($block) - 1; } // Get correct position if array given @@ -331,7 +343,7 @@ class context } } - return is_int($key) ? $key : false; + return (is_int($key) && ((0 <= $key) && ($key < sizeof($block)))) ? $key : false; } /** diff --git a/tests/template/template_test.php b/tests/template/template_test.php index 0bbfe3848d..33fa4b63a0 100644 --- a/tests/template/template_test.php +++ b/tests/template/template_test.php @@ -603,6 +603,43 @@ EOT $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring S_NUM_ROWS is correct after modification'); } + public function test_find_key_index() + { + $this->template->set_filenames(array('test' => 'loop_nested.html')); + + $this->template->assign_var('TEST_MORE', true); + + // @todo Change this + $this->template->assign_block_vars('outer', array('VARIABLE' => 'zero')); + $this->template->assign_block_vars('outer', array('VARIABLE' => 'one')); + $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '1A')); + $this->template->assign_block_vars('outer', array('VARIABLE' => 'two')); + $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '2A')); + $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '2B')); + $this->template->assign_block_vars('outer', array('VARIABLE' => 'three')); + $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3A')); + $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3B')); + $this->template->assign_block_vars('outer.middle', array('VARIABLE' => '3C')); + + $expect = 'outer - 0 - zero[outer|4]outer - 1 - one[outer|4]middle - 0 - 1A[middle|1]outer - 2 - two[outer|4]middle - 0 - 2A[middle|2]middle - 1 - 2B[middle|2]outer - 3 - three[outer|4]middle - 0 - 3A[middle|3]middle - 1 - 3B[middle|3]middle - 2 - 3C[middle|3]'; + $this->assertEquals($expect, str_replace(array("\n", "\r", "\t"), '', $this->display('test')), 'Ensuring template is built correctly before modification'); + + $this->template->find_key_index('outer', false); + + $this->assertEquals(0, $this->template->find_key_index('outer', false), 'Find index at the beginning of outer loop'); + $this->assertEquals(1, $this->template->find_key_index('outer', 1), 'Find index by index in outer loop'); + $this->assertEquals(2, $this->template->find_key_index('outer', array('VARIABLE' => 'two')), 'Find index by key in outer loop'); + $this->assertEquals(3, $this->template->find_key_index('outer', true), 'Find index at the end of outer loop'); + $this->assertEquals(false, $this->template->find_key_index('outer', 7), 'Find index out of bounds of outer loop'); + + $this->assertEquals(false, $this->template->find_key_index('outer[0].middle', false), 'Find index at the beginning of middle loop, no middle block'); + $this->assertEquals(false, $this->template->find_key_index('outer[1].middle', 1), 'Find index by index in inner loop, out of bounds'); + $this->assertEquals(1, $this->template->find_key_index('outer[2].middle', array('VARIABLE' => '2B')), 'Find index by key in middle loop'); + $this->assertEquals(2, $this->template->find_key_index('outer.middle', true), 'Find index at the end of middle loop'); + + $this->assertEquals(false, $this->template->find_key_index('outer.wrong'), 'Wrong middle block name'); + $this->assertEquals(false, $this->template->find_key_index('wrong.middle'), 'Wrong outer block name'); + } public function assign_block_vars_array_data() { return array( From 849fd9df7d9b2e449801e14ef54584fc8e063d43 Mon Sep 17 00:00:00 2001 From: javiexin Date: Sat, 28 Jan 2017 21:34:08 +0100 Subject: [PATCH 4/4] [ticket/14944] Add possibility to search for template loop indexes by key Adds a new function to the template interface, and implements it in the context class. The function returns the ordinal index for a specified key, with the same structure that the key for alter_block_array. Reuses same code. Remove unneeded references, do nothing for int keys. Check out of bounds or wrong blockname errors. Added tests. Remove default parameter value. PHPBB3-14944 --- phpBB/phpbb/template/base.php | 2 +- phpBB/phpbb/template/context.php | 2 +- phpBB/phpbb/template/template.php | 2 +- tests/template/template_test.php | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/phpBB/phpbb/template/base.php b/phpBB/phpbb/template/base.php index bc0f022cc4..41c0a01ba8 100644 --- a/phpBB/phpbb/template/base.php +++ b/phpBB/phpbb/template/base.php @@ -135,7 +135,7 @@ abstract class base implements template /** * {@inheritdoc} */ - public function find_key_index($blockname, $key = false) + public function find_key_index($blockname, $key) { return $this->context->find_key_index($blockname, $key); } diff --git a/phpBB/phpbb/template/context.php b/phpBB/phpbb/template/context.php index 8bfbd73f1a..e70d0574be 100644 --- a/phpBB/phpbb/template/context.php +++ b/phpBB/phpbb/template/context.php @@ -278,7 +278,7 @@ class context * * @return mixed false if not found, index position otherwise; be sure to test with === */ - public function find_key_index($blockname, $key = false) + public function find_key_index($blockname, $key) { // For nested block, $blockcount > 0, for top-level block, $blockcount == 0 $blocks = explode('.', $blockname); diff --git a/phpBB/phpbb/template/template.php b/phpBB/phpbb/template/template.php index b5a6ab32dc..9e3d658ca8 100644 --- a/phpBB/phpbb/template/template.php +++ b/phpBB/phpbb/template/template.php @@ -187,7 +187,7 @@ interface template * * @return mixed false if not found, index position otherwise; be sure to test with === */ - public function find_key_index($blockname, $key = false); + public function find_key_index($blockname, $key); /** * Get path to template for handle (required for BBCode parser) diff --git a/tests/template/template_test.php b/tests/template/template_test.php index 33fa4b63a0..997da80246 100644 --- a/tests/template/template_test.php +++ b/tests/template/template_test.php @@ -637,8 +637,8 @@ EOT $this->assertEquals(1, $this->template->find_key_index('outer[2].middle', array('VARIABLE' => '2B')), 'Find index by key in middle loop'); $this->assertEquals(2, $this->template->find_key_index('outer.middle', true), 'Find index at the end of middle loop'); - $this->assertEquals(false, $this->template->find_key_index('outer.wrong'), 'Wrong middle block name'); - $this->assertEquals(false, $this->template->find_key_index('wrong.middle'), 'Wrong outer block name'); + $this->assertEquals(false, $this->template->find_key_index('outer.wrong', true), 'Wrong middle block name'); + $this->assertEquals(false, $this->template->find_key_index('wrong.middle', false), 'Wrong outer block name'); } public function assign_block_vars_array_data() {