Skip to content

Commit

Permalink
Fix #97: Fix widget Radio::class, add documentation (#98)
Browse files Browse the repository at this point in the history
Co-authored-by: Alexander Makarov <sam@rmcreative.ru>
  • Loading branch information
terabytesoftw and samdark committed Oct 21, 2021
1 parent fd08ef9 commit c3800ae
Show file tree
Hide file tree
Showing 6 changed files with 366 additions and 109 deletions.
1 change: 1 addition & 0 deletions README.md
Expand Up @@ -128,6 +128,7 @@ class LoginForm extends FormModel
The following documentation describes how to use widgets with PHP:

- [Checkbox](docs/checkbox.md)
- [Radio](docs/radio.md)

### Unit testing

Expand Down
213 changes: 213 additions & 0 deletions docs/radio.md
@@ -0,0 +1,213 @@
# Radio widget

[Radio](https://www.w3.org/TR/2012/WD-html-markup-20120329/input.radio.html) is an input element whose value represents a selection of one items from a list (a radio button).

## Usage

Let's use `Radio` widget to return true when an element is selected.

```php
<?php

declare(strict_types=1);

namespace App\Form;

use Yiisoft\Form\FormModel;

final class TestForm extends FormModel
{
public bool $active = false;
}
```

Widget view:

```php
<?php

declare(strict_types=1);

use Yiisoft\Form\FormModelInterface;
use Yiisoft\Form\Widget\Field;
use Yiisoft\Form\Widget\Form;
use Yiisoft\Form\Widget\Label;
use Yiisoft\Form\Widget\Radio;

/**
* @var $data FormModelInterface
* @var $csrf string
*/
?>

<?= Form::widget()->action('widgets')->csrf($csrf)->begin() ?>
<?= Radio::widget()->config($data, 'active',)->value(true)->render(); ?>
<hr class="mt-3">
<?= Field::widget()->submitButton(['class' => 'button is-block is-info is-fullwidth', 'value' => 'Save']); ?>
<?= Form::end() ?>
```

That would generate the following code:

```html
<form action="widgets" method="POST" _csrf="ic2cDp39M0hFYD2KypD4NnXU4Gcx8FTma624ZZZuUwHYjtNW_odcG31ZTcaH9LJhN7LWKQm4GoAJ4-ctySghTg==">
<input type="hidden" name="_csrf" value="ic2cDp39M0hFYD2KypD4NnXU4Gcx8FTma624ZZZuUwHYjtNW_odcG31ZTcaH9LJhN7LWKQm4GoAJ4-ctySghTg==">
<label><input type="radio" id="testform-active" name="TestForm[active]" value="1"> Active</label>
<hr class="mt-3">
<div>
<input type="submit" id="submit-27736839536001" class="button is-block is-info is-fullwidth" name="submit-27736839536001" value="Save">
</div>
</form>
```

### Custom values

Custom values could be set as well. In the following example we use `5` when the radio is selected and `0` when the radio is not.

```php
<?php

declare(strict_types=1);

namespace App\Form;

use Yiisoft\Form\FormModel;

final class TestForm extends FormModel
{
public int $number = 0;

public function getAttributeLabels(): array
{
return [
'number' => 'Five',
];
}
}
```

Widget view:

```php
<?php

declare(strict_types=1);

use Yiisoft\Form\FormModelInterface;
use Yiisoft\Form\Widget\Field;
use Yiisoft\Form\Widget\Form;
use Yiisoft\Form\Widget\Label;
use Yiisoft\Form\Widget\Radio;

/**
* @var $data FormModelInterface
* @var $csrf string
*/
?>

<?= Form::widget()->action('widgets')->csrf($csrf)->begin() ?>
<?= Radio::widget()->config($data, 'number')->uncheckValue(0)->value(5)->render() ?>
<hr class="mt-3">
<?= Field::widget()->submitButton(['class' => 'button is-block is-info is-fullwidth', 'value' => 'Save']); ?>
<?= Form::end() ?>
```

That would generate the following code:

```html
<form action="widgets" method="POST" _csrf="atfZTzPpEYZxxetvS69gUg5zd_enzzaZaf6RNZj4nxk7lJYXUJN-1Un8myMGyyoFTBVBuZ-HeP8LsM59x77tVg==">
<input type="hidden" name="_csrf" value="atfZTzPpEYZxxetvS69gUg5zd_enzzaZaf6RNZj4nxk7lJYXUJN-1Un8myMGyyoFTBVBuZ-HeP8LsM59x77tVg==">
<input type="hidden" name="TestForm[number]" value="0">
<label><input type="radio" id="testform-number" name="TestForm[number]" value="5"> Five</label>
<hr class="mt-3">
<div>
<input type="submit" id="submit-29518822380001" class="button is-block is-info is-fullwidth" name="submit-29518822380001" value="Save">
</div>
</form>
```

### More custom values

In this example we use two values for selection states (`inactive`, `active`) and and empty string when the radio is not checked.

```php
<?php

declare(strict_types=1);

namespace App\Form;

use Yiisoft\Form\FormModel;

final class TestForm extends FormModel
{
public string $active = '';
}
```

Widget view:

```php
<?php

declare(strict_types=1);

use Yiisoft\Form\FormModelInterface;
use Yiisoft\Form\Widget\Field;
use Yiisoft\Form\Widget\Form;
use Yiisoft\Form\Widget\Label;
use Yiisoft\Form\Widget\Radio;

/**
* @var $data FormModelInterface
* @var $csrf string
*/
?>

<?= Form::widget()->action('widgets')->csrf($csrf)->begin() ?>
<?= Radio::widget()->config($data, 'active')->label('inactive')->uncheckValue("")->value('inactive')->render() ?>
<?= Radio::widget()->config($data, 'active')->value('active')->render() ?>
<hr class="mt-3">
<?= Field::widget()->submitButton(['class' => 'button is-block is-info is-fullwidth', 'value' => 'Save']); ?>
<?= Form::end() ?>
```

### Code generated by `Radio` Widget

```html
<form action="widgets" method="POST" _csrf="hzRUVdfY31_OBlxvJvg1ZVkXnZcGwAeJVbncB4jSQHfWdxsNtKKwDPY_LCNrnH8yG3Gr2T6ISe8394NP15QyOA==">
<input type="hidden" name="_csrf" value="hzRUVdfY31_OBlxvJvg1ZVkXnZcGwAeJVbncB4jSQHfWdxsNtKKwDPY_LCNrnH8yG3Gr2T6ISe8394NP15QyOA==">
<input type="hidden" name="TestForm[active]" value="">
<label><input type="radio" id="testform-active" name="TestForm[active]" value="inactive"> inactive</label>
<label><input type="radio" id="testform-active" name="TestForm[active]" value="active"> Active</label>
<hr class="mt-3">
<div>
<input type="submit" id="submit-31818689915001" class="button is-block is-info is-fullwidth" name="submit-31818689915001" value="Save">
</div>
</form>
```

### `Radio` methods:

Method | Description | Default
-------|-------------|---------
`enclosedByLabel(bool $value = true)` | If the widget should be enclosed by label. | `true`
`label(string $value)` | The label text. | `''`
`labelAttributes(array $attributes = [])` | HTML attributes for the label tag. | `[]`
`uncheckValue($value)` | The value that is returned when the radio button is not checked. | `null`
`value($value)` | The value that is returned when the radio button is checked. | `null`

### `Common` methods:

Method | Description | Default
-------|-------------|---------
`charset(string $value)` | Sets the charset attribute | `UTF-8`
`config(FormModelInterface $formModel, string $attribute, array $attributes = [])` | Configures the widget. |
`autofocus(bool $value = true)` | Sets the autofocus attribute | `false`
`disabled(bool $value = true)` | Sets the disabled attribute | `false`
`form(string $value)` | Sets the form attribute | ``
`id(string $value)` | Sets the id attribute | `''`
`required(bool $value = true)` | Sets the required attribute | `false`
`readonly()` | Sets the readonly attribute | `false`
`tabIndex(int $value = 0)` | Sets the tabindex attribute | `0`

10 changes: 9 additions & 1 deletion src/Widget/Field.php
Expand Up @@ -6,6 +6,7 @@

use Closure;
use ReflectionException;
use Stringable;
use Yiisoft\Arrays\ArrayHelper;
use Yiisoft\Form\Widget\Attribute\FieldAttributes;
use Yiisoft\Html\Html;
Expand Down Expand Up @@ -518,6 +519,13 @@ public function radio(array $attributes = [], bool $enclosedByLabel = true): sel
$new->parts['{label}'] = '';
}

if (
isset($attributes['uncheckValue']) &&
((is_scalar($attributes['uncheckValue'])) || $attributes['uncheckValue'] instanceof Stringable)
) {
$radio = $radio->uncheckValue($attributes['uncheckValue']);
}

if (isset($attributes['label']) && is_string($attributes['label'])) {
$radio = $radio->label($attributes['label']);
}
Expand All @@ -526,7 +534,7 @@ public function radio(array $attributes = [], bool $enclosedByLabel = true): sel
$radio = $radio->labelAttributes($attributes['labelAttributes']);
}

unset($attributes['label'], $attributes['labelAttributes']);
unset($attributes['label'], $attributes['labelAttributes'], $attributes['uncheckValue']);

$new->parts['{input}'] = $radio
->config($new->getFormModel(), $new->attribute, $attributes)
Expand Down
51 changes: 41 additions & 10 deletions src/Widget/Radio.php
Expand Up @@ -5,6 +5,7 @@
namespace Yiisoft\Form\Widget;

use InvalidArgumentException;
use Stringable;
use Yiisoft\Form\Helper\HtmlForm;
use Yiisoft\Form\Widget\Attribute\CommonAttributes;
use Yiisoft\Form\Widget\Attribute\ModelAttributes;
Expand All @@ -25,6 +26,9 @@ final class Radio extends Widget
private bool $enclosedByLabel = true;
private string $label = '';
private array $labelAttributes = [];
/** @var scalar|Stringable|null */
private $value = null;
private ?string $uncheckValue = null;

/**
* If the widget should be enclosed by label.
Expand Down Expand Up @@ -75,6 +79,34 @@ public function labelAttributes(array $value = []): self
return $new;
}

/**
* @param bool|float|int|string|Stringable|null $value Value that corresponds to "unchecked" state of the input.
*
* @return static
*/
public function uncheckValue($value): self
{
$new = clone $this;
$new->uncheckValue = $value === null ? null : (string) $value;
return $new;
}

/**
* The value of the radio button.
*
* @param scalar|Stringable|null $value
*
* @return static
*
* @link https://www.w3.org/TR/2012/WD-html-markup-20120329/input.radio.html#input.radio.attrs.value
*/
public function value($value): self
{
$new = clone $this;
$new->value = $value;
return $new;
}

/**
* Generates a radio button tag together with a label for the given form attribute.
*
Expand All @@ -85,29 +117,28 @@ protected function run(): string
$new = clone $this;
$radio = RadioTag::tag();

/** @var bool|float|int|string|null */
$forceUncheckedValue = $new->attributes['forceUncheckedValue'] ?? null;

unset($new->attributes['forceUncheckedValue']);

$value = HtmlForm::getAttributeValue($new->getFormModel(), $new->attribute);

if (is_iterable($value) || is_object($value)) {
throw new InvalidArgumentException('Radio widget requires a bool|float|int|string|null value.');
throw new InvalidArgumentException('Radio widget value can not be an iterable or an object.');
}

/** @var scalar|Stringable|null */
$valueDefault = array_key_exists('value', $new->attributes) ? $new->attributes['value'] : $new->value;

if ($new->enclosedByLabel === true) {
$label = $new->label !== '' ? $new->label : HtmlForm::getAttributeLabel($new->getFormModel(), $new->attribute);
$label = $new->label !== ''
? $new->label : HtmlForm::getAttributeLabel($new->getFormModel(), $new->attribute);
$radio = $radio->label($label, $new->labelAttributes);
}

return $radio
->checked("$value" === "{$valueDefault}")
->attributes($new->attributes)
->checked((bool) $value)
->id($new->getId())
->name(HtmlForm::getInputName($new->getFormModel(), $new->attribute))
->uncheckValue($forceUncheckedValue)
->value((int) $value)
->uncheckValue($new->uncheckValue)
->value(is_bool($valueDefault) ? (int) $valueDefault : $valueDefault)
->render();
}
}

0 comments on commit c3800ae

Please sign in to comment.