diff --git a/src/Contracts/Element.php b/src/Contracts/Element.php index fd37eda..02227d6 100644 --- a/src/Contracts/Element.php +++ b/src/Contracts/Element.php @@ -6,6 +6,14 @@ interface Element { public function __construct(array $options = []); + public function setOptions(array $options): Element; + + public function getOptions(): array; + + public function isValid(): bool; + + public function resolve(): Element; + public function render(): string; public function toString(): string; diff --git a/src/Elements/BladeElement.php b/src/Elements/BladeElement.php index afce8e9..2cd920e 100644 --- a/src/Elements/BladeElement.php +++ b/src/Elements/BladeElement.php @@ -9,6 +9,8 @@ abstract class BladeElement extends Element { public function render(): string { + $this->resolve(); + return $this->getEngine()->make(implode('.', array_filter([ $this->getPath(), $this->name, diff --git a/src/Elements/Element.php b/src/Elements/Element.php index e0627ce..7561aa3 100644 --- a/src/Elements/Element.php +++ b/src/Elements/Element.php @@ -3,6 +3,7 @@ namespace Curlyspoon\Core\Elements; use Curlyspoon\Core\Contracts\Element as ElementContract; +use Exception; use Symfony\Component\OptionsResolver\OptionsResolver; abstract class Element implements ElementContract @@ -45,14 +46,26 @@ abstract class Element implements ElementContract */ protected $options = []; + /** + * @var OptionsResolver + */ + protected $resolver; + public function __construct(array $options = []) { $this->setOptions($options); } - public function setOptions(array $options) + public static function make(array $options = []): ElementContract { - $this->options = $this->optionsResolver()->resolve($options); + return new static($options); + } + + public function setOptions(array $options): ElementContract + { + $this->options = $options; + + return $this; } public function getOptions(): array @@ -60,6 +73,24 @@ public function getOptions(): array return $this->options; } + public function resolve(): ElementContract + { + $this->setOptions($this->optionsResolver()->resolve($this->getOptions())); + + return $this; + } + + public function isValid(): bool + { + try { + $this->optionsResolver()->resolve($this->getOptions()); + + return true; + } catch (Exception $exception) { + return false; + } + } + abstract public function render(): string; public function toString(): string @@ -74,23 +105,25 @@ public function __toString(): string protected function optionsResolver(): OptionsResolver { - $resolver = new OptionsResolver(); - $resolver->setDefaults($this->defaults); + if (is_null($this->resolver)) { + $this->resolver = new OptionsResolver(); + $this->resolver->setDefaults($this->defaults); - $resolver->setRequired($this->required); + $this->resolver->setRequired($this->required); - foreach ($this->types as $option => $types) { - $resolver->setAllowedTypes($option, $types); - } + foreach ($this->types as $option => $types) { + $this->resolver->setAllowedTypes($option, $types); + } - foreach ($this->values as $option => $values) { - $resolver->setAllowedValues($option, $values); - } + foreach ($this->values as $option => $values) { + $this->resolver->setAllowedValues($option, $values); + } - if (method_exists($this, 'configureOptions')) { - $this->configureOptions($resolver); + if (method_exists($this, 'configureOptions')) { + $this->configureOptions($this->resolver); + } } - return $resolver; + return $this->resolver; } } diff --git a/src/Elements/PugElement.php b/src/Elements/PugElement.php index bff20ca..73b3fb7 100644 --- a/src/Elements/PugElement.php +++ b/src/Elements/PugElement.php @@ -8,6 +8,8 @@ abstract class PugElement extends Element { public function render(): string { + $this->resolve(); + return $this->getEngine()->renderFile($this->getPath().'/'.$this->name.'.pug', $this->getOptions()); } diff --git a/src/Elements/TwigElement.php b/src/Elements/TwigElement.php index 1d2fae5..d6de22e 100644 --- a/src/Elements/TwigElement.php +++ b/src/Elements/TwigElement.php @@ -9,6 +9,8 @@ abstract class TwigElement extends Element { public function render(): string { + $this->resolve(); + return $this->getEngine()->render($this->name.'.twig', $this->getOptions()); } diff --git a/tests/Elements/Native/Headline.php b/tests/Elements/Native/Headline.php index de66c03..bc46327 100644 --- a/tests/Elements/Native/Headline.php +++ b/tests/Elements/Native/Headline.php @@ -27,6 +27,8 @@ class Headline extends Element public function render(): string { + $this->resolve(); + return sprintf('%s', $this->options['size'], $this->options['text'], $this->options['size']); } } diff --git a/tests/integration/Libs/ElementTest.php b/tests/integration/Libs/ElementTest.php index 28c1b3b..073cc6e 100644 --- a/tests/integration/Libs/ElementTest.php +++ b/tests/integration/Libs/ElementTest.php @@ -13,7 +13,7 @@ public function text_option_is_required() $this->expectException(MissingOptionsException::class); $this->expectExceptionMessage('The required option "text" is missing.'); - new Headline(); + Headline::make()->resolve(); } /** @test */ @@ -32,12 +32,12 @@ public function text_option_does_not_accept_array() $this->expectException(InvalidOptionsException::class); $this->expectExceptionMessage('The option "text" with value array is expected to be of type "string", but is of type "array".'); - new Headline([ + Headline::make([ 'text' => [ 'my', 'headline', ], - ]); + ])->resolve(); } /** @test */ @@ -47,7 +47,7 @@ public function size_option_has_default() 'text' => 'my headline', ]); - $this->assertEquals(1, $headline->getOptions()['size']); + $this->assertEquals(1, $headline->resolve()->getOptions()['size']); } /** @test */ @@ -56,10 +56,10 @@ public function size_option_does_not_accept_zero() $this->expectException(InvalidOptionsException::class); $this->expectExceptionMessage('The option "size" with value 0 is invalid. Accepted values are: 1, 2, 3, 4, 5, 6.'); - new Headline([ + Headline::make([ 'text' => 'my headline', 'size' => 0, - ]); + ])->resolve(); } /** @test */