Skip to content

Commit 3d0f9f2

Browse files
fix: Parser - Equal key name replace conflict (#9246)
* Parse equal key name replace * fix: parsing equal key name replace for parser * improved code readability Co-authored-by: Mostafa Khudair <[email protected]> * updated changelog --------- Co-authored-by: Mostafa Khudair <[email protected]>
1 parent caf4d53 commit 3d0f9f2

File tree

3 files changed

+68
-7
lines changed

3 files changed

+68
-7
lines changed

system/View/Parser.php

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -254,20 +254,39 @@ protected function parse(string $template, array $data = [], ?array $options = n
254254
// it can potentially modify any template between its tags.
255255
$template = $this->parsePlugins($template);
256256

257-
// loop over the data variables, replacing
258-
// the content as we go.
257+
// Parse stack for each parse type (Single and Pairs)
258+
$replaceSingleStack = [];
259+
$replacePairsStack = [];
260+
261+
// loop over the data variables, saving regex and data
262+
// for later replacement.
259263
foreach ($data as $key => $val) {
260264
$escape = true;
261265

262266
if (is_array($val)) {
263-
$escape = false;
264-
$replace = $this->parsePair($key, $val, $template);
267+
$escape = false;
268+
$replacePairsStack[] = [
269+
'replace' => $this->parsePair($key, $val, $template),
270+
'escape' => $escape,
271+
];
265272
} else {
266-
$replace = $this->parseSingle($key, (string) $val);
273+
$replaceSingleStack[] = [
274+
'replace' => $this->parseSingle($key, (string) $val),
275+
'escape' => $escape,
276+
];
267277
}
278+
}
279+
280+
// Merge both stacks, pairs first + single stacks
281+
// This allows for nested data with the same key to be replaced properly
282+
$replace = array_merge($replacePairsStack, $replaceSingleStack);
268283

269-
foreach ($replace as $pattern => $content) {
270-
$template = $this->replaceSingle($pattern, $content, $template, $escape);
284+
// Loop over each replace array item which
285+
// holds all the data to be replaced
286+
foreach ($replace as $replaceItem) {
287+
// Loop over the actual data to be replaced
288+
foreach ($replaceItem['replace'] as $pattern => $content) {
289+
$template = $this->replaceSingle($pattern, $content, $template, $replaceItem['escape']);
271290
}
272291
}
273292

tests/system/View/ParserTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,4 +1061,44 @@ public function testChangeConditionalDelimitersWorkWithJavaScriptCode(): void
10611061
EOL;
10621062
$this->assertSame($expected, $this->parser->renderString($template));
10631063
}
1064+
1065+
/**
1066+
* @see https://github.com/codeigniter4/CodeIgniter4/issues/9245
1067+
*/
1068+
public function testParseSameArrayKeyName(): void
1069+
{
1070+
$data = [
1071+
'type' => 'Super Powers',
1072+
'powers' => [
1073+
[
1074+
'type' => 'invisibility',
1075+
],
1076+
],
1077+
];
1078+
1079+
$template = '{type} like {powers}{type}{/powers}';
1080+
1081+
$this->parser->setData($data);
1082+
$this->assertSame('Super Powers like invisibility', $this->parser->renderString($template));
1083+
}
1084+
1085+
public function testParseSameArrayKeyNameNested(): void
1086+
{
1087+
$data = [
1088+
'title' => 'My title',
1089+
'similar' => [
1090+
['items' => [
1091+
[
1092+
'title' => 'My similar title',
1093+
],
1094+
],
1095+
],
1096+
],
1097+
];
1098+
1099+
$template = '{title} with similar item {similar}{items}{title}{/items}{/similar}';
1100+
1101+
$this->parser->setData($data);
1102+
$this->assertSame('My title with similar item My similar title', $this->parser->renderString($template));
1103+
}
10641104
}

user_guide_src/source/changelogs/v4.5.6.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ Bugs Fixed
3333

3434
- **Validation:** Fixed the `getValidated()` method that did not return valid data when validation rules used multiple asterisks.
3535

36+
- **Parser:** Fixed bug that caused equal key names to be replaced by the key name defined first.
37+
3638
See the repo's
3739
`CHANGELOG.md <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
3840
for a complete list of bugs fixed.

0 commit comments

Comments
 (0)