Skip to content

Commit

Permalink
ChoiceControl, MultiChoiceControl: choices are internally stored in $…
Browse files Browse the repository at this point in the history
…choices array
  • Loading branch information
dg committed May 19, 2024
1 parent 0cfa5b2 commit 09a4bf8
Showing 2 changed files with 40 additions and 36 deletions.
41 changes: 25 additions & 16 deletions src/Forms/Controls/ChoiceControl.php
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
namespace Nette\Forms\Controls;

use Nette;
use Nette\Utils\Arrays;


/**
@@ -21,7 +22,9 @@
abstract class ChoiceControl extends BaseControl
{
private bool $checkDefaultValue = true;
private array $items = [];

/** @var list<array{int|string, string|\Stringable}> */
private array $choices = [];


public function __construct($label = null, ?array $items = null)
@@ -46,26 +49,28 @@ public function loadHttpData(): void

/**
* Sets selected item (by key).
* @param string|int|\BackedEnum|null $value
* @param string|int|\BackedEnum|\Stringable|null $value
* @return static
* @internal
*/
public function setValue($value)
{
if ($value instanceof \BackedEnum) {
if ($value === null) {
$this->value = null;
return $this;
} elseif ($value instanceof \BackedEnum) {
$value = $value->value;
} elseif (!is_string($value) && !is_int($value) && !$value instanceof \Stringable) { // do ChoiceControl
throw new Nette\InvalidArgumentException(sprintf('Value must be scalar|enum|Stringable, %s given.', get_debug_type($value)));
}

if ($this->checkDefaultValue && $value !== null && !array_key_exists((string) $value, $this->items)) {
$set = Nette\Utils\Strings::truncate(
implode(', ', array_map(fn($s) => var_export($s, return: true), array_keys($this->items))),
70,
'...',
);
$value = Arrays::toKey((string) $value);
if ($this->checkDefaultValue && !Arrays::some($this->choices, fn($choice) => $choice[0] === $value)) {
$set = Nette\Utils\Strings::truncate(implode(', ', array_map(fn($choice) => var_export($choice[0], return: true), $this->choices)), 70, '...');
throw new Nette\InvalidArgumentException("Value '$value' is out of allowed set [$set] in field '{$this->getName()}'.");
}

$this->value = $value === null ? null : key([(string) $value => null]);
$this->value = $value;
return $this;
}

@@ -76,8 +81,8 @@ public function setValue($value)
*/
public function getValue(): mixed
{
return array_key_exists($this->value, $this->items)
? $this->value
return $this->value !== null && ([$res] = Arrays::first($this->choices, fn($choice) => $choice[0] === $this->value))
? $res
: null;
}

@@ -106,7 +111,10 @@ public function isFilled(): bool
*/
public function setItems(array $items, bool $useKeys = true)
{
$this->items = $useKeys ? $items : array_combine($items, $items);
$this->choices = [];
foreach ($items as $k => $v) {
$this->choices[] = [$useKeys ? $k : Arrays::toKey((string) $v), $v];
}
return $this;
}

@@ -116,7 +124,7 @@ public function setItems(array $items, bool $useKeys = true)
*/
public function getItems(): array
{
return $this->items;
return array_column($this->choices, 1, 0);
}


@@ -125,8 +133,9 @@ public function getItems(): array
*/
public function getSelectedItem(): mixed
{
$value = $this->getValue();
return $value === null ? null : $this->items[$value];
return $this->value !== null && ([, $res] = Arrays::first($this->choices, fn($choice) => $choice[0] === $this->value))
? $res
: null;
}


35 changes: 15 additions & 20 deletions src/Forms/Controls/MultiChoiceControl.php
Original file line number Diff line number Diff line change
@@ -10,6 +10,7 @@
namespace Nette\Forms\Controls;

use Nette;
use Nette\Utils\Arrays;


/**
@@ -21,7 +22,9 @@
abstract class MultiChoiceControl extends BaseControl
{
private bool $checkDefaultValue = true;
private array $items = [];

/** @var list<array{int|string, string|\Stringable}> */
private array $choices = [];


public function __construct($label = null, ?array $items = null)
@@ -67,12 +70,8 @@ public function setValue($values)
}

$values = array_keys($flip);
if ($this->checkDefaultValue && ($diff = array_diff($values, array_keys($this->items)))) {
$set = Nette\Utils\Strings::truncate(
implode(', ', array_map(fn($s) => var_export($s, return: true), array_keys($this->items))),
70,
'...',
);
if ($this->checkDefaultValue && ($diff = array_diff($values, $tmp = array_column($this->choices, 0)))) {
$set = Nette\Utils\Strings::truncate(implode(', ', array_map(fn($s) => var_export($s, return: true), $tmp)), 70, '...');
$vals = (count($diff) > 1 ? 's' : '') . " '" . implode("', '", $diff) . "'";
throw new Nette\InvalidArgumentException("Value$vals are out of allowed set [$set] in field '{$this->getName()}'.");
}
@@ -87,7 +86,7 @@ public function setValue($values)
*/
public function getValue(): array
{
return array_values(array_intersect($this->value, array_keys($this->items)));
return array_values(array_intersect($this->value, array_column($this->choices, 0)));
}


@@ -100,22 +99,16 @@ public function getRawValue(): array
}


/**
* Is any item selected?
*/
public function isFilled(): bool
{
return $this->getValue() !== [];
}


/**
* Sets items from which to choose.
* @return static
*/
public function setItems(array $items, bool $useKeys = true)
{
$this->items = $useKeys ? $items : array_combine($items, $items);
$this->choices = [];
foreach ($items as $k => $v) {
$this->choices[] = [$useKeys ? $k : Arrays::toKey((string) $v), $v];
}
return $this;
}

@@ -125,7 +118,7 @@ public function setItems(array $items, bool $useKeys = true)
*/
public function getItems(): array
{
return $this->items;
return array_column($this->choices, 1, 0);
}


@@ -134,7 +127,9 @@ public function getItems(): array
*/
public function getSelectedItems(): array
{
return array_intersect_key($this->items, array_flip($this->value));
$flip = array_flip($this->value);
$res = array_filter($this->choices, fn($choice) => isset($flip[$choice[0]]));
return array_column($res, 1, 0);
}


0 comments on commit 09a4bf8

Please sign in to comment.