Skip to content

Commit 810617e

Browse files
committed
ChoiceControl, MultiChoiceControl: choices are internally stored in $choices array [WIP]
1 parent 5701a0a commit 810617e

File tree

2 files changed

+40
-36
lines changed

2 files changed

+40
-36
lines changed

src/Forms/Controls/ChoiceControl.php

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Nette\Forms\Controls;
1111

1212
use Nette;
13+
use Nette\Utils\Arrays;
1314

1415

1516
/**
@@ -21,7 +22,9 @@
2122
abstract class ChoiceControl extends BaseControl
2223
{
2324
private bool $checkDefaultValue = true;
24-
private array $items = [];
25+
26+
/** @var list<array{int|string, string|\Stringable}> */
27+
private array $choices = [];
2528

2629

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

4750
/**
4851
* Sets selected item (by key).
49-
* @param string|int|\BackedEnum|null $value
52+
* @param string|int|\BackedEnum|\Stringable|null $value
5053
* @return static
5154
* @internal
5255
*/
5356
public function setValue($value)
5457
{
55-
if ($value instanceof \BackedEnum) {
58+
if ($value === null) {
59+
$this->value = null;
60+
return $this;
61+
} elseif ($value instanceof \BackedEnum) {
5662
$value = $value->value;
63+
} elseif (!is_string($value) && !is_int($value) && !$value instanceof \Stringable) { // do ChoiceControl
64+
throw new Nette\InvalidArgumentException(sprintf('Value must be scalar|enum|Stringable, %s given.', get_debug_type($value)));
5765
}
5866

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

68-
$this->value = $value === null ? null : key([(string) $value => null]);
73+
$this->value = $value;
6974
return $this;
7075
}
7176

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

@@ -106,7 +111,10 @@ public function isFilled(): bool
106111
*/
107112
public function setItems(array $items, bool $useKeys = true)
108113
{
109-
$this->items = $useKeys ? $items : array_combine($items, $items);
114+
$this->choices = [];
115+
foreach ($items as $k => $v) {
116+
$this->choices[] = [$useKeys ? $k : Arrays::toKey((string) $v), $v];
117+
}
110118
return $this;
111119
}
112120

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

122130

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

132141

src/Forms/Controls/MultiChoiceControl.php

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
namespace Nette\Forms\Controls;
1111

1212
use Nette;
13+
use Nette\Utils\Arrays;
1314

1415

1516
/**
@@ -21,7 +22,9 @@
2122
abstract class MultiChoiceControl extends BaseControl
2223
{
2324
private bool $checkDefaultValue = true;
24-
private array $items = [];
25+
26+
/** @var list<array{int|string, string|\Stringable}> */
27+
private array $choices = [];
2528

2629

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

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

9392

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

102101

103-
/**
104-
* Is any item selected?
105-
*/
106-
public function isFilled(): bool
107-
{
108-
return $this->getValue() !== [];
109-
}
110-
111-
112102
/**
113103
* Sets items from which to choose.
114104
* @return static
115105
*/
116106
public function setItems(array $items, bool $useKeys = true)
117107
{
118-
$this->items = $useKeys ? $items : array_combine($items, $items);
108+
$this->choices = [];
109+
foreach ($items as $k => $v) {
110+
$this->choices[] = [$useKeys ? $k : Arrays::toKey((string) $v), $v];
111+
}
119112
return $this;
120113
}
121114

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

131124

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

140135

0 commit comments

Comments
 (0)