Skip to content

Commit

Permalink
FormElement: Add RadioElement
Browse files Browse the repository at this point in the history
  • Loading branch information
sukhwinder33445 committed Nov 28, 2022
1 parent c3293ce commit f307b32
Show file tree
Hide file tree
Showing 3 changed files with 607 additions and 0 deletions.
175 changes: 175 additions & 0 deletions src/FormElement/RadioElement.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<?php

namespace ipl\Html\FormElement;

use InvalidArgumentException;
use ipl\Html\Attributes;
use ipl\Html\HtmlDocument;
use ipl\Html\HtmlElement;
use ipl\Html\Text;
use ipl\I18n\Translation;
use ipl\Validator\DeferredInArrayValidator;
use ipl\Validator\ValidatorChain;

class RadioElement extends BaseFormElement
{
use Translation;

/** @var string The element type */
protected $type = 'radio';

/** @var RadioOption[] Radio options */
protected $options = [];

/** @var array Disabled radio options */
protected $disabledOptions = [];

/**
* Set the options
*
* @param array $options
*
* @return $this
*/
public function setOptions(array $options): self
{
$this->options = [];
foreach ($options as $value => $label) {
$option = (new RadioOption($value, $label))
->setDisabled(in_array($value, $this->disabledOptions, true));

$this->options[$value] = $option;
}

$this->disabledOptions = [];

return $this;
}

/**
* Get the option with specified value
*
* @param string|int $value
*
* @return RadioOption
*
* @throws InvalidArgumentException If no option with the specified value exists
*/
public function getOption($value): RadioOption
{
if (! isset($this->options[$value])) {
throw new InvalidArgumentException(sprintf('There is no such option "%s"', $value));
}

return $this->options[$value];
}

/**
* Set the specified options as disable
*
* @param array $disabledOptions
*
* @return $this
*/
public function setDisabledOptions(array $disabledOptions): self
{
if (! empty($this->options)) {
foreach ($this->options as $option) {
$option->setDisabled(
in_array($option->getValue(), $disabledOptions, true)
);
}

$this->disabledOptions = [];
} else {
$this->disabledOptions = $disabledOptions;
}

return $this;
}

public function renderUnwrapped()
{
// Parent::renderUnwrapped() requires $tag and the content should be empty. However, since we are wrapping
// each button in a label, the call to parent cannot work here and must be overridden.
return HtmlDocument::renderUnwrapped();
}

protected function assemble()
{
foreach ($this->options as $option) {
$radio = (new InputElement($this->getName()))
->setType($this->type)
->setValue($option->getValue());

// Only add the non-callback attributes to all options
foreach ($this->getAttributes() as $attribute) {
$radio->getAttributes()->addAttribute(clone $attribute);
}

$radio->getAttributes()
->merge($option->getAttributes())
->registerAttributeCallback('checked',
function () use ($option) {
$optionValue = $option->getValue();

if ($optionValue === '') {
$optionValue = null;
}
return $this->getValue() === $optionValue;
}
)
->registerAttributeCallback('disabled',
function () use ($option) {
return $this->getAttributes()->get('disabled')->getValue() || $option->isDisabled();
}
);

$labelAttributes = (new Attributes(['class' => RadioOption::LABEL_CLASS]))
->add('class', $option->getlabelCssClass());

$label = new HtmlElement(
'label',
$labelAttributes,
$radio,
Text::create($option->getLabel())
);

$this->addHtml($label);
}
}

protected function addDefaultValidators(ValidatorChain $chain): void
{
$chain->add(new DeferredInArrayValidator(function (): array {
$possibleValues = [];

foreach ($this->options as $option) {
if ($option->isDisabled()) {
continue;
}

$possibleValues[] = $option->getValue();
}

return $possibleValues;
}));
}

protected function registerAttributeCallbacks(Attributes $attributes)
{
parent::registerAttributeCallbacks($attributes);

$this->getAttributes()->registerAttributeCallback(
'options',
null,
[$this, 'setOptions']
);

$this->getAttributes()->registerAttributeCallback(
'disabledOptions',
null,
[$this, 'setDisabledOptions']
);
}
}
148 changes: 148 additions & 0 deletions src/FormElement/RadioOption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<?php

namespace ipl\Html\FormElement;

use ipl\Html\Attribute;
use ipl\Html\Attributes;

class RadioOption
{
public const LABEL_CLASS = 'radio-label';

/** @var string|int Value of the option */
protected $value;

/** @var string Label of the option */
protected $label;

/** @var mixed Css class of the option's label */
protected $labelCssClass;

/** @var bool Whether the radio option is disabled */
protected $disabled = false;

/** @var Attributes */
protected $attributes;

/**
* RadioOption constructor.
*
* @param string|int $value
* @param string $label
*/
public function __construct($value, string $label)
{
$this->value = $value;
$this->label = $label;
}

/**
* Set the label of the option
*
* @param string $label
*
* @return $this
*/
public function setLabel(string $label): self
{
$this->label = $label;

return $this;
}

/**
* Get the label of the option
*
* @return string
*/
public function getLabel(): string
{
return $this->label;
}

/**
* Get the value of the option
*
* @return int|string
*/
public function getValue()
{
return $this->value;
}

/**
* Add css class to the option label
*
* @param string|array|Attribute $labelCssClass
*
* @return $this
*/
public function addLabelCssClass($labelCssClass): self
{
$this->labelCssClass = $labelCssClass;

return $this;
}

/**
* Get css class of the option label
*
* @return string|string[]
*/
public function getLabelCssClass()
{
return $this->labelCssClass;
}

/**
* Set whether to disable the option
*
* @param bool $disabled
*
* @return $this
*/
public function setDisabled(bool $disabled = true): self
{
$this->disabled = $disabled;

return $this;
}

/**
* Get whether the option is disabled
*
* @return bool
*/
public function isDisabled(): bool
{
return $this->disabled;
}

/**
* Add the attributes
*
* @param Attributes $attributes
*
* @return $this
*/
public function addAttributes(Attributes $attributes): self
{
$this->attributes = $attributes;

return $this;
}

/**
* Get the attributes
*
* @return Attributes
*/
public function getAttributes(): Attributes
{
if ($this->attributes === null) {
$this->attributes = new Attributes();
}

return $this->attributes;
}
}

0 comments on commit f307b32

Please sign in to comment.