From b33b41815f1671bd902c0b2ace2a571adc2fe044 Mon Sep 17 00:00:00 2001 From: CosDiabos <14842802+CosDiabos@users.noreply.github.com> Date: Wed, 30 Oct 2024 12:27:27 +0100 Subject: [PATCH 1/4] Parse equal key name replace --- system/View/Parser.php | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/system/View/Parser.php b/system/View/Parser.php index 6600b0178369..69445b57d1a8 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -254,20 +254,34 @@ protected function parse(string $template, array $data = [], ?array $options = n // it can potentially modify any template between its tags. $template = $this->parsePlugins($template); - // loop over the data variables, replacing - // the content as we go. + // Parse stack for each parse type (Single and Pairs) + $replaceSingleStack = []; + $replacePairsStack = []; + + // loop over the data variables, saving regex and data + // for later replacement. foreach ($data as $key => $val) { $escape = true; if (is_array($val)) { $escape = false; - $replace = $this->parsePair($key, $val, $template); + array_push($replacePairsStack, ['replace' => $this->parsePair($key, $val, $template), 'escape' => $escape]); } else { - $replace = $this->parseSingle($key, (string) $val); + array_push($replaceSingleStack, ['replace' => $this->parseSingle($key, (string) $val), 'escape' => $escape]); } + } + + // Merge both stacks, pairs first + single stacks + // This allows for nested data with the same key to be replaced properly + $replace = array_merge($replacePairsStack, $replaceSingleStack); + + // Loop over each replace array item which + // holds all the data to be replaced + foreach ($replace as $replaceItem) { - foreach ($replace as $pattern => $content) { - $template = $this->replaceSingle($pattern, $content, $template, $escape); + // Loop over the actual data to be replaced + foreach ($replaceItem['replace'] as $pattern => $content) { + $template = $this->replaceSingle($pattern, $content, $template, $replaceItem['escape']); } } From a1bc04c1b7a29c87618799c3862cfcd6b98dac7c Mon Sep 17 00:00:00 2001 From: CosDiabos <14842802+CosDiabos@users.noreply.github.com> Date: Thu, 31 Oct 2024 21:27:19 +0100 Subject: [PATCH 2/4] fix: parsing equal key name replace for parser --- system/View/Parser.php | 11 ++++----- tests/system/View/ParserTest.php | 40 ++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/system/View/Parser.php b/system/View/Parser.php index 69445b57d1a8..4d580a35253a 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -256,7 +256,7 @@ protected function parse(string $template, array $data = [], ?array $options = n // Parse stack for each parse type (Single and Pairs) $replaceSingleStack = []; - $replacePairsStack = []; + $replacePairsStack = []; // loop over the data variables, saving regex and data // for later replacement. @@ -264,10 +264,10 @@ protected function parse(string $template, array $data = [], ?array $options = n $escape = true; if (is_array($val)) { - $escape = false; - array_push($replacePairsStack, ['replace' => $this->parsePair($key, $val, $template), 'escape' => $escape]); + $escape = false; + $replacePairsStack[] = ['replace' => $this->parsePair($key, $val, $template), 'escape' => $escape]; } else { - array_push($replaceSingleStack, ['replace' => $this->parseSingle($key, (string) $val), 'escape' => $escape]); + $replaceSingleStack[] = ['replace' => $this->parseSingle($key, (string) $val), 'escape' => $escape]; } } @@ -275,10 +275,9 @@ protected function parse(string $template, array $data = [], ?array $options = n // This allows for nested data with the same key to be replaced properly $replace = array_merge($replacePairsStack, $replaceSingleStack); - // Loop over each replace array item which + // Loop over each replace array item which // holds all the data to be replaced foreach ($replace as $replaceItem) { - // Loop over the actual data to be replaced foreach ($replaceItem['replace'] as $pattern => $content) { $template = $this->replaceSingle($pattern, $content, $template, $replaceItem['escape']); diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php index 9a9f1fd8d0ac..b3c99a2872ce 100644 --- a/tests/system/View/ParserTest.php +++ b/tests/system/View/ParserTest.php @@ -1061,4 +1061,44 @@ public function testChangeConditionalDelimitersWorkWithJavaScriptCode(): void EOL; $this->assertSame($expected, $this->parser->renderString($template)); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/9245 + */ + public function testParseSameArrayKeyName(): void + { + $data = [ + 'type' => 'Super Powers', + 'powers' => [ + [ + 'type' => 'invisibility', + ], + ], + ]; + + $template = '{type} like {powers}{type}{/powers}'; + + $this->parser->setData($data); + $this->assertSame('Super Powers like invisibility', $this->parser->renderString($template)); + } + + public function testParseSameArrayKeyNameNested(): void + { + $data = [ + 'title' => 'My title', + 'similar' => [ + ['items' => [ + [ + 'title' => 'My similar title', + ], + ], + ], + ], + ]; + + $template = '{title} with similar item {similar}{items}{title}{/items}{/similar}'; + + $this->parser->setData($data); + $this->assertSame('My title with similar item My similar title', $this->parser->renderString($template)); + } } From e1631efeb59f9ee5615e5a8ca96528dd28f6e3bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9ssica=20Pereira?= <14842802+CosDiabos@users.noreply.github.com> Date: Fri, 1 Nov 2024 15:46:27 +0100 Subject: [PATCH 3/4] improved code readability Co-authored-by: Mostafa Khudair <59371810+mostafakhudair@users.noreply.github.com> --- system/View/Parser.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/system/View/Parser.php b/system/View/Parser.php index 4d580a35253a..8a26cf825d3f 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -265,9 +265,15 @@ protected function parse(string $template, array $data = [], ?array $options = n if (is_array($val)) { $escape = false; - $replacePairsStack[] = ['replace' => $this->parsePair($key, $val, $template), 'escape' => $escape]; + $replacePairsStack[] = [ + 'replace' => $this->parsePair($key, $val, $template), + 'escape' => $escape, + ]; } else { - $replaceSingleStack[] = ['replace' => $this->parseSingle($key, (string) $val), 'escape' => $escape]; + $replaceSingleStack[] = [ + 'replace' => $this->parseSingle($key, (string) $val), + 'escape' => $escape, + ]; } } From 35c92511acb30f7c9e091e74ecc062b64c83a8ff Mon Sep 17 00:00:00 2001 From: CosDiabos <14842802+CosDiabos@users.noreply.github.com> Date: Sat, 2 Nov 2024 18:36:14 +0100 Subject: [PATCH 4/4] updated changelog --- user_guide_src/source/changelogs/v4.5.6.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.5.6.rst b/user_guide_src/source/changelogs/v4.5.6.rst index b982f54b38f7..c2f396627442 100644 --- a/user_guide_src/source/changelogs/v4.5.6.rst +++ b/user_guide_src/source/changelogs/v4.5.6.rst @@ -33,6 +33,8 @@ Bugs Fixed - **Validation:** Fixed the `getValidated()` method that did not return valid data when validation rules used multiple asterisks. +- **Parser:** Fixed bug that caused equal key names to be replaced by the key name defined first. + See the repo's `CHANGELOG.md `_ for a complete list of bugs fixed.