1010namespace Nette \Forms \Controls ;
1111
1212use Nette ;
13+ use Nette \Utils \Arrays ;
1314
1415
1516/**
2122abstract 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
0 commit comments