Skip to content

Commit

Permalink
Merge pull request tempestphp#323 from tempestphp/elseif-attribute
Browse files Browse the repository at this point in the history
Elseif attribute
  • Loading branch information
brendt authored Aug 13, 2024
2 parents ac0cb13 + ed42d45 commit 4cbf642
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 7 deletions.
1 change: 1 addition & 0 deletions src/Tempest/View/Attributes/AttributeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public function make(View $view, string $name, ?string $value): Attribute
{
return match(true) {
$name === ':if' => new IfAttribute(),
$name === ':elseif' => new ElseIfAttribute(),
$name === ':else' => new ElseAttribute(),
$name === ':foreach' => new ForeachAttribute($view, $value),
$name === ':forelse' => new ForelseAttribute(),
Expand Down
22 changes: 15 additions & 7 deletions src/Tempest/View/Attributes/ElseAttribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,25 @@
public function apply(Element $element): Element
{
$previous = $element->getPrevious();
$previousCondition = false;

if (
! $previous instanceof GenericElement
|| ! $previous->hasAttribute('if')
) {
throw new Exception('No valid if condition found in preceding element');
if (! $previous instanceof GenericElement) {
throw new Exception("Invalid preceding element before :else");
}

$condition = $previous->getAttribute('if');
// Check all :elseif and :if conditions for previous elements
// If one of the previous element's conditions is true, we'll stop.
// We won't have to render this :else element
while (
$previousCondition === false
&& $previous instanceof GenericElement
&& ($previous->hasAttribute('if') || $previous->hasAttribute('elseif'))
) {
$previousCondition = (bool) ($previous->getAttribute('if') ?? $previous->getAttribute('elseif'));
$previous = $previous->getPrevious();
}

if ($condition) {
if ($previousCondition) {
return new EmptyElement();
}

Expand Down
52 changes: 52 additions & 0 deletions src/Tempest/View/Attributes/ElseIfAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

// draft

declare(strict_types=1);

namespace Tempest\View\Attributes;

use Exception;
use Tempest\View\Attribute;
use Tempest\View\Element;
use Tempest\View\Elements\EmptyElement;
use Tempest\View\Elements\GenericElement;

final readonly class ElseIfAttribute implements Attribute
{
public function apply(Element $element): Element
{
if (! $element instanceof GenericElement) {
throw new Exception("Invalid element with :elseif");
}

$previous = $element->getPrevious();
$previousCondition = false;

if (! $previous instanceof GenericElement) {
throw new Exception("Invalid preceding element before :elseif");
}

// Check all :elseif and :if conditions for previous elements
// If one of the previous element's conditions is true, we'll stop.
// We won't have to render this :elseif element
while (
$previousCondition === false
&& $previous instanceof GenericElement
&& ($previous->hasAttribute('if') || $previous->hasAttribute('elseif'))
) {
$previousCondition = (bool) ($previous->getAttribute('if') ?? $previous->getAttribute('elseif'));
$previous = $previous->getPrevious();
}

$currentCondition = (bool) $element->getAttribute('elseif');

// For this element to render, the previous conditions need to be false,
// and the current condition must be true
if ($previousCondition === false && $currentCondition === true) {
return $element;
}

return new EmptyElement();
}
}
38 changes: 38 additions & 0 deletions tests/Integration/View/TempestViewRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,44 @@ public function test_if_attribute(): void
);
}

public function test_elseif_attribute(): void
{
$this->assertSame(
'<div :if="$this->a">A</div>',
$this->render(view('<div :if="$this->a">A</div><div :elseif="$this->b">B</div><div :else>None</div>')->data(a: true, b: true)),
);

$this->assertSame(
'<div :if="$this->a">A</div>',
$this->render(view('<div :if="$this->a">A</div><div :elseif="$this->b">B</div><div :else>None</div>')->data(a: true, b: false)),
);

$this->assertSame(
'<div :elseif="$this->b">B</div>',
$this->render(view('<div :if="$this->a">A</div><div :elseif="$this->b">B</div><div :else>None</div>')->data(a: false, b: true)),
);

$this->assertSame(
'<div :else>None</div>',
$this->render(view('<div :if="$this->a">A</div><div :elseif="$this->b">B</div><div :else>None</div>')->data(a: false, b: false)),
);

$this->assertSame(
'<div :elseif="$this->c">C</div>',
$this->render(view('<div :if="$this->a">A</div><div :elseif="$this->b">B</div><div :elseif="$this->c">C</div><div :else>None</div>')->data(a: false, b: false, c: true)),
);

$this->assertSame(
'<div :elseif="$this->b">B</div>',
$this->render(view('<div :if="$this->a">A</div><div :elseif="$this->b">B</div><div :elseif="$this->c">C</div><div :else>None</div>')->data(a: false, b: true, c: true)),
);

$this->assertSame(
'<div :else>None</div>',
$this->render(view('<div :if="$this->a">A</div><div :elseif="$this->b">B</div><div :elseif="$this->c">C</div><div :else>None</div>')->data(a: false, b: false, c: false)),
);
}

public function test_else_attribute(): void
{
$this->assertSame(
Expand Down

0 comments on commit 4cbf642

Please sign in to comment.