Skip to content

Commit

Permalink
FormElement: Add RadioElement
Browse files Browse the repository at this point in the history
  • Loading branch information
sukhwinder33445 committed Oct 26, 2022
1 parent 239b215 commit b04b6ba
Show file tree
Hide file tree
Showing 2 changed files with 330 additions and 0 deletions.
165 changes: 165 additions & 0 deletions src/FormElement/RadioElement.php
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);
}
}
}
165 changes: 165 additions & 0 deletions tests/FormElement/RadioElementTest.php
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());
}
}

0 comments on commit b04b6ba

Please sign in to comment.