-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c3293ce
commit 0d0f388
Showing
3 changed files
with
779 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
<?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, ! is_int($value)) | ||
|| ($value === '' && in_array(null, $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 $value => $option) { | ||
$option->setDisabled( | ||
in_array($value, $disabledOptions, ! is_int($value)) | ||
|| ($value === '' && in_array(null, $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(); | ||
|
||
return ! is_int($optionValue) | ||
? $this->getValue() === $optionValue | ||
: $this->getValue() == $optionValue; | ||
} | ||
) | ||
->registerAttributeCallback( | ||
'disabled', | ||
function () use ($option) { | ||
return $this->getAttributes()->get('disabled')->getValue() || $option->isDisabled(); | ||
} | ||
); | ||
|
||
$label = new HtmlElement( | ||
'label', | ||
new Attributes(['class' => $option->getLabelCssClass()]), | ||
$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'] | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
<?php | ||
|
||
namespace ipl\Html\FormElement; | ||
|
||
use ipl\Html\Attributes; | ||
|
||
class RadioOption | ||
{ | ||
/** @var string The default label class */ | ||
public const LABEL_CLASS = 'radio-label'; | ||
|
||
/** @var string|int|null 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 = self::LABEL_CLASS; | ||
|
||
/** @var bool Whether the radio option is disabled */ | ||
protected $disabled = false; | ||
|
||
/** @var Attributes */ | ||
protected $attributes; | ||
|
||
/** | ||
* RadioOption constructor. | ||
* | ||
* @param string|int|null $value | ||
* @param string $label | ||
*/ | ||
public function __construct($value, string $label) | ||
{ | ||
$this->value = $value === '' ? null : $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 string|int|null | ||
*/ | ||
public function getValue() | ||
{ | ||
return $this->value; | ||
} | ||
|
||
/** | ||
* Set css class to the option label | ||
* | ||
* @param string|string[] $labelCssClass | ||
* | ||
* @return $this | ||
*/ | ||
public function setLabelCssClass($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; | ||
} | ||
} |
Oops, something went wrong.