diff --git a/src/Tempest/View/src/Elements/IsElement.php b/src/Tempest/View/src/Elements/IsElement.php index fb2400225..5e31977e8 100644 --- a/src/Tempest/View/src/Elements/IsElement.php +++ b/src/Tempest/View/src/Elements/IsElement.php @@ -34,21 +34,17 @@ public function getAttributes(): array $attributes = [...$this->attributes, ...$wrappingAttributes]; - // Some attributes should always come after others, - // so that these expressions have access to the data attributes - $attributePrecedence = [ - ':foreach' => 1, - ':if' => 2, - ]; + $tailingAttributes = []; - uksort($attributes, function (string $a, string $b) use ($attributePrecedence) { - $precedenceA = $attributePrecedence[$a] ?? 0; - $precedenceB = $attributePrecedence[$b] ?? 0; - - return $precedenceA <=> $precedenceB; - }); + foreach ($attributes as $name => $value) { + if ($name === ':foreach' || $name === ':if') { + unset($attributes[$name]); + $tailingAttributes[$name] = $value; + } + } - return $attributes; + // Tailing attributes are reversed because they need to be applied in reverse order + return [...$attributes, ...array_reverse($tailingAttributes)]; } public function hasAttribute(string $name): bool diff --git a/tests/Integration/View/TempestViewRendererCombinedExpressionsTest.php b/tests/Integration/View/TempestViewRendererCombinedExpressionsTest.php index 5b5f10b1e..3411de79e 100644 --- a/tests/Integration/View/TempestViewRendererCombinedExpressionsTest.php +++ b/tests/Integration/View/TempestViewRendererCombinedExpressionsTest.php @@ -76,7 +76,7 @@ public function test_foreach_with_if_and_else_expression(): void public function test_foreach_with_if_and_forelse_expression(): void { $view = <<<'HTML' -
+
{{ $label }} {{ $item }}
diff --git a/tests/Integration/View/TempestViewRendererTest.php b/tests/Integration/View/TempestViewRendererTest.php index a16ce0b83..90f60a1f9 100644 --- a/tests/Integration/View/TempestViewRendererTest.php +++ b/tests/Integration/View/TempestViewRendererTest.php @@ -604,6 +604,105 @@ public function test_loop_variable_can_be_used_within_the_looped_tag(): void HTML, $html); } + public function test_if_and_foreach_precedence(): void + { + $html = $this->render( + <<<'HTML' +
{{ $item->name }}
+ HTML, + items: [ + (object) ['name' => 'A', 'show' => true], + (object) ['name' => 'B', 'show' => false], + (object) ['name' => 'C', 'show' => true], + ], + ); + + $this->assertSnippetsMatch('
A
C
', $html); + + $html = $this->render( + <<<'HTML' +
{{ $item->name }}
+ HTML, + show: true, + items: [ + (object) ['name' => 'A', 'show' => true], + (object) ['name' => 'B', 'show' => false], + (object) ['name' => 'C', 'show' => true], + ], + ); + + $this->assertSnippetsMatch('
A
B
C
', $html); + + $html = $this->render( + <<<'HTML' +
{{ $item->name }}
+ HTML, + show: true, + items: [ + (object) ['name' => 'A', 'show' => true], + (object) ['name' => 'B', 'show' => false], + (object) ['name' => 'C', 'show' => true], + ], + ); + + $this->assertSnippetsMatch('
A
B
C
', $html); + + $html = $this->render( + <<<'HTML' +
{{ $item->name }}
+ HTML, + show: false, + items: [ + (object) ['name' => 'A', 'show' => true], + (object) ['name' => 'B', 'show' => false], + (object) ['name' => 'C', 'show' => true], + ], + ); + + $this->assertSnippetsMatch('', $html); + + $html = $this->render( + <<<'HTML' +
{{ $item->name }}
+ HTML, + show: false, + items: [ + (object) ['name' => 'A', 'show' => true], + (object) ['name' => 'B', 'show' => false], + (object) ['name' => 'C', 'show' => true], + ], + ); + + $this->assertSnippetsMatch('', $html); + + $html = $this->render( + <<<'HTML' +
{{ $item->name }}
+ HTML, + item: (object) ['show' => true], + items: [ + (object) ['name' => 'A', 'show' => true], + (object) ['name' => 'B', 'show' => false], + (object) ['name' => 'C', 'show' => true], + ], + ); + + $this->assertSnippetsMatch('
A
B
C
', $html); + + $html = $this->render( + <<<'HTML' +
{{ $item->name }}
+ HTML, + items: [ + (object) ['name' => 'A', 'show' => true], + (object) ['name' => 'B', 'show' => false], + (object) ['name' => 'C', 'show' => true], + ], + ); + + $this->assertSnippetsMatch('', $html); + } + private function assertSnippetsMatch(string $expected, string $actual): void { $expected = str_replace([PHP_EOL, ' '], '', $expected);