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);