Skip to content

Commit

Permalink
Add RadioList and CheckboxList classes. (#172)
Browse files Browse the repository at this point in the history
  • Loading branch information
terabytesoftw committed Dec 22, 2023
1 parent fc90d04 commit 0c5272b
Show file tree
Hide file tree
Showing 18 changed files with 929 additions and 10 deletions.
2 changes: 0 additions & 2 deletions src/Attribute/Custom/HasSeparator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
*/
trait HasSeparator
{
protected string $separator = PHP_EOL;

/**
* Set the separator.
*
Expand Down
12 changes: 12 additions & 0 deletions src/Attribute/Input/HasValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@
*/
trait HasValue
{
/**
* Get the value content attribute gives the default value of the field.
*
* @return mixed The value of the widget.
*
* @link https://html.spec.whatwg.org/multipage/input.html#attr-input-value
*/
public function getValue(): mixed
{
return $this->attributes['value'] ?? null;
}

/**
* set the value content attribute gives the default value of the field.
*
Expand Down
2 changes: 1 addition & 1 deletion src/Base/AbstractSelect.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ protected function run(): string
$attributes = $this->attributes;
$multiple = false;
/** @psalm-var array<int, \Stringable|scalar>|scalar|object|null $value */
$value = $attributes['value'] ?? [];
$value = $this->getValue();

$items = match ($this->prompt) {
'' => PHP_EOL . Tag::widget()->content('Select an option')->tagName('option')->render(),
Expand Down
15 changes: 12 additions & 3 deletions src/Input/Base/AbstractChoice.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use InvalidArgumentException;
use PHPForge\Html\Attribute;
use PHPForge\Html\Input\CheckedValueInterface;
use PHPForge\Html\Input\Hidden;
use PHPForge\Html\Input\LabelInterface;
use PHPForge\Html\Label;
Expand All @@ -15,11 +16,12 @@
use function is_iterable;
use function is_object;

abstract class AbstractChoice extends AbstractInput implements LabelInterface
abstract class AbstractChoice extends AbstractInput implements CheckedValueInterface, LabelInterface
{
use Attribute\Custom\HasCheckedValue;
use Attribute\Custom\HasContainer;
use Attribute\Custom\HasLabel;
use Attribute\Custom\HasSeparator;
use Attribute\Custom\HasUnchecked;
use Attribute\Input\CanBeChecked;
use Attribute\Input\CanBeRequired;
Expand All @@ -28,11 +30,12 @@ abstract class AbstractChoice extends AbstractInput implements LabelInterface
protected bool $container = false;
protected string $containerTag = 'div';
protected string $type = '';
protected string $separator = PHP_EOL;

protected function run(): string
{
$attributes = $this->attributes;
$value = $attributes['value'] ?? null;
$value = $this->getValue();

/**
* @link https://www.w3.org/TR/2012/WD-html-markup-20120329/input.checkbox.html#input.checkbox.attrs.value
Expand Down Expand Up @@ -92,7 +95,13 @@ private function renderLabelTag(Tag $inputCheckboxTag): Label|Tag

return Label::widget()
->attributes($this->labelAttributes)
->content(PHP_EOL, $inputCheckboxTag, PHP_EOL, $this->labelContent, PHP_EOL)
->content(
$this->separator,
$inputCheckboxTag,
$this->separator,
$this->labelContent,
$this->separator,
)
->for($inputCheckboxTag->getId());
}
}
114 changes: 114 additions & 0 deletions src/Input/Base/AbstractChoiceList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<?php

declare(strict_types=1);

namespace PHPForge\Html\Input\Base;

use InvalidArgumentException;
use PHPForge\Html\Attribute;
use PHPForge\Html\Input\Checkbox;
use PHPForge\Html\Input\InputInterface;
use PHPForge\Html\Input\LabelInterface;
use PHPForge\Html\Input\Radio;
use PHPForge\Html\Label;
use PHPForge\Html\Tag;
use PHPForge\Widget\Element;

abstract class AbstractChoiceList extends Element implements InputInterface, LabelInterface
{
use Attribute\Aria\HasAriaDescribedBy;
use Attribute\Aria\HasAriaLabel;
use Attribute\CanBeAutofocus;
use Attribute\Custom\HasAttributes;
use Attribute\Custom\HasContainer;
use Attribute\Custom\HasLabel;
use Attribute\Custom\HasSeparator;
use Attribute\HasClass;
use Attribute\HasId;
use Attribute\HasTabindex;
use Attribute\Input\CanBeChecked;
use Attribute\Input\CanBeRequired;
use Attribute\Input\HasName;
use Attribute\Input\HasValue;

protected array $attributes = [];
protected bool $container = true;
protected string $containerTag = 'div';
/**
* @psalm-var Checkbox[]|Radio[] $items
*/
protected array $items = [];
protected string $separator = '';

public function items(Checkbox|Radio ...$items): static
{
$new = clone $this;
$new->items = $items;

return $new;
}

protected function run(): string
{
$attributes = $this->attributes;
$containerAttributes = $this->containerAttributes;
$id = $this->generateId('choice-');
$items = $this->items;
$labelTag = '';
$listItems = [];
$value = $this->getValue();

/**
* @link https://www.w3.org/TR/2012/WD-html-markup-20120329/input.checkbox.html#input.checkbox.attrs.value
*/
if (is_iterable($value) || is_object($value)) {
throw new InvalidArgumentException(
sprintf('%s::class widget must be a scalar value.', static::class)
);
}

unset($attributes['value']);

if (array_key_exists('autofocus', $attributes) && is_bool($attributes['autofocus'])) {
$containerAttributes['autofocus'] = $attributes['autofocus'];

unset($attributes['autofocus']);
}

if (array_key_exists('tabindex', $attributes) && is_int($attributes['tabindex'])) {
$containerAttributes['tabindex'] = $attributes['tabindex'];

unset($attributes['tabindex']);
}

foreach ($items as $item) {
$listItems[] = $item
->attributes($attributes)
->checked($value === $item->getValue())
->id(null)
->separator($this->separator)
->labelFor(null);
}

$listTagItems = implode(PHP_EOL, $listItems);

if ($this->labelContent !== '') {
$labelTag = Label::widget()
->attributes($this->labelAttributes)
->content($this->labelContent)
->for($id)
->render() . PHP_EOL;
}

return match ($this->container) {
true => $labelTag .
Tag::widget()
->attributes($containerAttributes)
->content($listTagItems)
->id($id)
->tagName($this->containerTag)
->render(),
default => $listTagItems,
};
}
}
2 changes: 1 addition & 1 deletion src/Input/Base/AbstractColor.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ abstract class AbstractColor extends AbstractInput
protected function run(): string
{
$attributes = $this->attributes;
$value = $attributes['value'] ?? null;
$value = $this->getValue();

/**
* @link https://www.w3.org/TR/2012/WD-html-markup-20120329/input.color.html#input.color.attrs.value
Expand Down
2 changes: 1 addition & 1 deletion src/Input/Base/AbstractControl.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ abstract class AbstractControl extends AbstractInput
protected function run(): string
{
$attributes = $this->attributes;
$value = $attributes['value'] ?? null;
$value = $this->getValue();

/**
* @link https://www.w3.org/TR/2012/WD-html-markup-20120329/input.date.html#input.date.attrs.value
Expand Down
2 changes: 1 addition & 1 deletion src/Input/Base/AbstractHidden.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ abstract class AbstractHidden extends Element implements HiddenInterface
protected function run(): string
{
$attributes = $this->attributes;
$value = $attributes['value'] ?? null;
$value = $this->getValue();

/**
* @link https://www.w3.org/TR/2012/WD-html-markup-20120329/input.hidden.html#input.hidden.attrs.value
Expand Down
2 changes: 1 addition & 1 deletion src/Input/Base/AbstractText.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ abstract class AbstractText extends AbstractInput implements PlaceholderInterfac
protected function run(): string
{
$attributes = $this->attributes;
$value = $attributes['value'] ?? null;
$value = $this->getValue();

/**
* @link https://www.w3.org/TR/2012/WD-html-markup-20120329/input.text.html#input.text.attrs.value
Expand Down
20 changes: 20 additions & 0 deletions src/Input/CheckedValueInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace PHPForge\Html\Input;

/**
* Provide methods for handling HTML checked value-related attributes and properties.
*/
interface CheckedValueInterface
{
/**
* Set the value that determines when the checkbox should be checked.
*
* @param mixed $checkedValue The value that, when matched with the checkbox value, will mark the checkbox as checked.
*
* @return static Returns a new instance of the class with the updated checked value.
*/
public function checkedValue(mixed $checkedValue): static;
}
14 changes: 14 additions & 0 deletions src/Input/ChoiceList.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace PHPForge\Html\Input;

/*
* Generates a list of checkboxes.
*
* A checkbox or radio list allows many selections.
*/
final class ChoiceList extends Base\AbstractChoiceList
{
}
3 changes: 3 additions & 0 deletions src/Input/RuleHtmlByAttributeInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

namespace PHPForge\Html\Input;

/**
* Provide methods for handling HTML rule-related attributes from validators.
*/
interface RuleHtmlByAttributeInterface
{
}
2 changes: 2 additions & 0 deletions tests/Attribute/Custom/HasSeparatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ public function testImmutability(): void
{
$instance = new class () {
use HasSeparator;

protected string $separator = ',';
};

$this->assertNotSame($instance, $instance->separator('foo'));
Expand Down
11 changes: 11 additions & 0 deletions tests/Attribute/Input/HasValueTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@

final class HasValueTest extends TestCase
{
public function testGetValue(): void
{
$instance = new class () {
use HasValue;

protected array $attributes = ['value' => 'foo'];
};

$this->assertSame('foo', $instance->getValue());
}

public function testImmutability(): void
{
$instance = new class () {
Expand Down

0 comments on commit 0c5272b

Please sign in to comment.