-
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
239b215
commit b04b6ba
Showing
2 changed files
with
330 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,165 @@ | ||
<?php | ||
|
||
namespace ipl\Html\FormElement; | ||
|
||
use ipl\Html\Attributes; | ||
use ipl\Html\HtmlElement; | ||
use ipl\Html\HtmlString; | ||
use ipl\I18n\Translation; | ||
use ipl\Validator\InArray; | ||
|
||
class RadioElement extends InputElement | ||
{ | ||
use Translation; | ||
|
||
protected $type = 'radio'; | ||
|
||
/** @var InputElement[] Radio button elements */ | ||
protected $options; | ||
|
||
/** @var array Values that are not disabled */ | ||
protected $possibleValues; | ||
|
||
public function __construct($name, $attributes = null) | ||
{ | ||
$this->getAttributes()->registerAttributeCallback( | ||
'options', | ||
null, | ||
[$this, 'setOptions'] | ||
); | ||
|
||
$this->getAttributes()->registerAttributeCallback( | ||
'disableOptions', | ||
null, | ||
[$this, 'disableOptions'] | ||
); | ||
|
||
$this->getAttributes()->registerAttributeCallback( | ||
'disabled', | ||
null, | ||
[$this, 'disableOptions'] | ||
); | ||
|
||
parent::__construct($name, $attributes); | ||
} | ||
|
||
/** | ||
* Disable radio button that contains given value | ||
* | ||
* @param string $value | ||
* | ||
* @return $this | ||
*/ | ||
private function disableOption(string $value): RadioElement | ||
{ | ||
if ($option = $this->getOption($value)) { | ||
$option->setAttribute('disabled', true); | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* Disable radio buttons that contain given values | ||
* | ||
* @param mixed $values array, string or bool (if set to true, all options will be disabled) | ||
* | ||
* @return $this | ||
*/ | ||
public function disableOptions($values): RadioElement | ||
{ | ||
$this->valid = null; | ||
$this->validators = null; // required to add validator with new possibleValues | ||
|
||
if (is_bool($values)) { | ||
$values = $this->possibleValues; | ||
$this->possibleValues = (array) $this->getValue(); | ||
} else { | ||
$values = (array) $values; | ||
$this->possibleValues = array_diff($this->possibleValues, $values); | ||
} | ||
|
||
foreach ($values as $value) { | ||
if ($option = $this->getOption($value)) { | ||
$option->setAttribute('disabled', true); | ||
} | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
/** | ||
* Get radio button with given value | ||
* | ||
* @param string $value | ||
* | ||
* @return InputElement|null | ||
*/ | ||
public function getOption(string $value): ?InputElement | ||
{ | ||
return $this->options[$value] ?? null; | ||
} | ||
|
||
public function setValue($value) | ||
{ | ||
parent::setValue($value); | ||
|
||
foreach ($this->options as $radio) { | ||
$radio->getAttributes()->remove('checked'); | ||
if ($radio->getValueAttribute() === $value) { | ||
$radio->setAttribute('checked', true); | ||
} | ||
} | ||
|
||
return $this; | ||
} | ||
|
||
public function addDefaultValidators() | ||
{ | ||
$this->getValidators()->add(new InArray(['haystack' => $this->possibleValues])); | ||
} | ||
|
||
/** | ||
* Prepare options | ||
* | ||
* @param array $options | ||
* | ||
* @return $this | ||
*/ | ||
public function setOptions(array $options): RadioElement | ||
{ | ||
$this->possibleValues = array_keys($options); | ||
|
||
foreach ($options as $value => $label) { | ||
$input = (new InputElement($this->getName())) | ||
->setType($this->type) | ||
->setValue($value) | ||
->setLabel($label); | ||
|
||
$this->options[$value] = $input; | ||
} | ||
|
||
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 $this->renderContent(); | ||
} | ||
|
||
protected function assemble() | ||
{ | ||
foreach ($this->options as $radioElm) { | ||
$labelElm = new HtmlElement( | ||
'label', | ||
Attributes::create(['class' => 'radio-label']), | ||
$radioElm, | ||
HtmlString::create($radioElm->getLabel()) | ||
); | ||
|
||
$this->addHtml($labelElm); | ||
} | ||
} | ||
} |
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,165 @@ | ||
<?php | ||
|
||
namespace ipl\Tests\Html\FormElement; | ||
|
||
use ipl\Html\FormElement\RadioElement; | ||
use ipl\I18n\NoopTranslator; | ||
use ipl\I18n\StaticTranslator; | ||
use ipl\Tests\Html\TestCase; | ||
|
||
class RadioElementTest extends TestCase | ||
{ | ||
public function testCreateRadioElementsCorrectly() | ||
{ | ||
$radio = new RadioElement('test', [ | ||
'label' => 'Test', | ||
'options' => [ | ||
'foo' => 'Foo', | ||
'bar' => 'Bar', | ||
'yes' => 'Yes' | ||
] | ||
]); | ||
|
||
$html = <<<HTML | ||
<label class="radio-label"><input value="foo" name="test" type="radio">Foo</label> | ||
<label class="radio-label"><input value="bar" name="test" type="radio">Bar</label> | ||
<label class="radio-label"><input value="yes" name="test" type="radio">Yes</label> | ||
HTML; | ||
|
||
$this->assertHtml($html, $radio); | ||
} | ||
|
||
public function testCheckCorrectRadio() | ||
{ | ||
$radio = new RadioElement('test', [ | ||
'label' => 'Test', | ||
'options' => [ | ||
'foo' => 'Foo', | ||
'bar' => 'Bar', | ||
'yes' => 'Yes' | ||
], | ||
'value' => 'bar' | ||
]); | ||
|
||
$html = <<<HTML | ||
<label class="radio-label"><input value="foo" name="test" type="radio">Foo</label> | ||
<label class="radio-label"><input value="bar" name="test" type="radio" checked>Bar</label> | ||
<label class="radio-label"><input value="yes" name="test" type="radio">Yes</label> | ||
HTML; | ||
$this->assertHtml($html, $radio); | ||
|
||
$radio->setValue('yes'); | ||
|
||
$html = <<<HTML | ||
<label class="radio-label"><input value="foo" name="test" type="radio">Foo</label> | ||
<label class="radio-label"><input value="bar" name="test" type="radio">Bar</label> | ||
<label class="radio-label"><input value="yes" name="test" type="radio" checked>Yes</label> | ||
HTML; | ||
$this->assertHtml($html, $radio); | ||
|
||
$radio->setValue('no'); | ||
|
||
$html = <<<HTML | ||
<label class="radio-label"><input value="foo" name="test" type="radio">Foo</label> | ||
<label class="radio-label"><input value="bar" name="test" type="radio">Bar</label> | ||
<label class="radio-label"><input value="yes" name="test" type="radio">Yes</label> | ||
HTML; | ||
$this->assertHtml($html, $radio); | ||
} | ||
|
||
public function testDisableRadioOptions() | ||
{ | ||
$radio = new RadioElement('test', [ | ||
'label' => 'Test', | ||
'options' => [ | ||
'foo' => 'Foo', | ||
'bar' => 'Bar', | ||
'yes' => 'Yes', | ||
'no' => 'No' | ||
], | ||
'value' => 'bar', | ||
'disableOptions' => 'yes' | ||
]); | ||
|
||
$html = <<<HTML | ||
<label class="radio-label"><input value="foo" name="test" type="radio">Foo</label> | ||
<label class="radio-label"><input value="bar" name="test" type="radio" checked>Bar</label> | ||
<label class="radio-label"><input value="yes" name="test" type="radio" disabled>Yes</label> | ||
<label class="radio-label"><input value="no" name="test" type="radio">No</label> | ||
HTML; | ||
$this->assertHtml($html, $radio); | ||
|
||
$radio->disableOptions(['yes', 'no', 'foo']); | ||
|
||
$html = <<<HTML | ||
<label class="radio-label"><input value="foo" name="test" type="radio" disabled>Foo</label> | ||
<label class="radio-label"><input value="bar" name="test" type="radio" checked>Bar</label> | ||
<label class="radio-label"><input value="yes" name="test" type="radio" disabled>Yes</label> | ||
<label class="radio-label"><input value="no" name="test" type="radio" disabled>No</label> | ||
HTML; | ||
$this->assertHtml($html, $radio); | ||
|
||
$radio->disableOptions(true); | ||
|
||
$html = <<<HTML | ||
<label class="radio-label"><input value="foo" name="test" type="radio" disabled>Foo</label> | ||
<label class="radio-label"><input value="bar" name="test" type="radio" checked disabled>Bar</label> | ||
<label class="radio-label"><input value="yes" name="test" type="radio" disabled>Yes</label> | ||
<label class="radio-label"><input value="no" name="test" type="radio" disabled>No</label> | ||
HTML; | ||
$this->assertHtml($html, $radio); | ||
} | ||
|
||
public function testRadioNotValidIfCheckedValueIsInvalid() | ||
{ | ||
$this->markTestSkipped('Requires https://github.com/Icinga/ipl-validator/pull/8'); | ||
|
||
StaticTranslator::$instance = new NoopTranslator(); | ||
$radio = new RadioElement('test', [ | ||
'label' => 'Test', | ||
'options' => [ | ||
'foo' => 'Foo', | ||
'bar' => 'Bar', | ||
'yes' => 'Yes' | ||
], | ||
'value' => 'bar', | ||
'disableOptions' => 'yes' | ||
]); | ||
|
||
$this->assertTrue($radio->isValid()); | ||
|
||
$radio->setValue('no'); | ||
$this->assertFalse($radio->isValid()); | ||
|
||
$radio->setValue('tom'); | ||
$this->assertFalse($radio->isValid()); | ||
} | ||
|
||
public function testRadioNotValidIfCheckedValueIsDisabled() | ||
{ | ||
$this->markTestSkipped('Requires https://github.com/Icinga/ipl-validator/pull/8'); | ||
|
||
StaticTranslator::$instance = new NoopTranslator(); | ||
$radio = new RadioElement('test', [ | ||
'label' => 'Test', | ||
'options' => [ | ||
'foo' => 'Foo', | ||
'bar' => 'Bar', | ||
'yes' => 'Yes' | ||
], | ||
'value' => 'bar', | ||
'disableOptions' => 'yes' | ||
]); | ||
|
||
$this->assertTrue($radio->isValid()); | ||
|
||
$radio->setValue('yes'); | ||
$this->assertFalse($radio->isValid()); | ||
|
||
$radio->setValue('bar'); | ||
$this->assertTrue($radio->isValid()); | ||
|
||
$radio->disableOptions(['bar', 'yes', 'foo']); | ||
$this->assertFalse($radio->isValid()); | ||
} | ||
} |