Skip to content

Commit

Permalink
fix: Parser - Equal key name replace conflict (#9246)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
CosDiabos and mostafakhudair authored Nov 3, 2024
1 parent caf4d53 commit 3d0f9f2
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 7 deletions.
33 changes: 26 additions & 7 deletions system/View/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -254,20 +254,39 @@ 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);
$escape = false;
$replacePairsStack[] = [
'replace' => $this->parsePair($key, $val, $template),
'escape' => $escape,
];
} else {
$replace = $this->parseSingle($key, (string) $val);
$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);
foreach ($replace as $pattern => $content) {
$template = $this->replaceSingle($pattern, $content, $template, $escape);
// 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']);
}
}
Expand Down
40 changes: 40 additions & 0 deletions tests/system/View/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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));
}
}
2 changes: 2 additions & 0 deletions user_guide_src/source/changelogs/v4.5.6.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 <https://github.com/codeigniter4/CodeIgniter4/blob/develop/CHANGELOG.md>`_
for a complete list of bugs fixed.

0 comments on commit 3d0f9f2

Please sign in to comment.