Skip to content

Commit

Permalink
Add backed enum value support to Select field (#363)
Browse files Browse the repository at this point in the history
  • Loading branch information
vjik authored Sep 21, 2024
1 parent 56aea45 commit 8452212
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 34 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

## 1.0.1 under development

- no changes in this release.
- Enh #363: Add backed enumeration value support to `Select` field (@vjik)

## 1.0.0 August 26, 2024

- Initial release.
- Initial release.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"require": {
"php": "^8.1",
"yiisoft/friendly-exception": "^1.0",
"yiisoft/html": "^3.6",
"yiisoft/html": "^3.7",
"yiisoft/widget": "^2.2"
},
"require-dev": {
Expand Down
12 changes: 7 additions & 5 deletions src/Field/Select.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

namespace Yiisoft\Form\Field;

use BackedEnum;
use InvalidArgumentException;
use Stringable;
use Yiisoft\Form\Field\Base\EnrichFromValidationRules\EnrichFromValidationRulesInterface;
Expand All @@ -15,6 +16,8 @@
use Yiisoft\Html\Tag\Option;
use Yiisoft\Html\Tag\Select as SelectTag;

use function is_scalar;

/**
* Represents `<select>` element that provides a menu of options.
*
Expand Down Expand Up @@ -261,14 +264,13 @@ protected function generateInput(): string
}
} else {
if (
!is_bool($value)
&& !is_string($value)
!is_scalar($value)
&& !$value instanceof Stringable
&& !is_numeric($value)
&& !$value instanceof BackedEnum
&& $value !== null
) {
throw new InvalidArgumentException(
'Non-multiple Select field requires a string, Stringable, numeric, bool or null value.'
'Non-multiple select field requires a string, Stringable, numeric, bool, backed enumeration or null value.'
);
}
$value = $value === null ? [] : [$value];
Expand All @@ -280,7 +282,7 @@ protected function generateInput(): string
$this->getInputAttributes()
);

/** @psalm-var iterable<int, Stringable|scalar> $value */
/** @psalm-var iterable<int, Stringable|scalar|BackedEnum> $value */
return $this->select
->addAttributes($selectAttributes)
->name($this->getName())
Expand Down
51 changes: 25 additions & 26 deletions tests/Field/SelectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
use stdClass;
use Yiisoft\Form\Field\Select;
use Yiisoft\Form\PureField\InputData;
use Yiisoft\Form\Tests\Support\IntegerEnum;
use Yiisoft\Form\Tests\Support\NullValidationRulesEnricher;
use Yiisoft\Form\Tests\Support\RequiredValidationRulesEnricher;
use Yiisoft\Form\Tests\Support\StringableObject;
use Yiisoft\Form\Tests\Support\StringEnum;
use Yiisoft\Form\Tests\Support\StubValidationRulesEnricher;
use Yiisoft\Form\Theme\ThemeContainer;
use Yiisoft\Html\Tag\Optgroup;
Expand Down Expand Up @@ -91,24 +93,36 @@ public function testBase(string $expected, InputData $inputData, array $theme =
$this->assertSame($expected, $result);
}

public function testSelectedSingle(): void
public static function dataSelectedSingle(): iterable
{
yield ['blue', 'blue'];
yield ['blue', new StringableObject('blue')];
yield ['', false];
yield ['1', true];
yield ['19', 19];
yield ['19.02', 19.02];
yield ['2', IntegerEnum::BLUE];
yield ['two', StringEnum::TWO];
}

#[DataProvider('dataSelectedSingle')]
public function testSelectedSingle(string $valueAsString, mixed $value): void
{
$result = Select::widget()
->name('count')
->value(15)
->name('color')
->value($value)
->optionsData([
10 => 'Ten',
15 => 'Fifteen',
20 => 'Twenty',
'red' => 'Red',
$valueAsString => 'Blue',
])
->render();

$expectedOption = '<option value' . ($valueAsString === '' ? '' : ('="' . $valueAsString . '"')) . ' selected>Blue</option>';
$expected = <<<HTML
<div>
<select name="count">
<option value="10">Ten</option>
<option value="15" selected>Fifteen</option>
<option value="20">Twenty</option>
<select name="color">
<option value="red">Red</option>
$expectedOption
</select>
</div>
HTML;
Expand Down Expand Up @@ -660,7 +674,7 @@ public function testSingleInvalidValue(): void

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage(
'Non-multiple Select field requires a string, Stringable, numeric, bool or null value.'
'Non-multiple select field requires a string, Stringable, numeric, bool, backed enumeration or null value.'
);
$widget->render();
}
Expand All @@ -674,21 +688,6 @@ public function testMultipleInvalidValue(): void
$widget->render();
}

public function testStringableValue(): void
{
$actualHtml = Select::widget()
->optionsData(['1' => 'One'])
->value(new StringableObject('1'))
->useContainer(false)
->render();
$expectedHtml = <<<HTML
<select>
<option value="1" selected>One</option>
</select>
HTML;
$this->assertSame($expectedHtml, $actualHtml);
}

public function testEnrichFromValidationRulesEnabled(): void
{
$html = Select::widget()
Expand Down
11 changes: 11 additions & 0 deletions tests/Support/IntegerEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Form\Tests\Support;

enum IntegerEnum: int
{
case GREEN = 1;
case BLUE = 2;
}
11 changes: 11 additions & 0 deletions tests/Support/StringEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Yiisoft\Form\Tests\Support;

enum StringEnum: string
{
case ONE = 'one';
case TWO = 'two';
}

0 comments on commit 8452212

Please sign in to comment.