diff --git a/src/Forms/Select.php b/src/Forms/Select.php new file mode 100644 index 0000000..a3eb455 --- /dev/null +++ b/src/Forms/Select.php @@ -0,0 +1,170 @@ + $options + * @param string|string[] $selected + */ + public static function create( + string|Stringable $label, + string|Stringable $name, + array $options, + string|array $selected = [] + ): self { + return new self($label, $name, $options, $selected); + } + + /** + * @param array $options + * @param string|string[] $selected + */ + final private function __construct( + private readonly string|Stringable $label, + private readonly string|Stringable $name, + private readonly array $options, + private string|array $selected = [] + ) { + } + + public function wrapperProps(string ...$propperties): self + { + $this->wrapperProperties = $propperties; + return $this; + } + + public function dropdown(): self + { + $this->dropdown = true; + $this->checkbox = false; + return $this; + } + + public function radio(): self + { + $this->dropdown = false; + $this->checkbox = false; + return $this; + } + + public function checkbox(): self + { + $this->checkbox = true; + $this->dropdown = false; + return $this; + } + + private function hasSelected(): bool + { + $selected = $this->selected(); + if (is_string($selected) and strlen($selected) > 0) { + return true; + + } elseif (is_array($selected) and count($selected) > 0) { + return true; + + } + return false; + } + + /** + * @return string|string[] + */ + private function selected(): string|array + { + if ($this->checkbox) { + if (is_array($this->selected)) { + return $this->selected; + } + return [$this->selected]; + } + + if (is_array($this->selected) and count($this->selected) > 0) { + return $this->selected[0]; + } + return $this->selected; + } + + private function isSelected(string $value): bool + { + if ($this->hasSelected() === false) { + return false; + } + + if (is_array($this->selected())) { + return in_array($value, $this->selected()); + } + return $value === $this->selected(); + } + + public function __toString(): string + { + if ($this->dropdown) { + return (string) $this->selectDropdown(); + } + return (string) $this->selectOther(); + } + + private function selectDropdown(): Element + { + $elements = []; + foreach ($this->options as $value => $content) { + $option = Element::option($content)->props('value ' . $value); + if ($this->isSelected($value)) { + $option = $option->prop('selected selected'); + } + $elements[] = $option; + } + + return Element::div( + Element::label( + $this->label + )->props('for ' . $this->name), + Element::select( + ...$elements + )->props('id ' . $this->name, 'name ' . $this->name) + )->props(...$this->wrapperProperties); + } + + private function selectOther(): Element + { + $elements = []; + $type = 'radio'; + if ($this->checkbox) { + $type = 'checkbox'; + } + foreach ($this->options as $value => $content) { + $id = $this->name . '-' . $value; + $label = Element::label($content)->props('for ' . $id); + $input = Element::input()->omitEndTag()->props( + 'id ' . $id, + 'type ' . $type, + 'value ' . $value + ); + if ($this->isSelected($value)) { + $input = $input->prop('checked checked'); + } + $elements[] = Element::div($input, $label); + } + return Element::fieldset( + Element::legend($this->label), + ...$elements + ); + } +} diff --git a/tests/Forms/SelectTest.php b/tests/Forms/SelectTest.php new file mode 100644 index 0000000..c478a1e --- /dev/null +++ b/tests/Forms/SelectTest.php @@ -0,0 +1,121 @@ +Select your option
+ html; + + $result = (string) Select::create( + 'Select your option', + 'select', + [ + 'value' => 'display', + 'value2' => 'display2' + ], + ['value', 'value2'] + )->checkbox(); + + $this->assertSame($expected, $result); + } + + /** + * @test + */ + public function can_be_radio_buttons(): void // phpcs: ignore + { + $expected = <<Select your option
+ html; + + $result = (string) Select::create( + 'Select your option', + 'select', + [ + 'value' => 'display' + ], + 'value' + )->radio(); + + $this->assertSame($expected, $result); + } + + /** + * @test + */ + public function can_add_properties_to_wrapper(): void // phpcs: ignore + { + $expected = << + html; + + $result = (string) Select::create( + 'Select your option', + 'select', + [ + 'value' => 'display' + ] + )->wrapperProps('id some-id', 'class some-token'); + + $this->assertSame($expected, $result); + } + + /** + * @test + */ + public function can_preselect_option(): void // phpcs:ignore + { + $expected = << + html; + + $result = (string) Select::create( + 'Select your option', + 'select', + [ + 'value' => 'display', + 'value2' => 'display2' + ], + 'value2' + ); + + $this->assertSame($expected, $result); + } + + /** + * @test + */ + public function is_expected_base(): void // phpcs:ignore + { + $expected = << + html; + + $result = (string) Select::create( + 'Select your option', + 'select', + [ + 'value' => 'display' + ] + ); + + $this->assertSame($expected, $result); + } +}