1313use Closure ;
1414use Nette ;
1515use ReflectionClass ;
16- use SplObjectStorage ;
17- use Traversable ;
16+ use WeakMap ;
1817
1918/**
2019 * @author Filip Procházka <filip@prochazka.su>
@@ -38,7 +37,7 @@ class Container extends Nette\Forms\Container
3837 public $ createDefault ;
3938
4039 /**
41- * @var string
40+ * @var class- string<Nette\Forms\Container>
4241 */
4342 public $ containerClass = Nette \Forms \Container::class;
4443
@@ -53,12 +52,12 @@ class Container extends Nette\Forms\Container
5352 private $ submittedBy = FALSE ;
5453
5554 /**
56- * @var array
55+ * @var array<string, Nette\Forms\Container>
5756 */
5857 private $ created = [];
5958
6059 /**
61- * @var array
60+ * @var ? array<string, array<string, mixed>>
6261 */
6362 private $ httpPost ;
6463
@@ -110,19 +109,25 @@ protected function attached(Nette\ComponentModel\IComponent $obj): void
110109 }
111110
112111 /**
113- * @return iterable <Nette\Forms\Container>
112+ * @return array <Nette\Forms\Container>
114113 */
115- public function getContainers (bool $ recursive = FALSE ): iterable
114+ public function getContainers (bool $ recursive = FALSE ): array
116115 {
117- return $ this ->getComponents ($ recursive , \Nette \Forms \Container::class);
116+ return array_filter (
117+ $ recursive ? $ this ->getComponentTree () : $ this ->getComponents (),
118+ fn ($ component ): bool => $ component instanceof \Nette \Forms \Container,
119+ );
118120 }
119121
120122 /**
121- * @return iterable <Nette\Forms\ISubmitterControl >
123+ * @return array <Nette\Forms\Controls\SubmitButton >
122124 */
123- public function getButtons (bool $ recursive = FALSE ): iterable
125+ public function getButtons (bool $ recursive = FALSE ): array
124126 {
125- return $ this ->getComponents ($ recursive , Nette \Forms \ISubmitterControl::class);
127+ return array_filter (
128+ $ recursive ? $ this ->getComponentTree () : $ this ->getComponents (),
129+ fn ($ component ): bool => $ component instanceof Nette \Forms \Controls \SubmitButton,
130+ );
126131 }
127132
128133 /**
@@ -143,10 +148,13 @@ protected function createComponent(string $name): ?Nette\ComponentModel\ICompone
143148
144149 private function getFirstControlName (): ?string
145150 {
146- $ controls = iterator_to_array ($ this ->getComponents (FALSE , Nette \Forms \IControl::class));
151+ $ controls = array_filter (
152+ $ this ->getComponents (),
153+ fn ($ component ): bool => $ component instanceof Nette \Forms \Control,
154+ );
147155 $ firstControl = reset ($ controls );
148156
149- return $ firstControl ? $ firstControl ->name : NULL ;
157+ return $ firstControl ? $ firstControl ->getName () : NULL ;
150158 }
151159
152160 protected function createContainer (): Nette \Forms \Container
@@ -179,24 +187,23 @@ public function createOne(?string $name = NULL): Nette\Forms\Container
179187 if ($ name === NULL ) {
180188 $ names = array_keys (iterator_to_array ($ this ->getContainers ()));
181189 $ name = $ names ? max ($ names ) + 1 : 0 ;
190+ $ name = (string ) $ name ;
182191 }
183192
184193 // Container is overriden, therefore every request for getComponent($name, FALSE) would return container
185194 if (isset ($ this ->created [$ name ])) {
186195 throw new Nette \InvalidArgumentException ("Container with name ' {$ name }' already exists. " );
187196 }
188197
189- return $ this [ $ name] ;
198+ return $ this -> getComponent ( $ name) ;
190199 }
191200
192201 /**
193- * @param array|Traversable $values
194- *
195- * @return Nette\Forms\Container|Container
202+ * @param iterable<string, iterable<string, mixed>> $values
196203 */
197204 public function setValues (array |object $ values , bool $ erase = FALSE , bool $ onlyDisabled = FALSE ): static
198205 {
199- if (!$ this ->form ->isAnchored () || !$ this ->form ->isSubmitted ()) {
206+ if (!$ this ->form ? ->isAnchored() || !$ this ->form ->isSubmitted ()) {
200207 foreach ($ values as $ name => $ value ) {
201208 if ((is_iterable ($ value )) && !$ this ->getComponent ($ name , FALSE )) {
202209 $ this ->createOne ($ name );
@@ -234,7 +241,7 @@ protected function createDefault(): void
234241
235242 if (!$ this ->getForm ()->isSubmitted ()) {
236243 foreach (range (0 , $ this ->createDefault - 1 ) as $ key ) {
237- $ this ->createOne ($ key );
244+ $ this ->createOne (( string ) $ key );
238245 }
239246
240247 } elseif ($ this ->forceDefault ) {
@@ -245,13 +252,18 @@ protected function createDefault(): void
245252 }
246253
247254 /**
248- * @return mixed|null
255+ * @return ?array<string, array<string, mixed>>
249256 */
250- private function getHttpData ()
257+ private function getHttpData (): ? array
251258 {
252259 if ($ this ->httpPost === NULL ) {
253- $ path = explode (self ::NAME_SEPARATOR , $ this ->lookupPath (Nette \Forms \Form::class));
254- $ this ->httpPost = Nette \Utils \Arrays::get ($ this ->getForm ()->getHttpData (), $ path , NULL );
260+ $ path = explode (self ::NameSeparator, $ this ->lookupPath (Nette \Forms \Form::class));
261+ /** @var array<string, mixed> */ // See https://github.com/nette/forms/pull/333
262+ $ httpData = $ this ->getForm ()
263+ ->getHttpData ();
264+ /** @var ?array<string, array<string, mixed>> */
265+ $ httpPost = Nette \Utils \Arrays::get ($ httpData , $ path , NULL );
266+ $ this ->httpPost = $ httpPost ;
255267 }
256268
257269 return $ this ->httpPost ;
@@ -267,7 +279,11 @@ public function remove(Nette\ComponentModel\Container $container, bool $cleanUpG
267279 }
268280
269281 // to check if form was submitted by this one
270- foreach ($ container ->getComponents (TRUE , Nette \Forms \ISubmitterControl::class) as $ button ) {
282+ $ buttons = array_filter (
283+ $ container ->getComponentTree (),
284+ fn ($ component ): bool => $ component instanceof Nette \Forms \SubmitterControl,
285+ );
286+ foreach ($ buttons as $ button ) {
271287 /** @var Nette\Forms\Controls\SubmitButton $button */
272288 if ($ button ->isSubmittedBy ()) {
273289 $ this ->submittedBy = TRUE ;
@@ -276,7 +292,7 @@ public function remove(Nette\ComponentModel\Container $container, bool $cleanUpG
276292 }
277293
278294 /** @var Nette\Forms\Controls\BaseControl[] $components */
279- $ components = $ container ->getComponents ( TRUE );
295+ $ components = $ container ->getComponentTree ( );
280296 $ this ->removeComponent ($ container );
281297
282298 // reflection is required to hack form groups
@@ -287,12 +303,12 @@ public function remove(Nette\ComponentModel\Container $container, bool $cleanUpG
287303 // walk groups and clean then from removed components
288304 $ affected = [];
289305 foreach ($ this ->getForm ()->getGroups () as $ group ) {
290- /** @var SplObjectStorage $groupControls */
306+ /** @var WeakMap<Nette\Forms\Control, null> $groupControls */
291307 $ groupControls = $ controlsProperty ->getValue ($ group );
292308
293309 foreach ($ components as $ control ) {
294- if ($ groupControls ->contains ($ control )) {
295- $ groupControls-> detach ( $ control );
310+ if ($ groupControls ->offsetExists ($ control )) {
311+ unset( $ groupControls[ $ control] );
296312
297313 if (!in_array ($ group , $ affected , TRUE )) {
298314 $ affected [] = $ group ;
@@ -303,7 +319,12 @@ public function remove(Nette\ComponentModel\Container $container, bool $cleanUpG
303319
304320 // remove affected & empty groups
305321 if ($ cleanUpGroups && $ affected ) {
306- foreach ($ this ->getForm ()->getComponents (FALSE , Nette \Forms \Container::class) as $ cont ) {
322+ $ containers = array_filter (
323+ $ this ->getForm ()
324+ ->getComponents (),
325+ fn ($ component ): bool => $ component instanceof Nette \Forms \Container,
326+ );
327+ foreach ($ containers as $ cont ) {
307328 if ($ index = array_search ($ cont ->currentGroup , $ affected , TRUE )) {
308329 unset($ affected [$ index ]);
309330 }
@@ -321,6 +342,9 @@ public function remove(Nette\ComponentModel\Container $container, bool $cleanUpG
321342
322343 /**
323344 * Counts filled values, filtered by given names
345+ *
346+ * @param array<string> $components
347+ * @param array<string> $subComponents
324348 */
325349 public function countFilledWithout (array $ components = [], array $ subComponents = []): int
326350 {
@@ -333,31 +357,48 @@ public function countFilledWithout(array $components = [], array $subComponents
333357 $ rows = [];
334358 $ subComponents = array_flip ($ subComponents );
335359 foreach ($ httpData as $ item ) {
336- $ filter = function ($ value ) use (&$ filter ) {
360+ $ filter = function ($ value ) use (&$ filter ): bool {
337361 if (is_array ($ value )) {
338362 return count (array_filter ($ value , $ filter )) > 0 ;
339363 }
340364
341- return strlen ($ value );
365+ if (is_string ($ value )) {
366+ return strlen ($ value ) > 0 ;
367+ }
368+
369+ return true ;
342370 };
343371 $ rows [] = array_filter (array_diff_key ($ item , $ subComponents ), $ filter ) ?: FALSE ;
344372 }
345373
346374 return count (array_filter ($ rows ));
347375 }
348376
377+ /**
378+ * @param array<string> $exceptChildren
379+ */
349380 public function isAllFilled (array $ exceptChildren = []): bool
350381 {
351382 $ components = [];
352- foreach ($ this ->getComponents (FALSE , Nette \Forms \IControl::class) as $ control ) {
353- /** @var Nette\Forms\Controls\BaseControl $control */
354- $ components [] = $ control ->getName ();
383+ $ controls = array_filter (
384+ $ this ->getComponents (),
385+ fn ($ component ): bool => $ component instanceof Nette \Forms \Control,
386+ );
387+ foreach ($ controls as $ control ) {
388+ if (($ name = $ control ->getName ()) !== null ) {
389+ $ components [] = $ name ;
390+ }
355391 }
356392
357393 foreach ($ this ->getContainers () as $ container ) {
358- foreach ($ container ->getComponents (TRUE , Nette \Forms \ISubmitterControl::class) as $ button ) {
359- /** @var Nette\Forms\Controls\SubmitButton $button */
360- $ exceptChildren [] = $ button ->getName ();
394+ $ buttons = array_filter (
395+ $ container ->getComponentTree (),
396+ fn ($ component ): bool => $ component instanceof Nette \Forms \SubmitterControl,
397+ );
398+ foreach ($ buttons as $ button ) {
399+ if (($ name = $ button ->getName ()) !== null ) {
400+ $ exceptChildren [] = $ name ;
401+ }
361402 }
362403 }
363404
@@ -366,9 +407,9 @@ public function isAllFilled(array $exceptChildren = []): bool
366407 return $ filled === iterator_count ($ this ->getContainers ());
367408 }
368409
369- public function addContainer ($ name ): Nette \Forms \Container
410+ public function addContainer (string | int $ name ): Nette \Forms \Container
370411 {
371- return $ this [$ name ] = new Nette \Forms \Container ();
412+ return $ this [( string ) $ name ] = new Nette \Forms \Container ();
372413 }
373414
374415 public function addComponent (Nette \ComponentModel \IComponent $ component , ?string $ name , ?string $ insertBefore = NULL ): static
@@ -381,14 +422,11 @@ public function addComponent(Nette\ComponentModel\IComponent $component, ?string
381422 return $ this ;
382423 }
383424
384- /**
385- * @var bool
386- */
387- private static $ registered = FALSE ;
425+ private static ?string $ registered = null ;
388426
389427 public static function register (string $ methodName = 'addDynamic ' ): void
390428 {
391- if (self ::$ registered ) {
429+ if (self ::$ registered !== null ) {
392430 Nette \Forms \Container::extensionMethod (self ::$ registered , function () {
393431 throw new Nette \MemberAccessException ();
394432 });
@@ -404,7 +442,7 @@ function (Nette\Forms\Container $_this, string $name, callable $factory, int $cr
404442 }
405443 );
406444
407- if (self ::$ registered ) {
445+ if (self ::$ registered !== null ) {
408446 return ;
409447 }
410448
@@ -415,13 +453,15 @@ function (Nette\Forms\Controls\SubmitButton $_this, ?callable $callback = NULL)
415453 $ _this ->onClick [] = function (Nette \Forms \Controls \SubmitButton $ button ) use ($ callback ) {
416454 /** @var self $replicator */
417455 $ replicator = $ button ->lookup (static ::class);
456+ $ container = $ button ->parent ;
457+ \assert ($ container instanceof Nette \ComponentModel \Container);
418458 if (is_callable ($ callback )) {
419- $ callback ($ replicator , $ button -> parent );
459+ $ callback ($ replicator , $ container );
420460 }
421461 if ($ form = $ button ->getForm (FALSE )) {
422462 $ form ->onSuccess = [];
423463 }
424- $ replicator ->remove ($ button -> parent );
464+ $ replicator ->remove ($ container );
425465 };
426466
427467 return $ _this ;
@@ -434,13 +474,9 @@ function (Nette\Forms\Controls\SubmitButton $_this, bool $allowEmpty = FALSE, ?c
434474 $ _this ->onClick [] = function (Nette \Forms \Controls \SubmitButton $ button ) use ($ allowEmpty , $ callback ) {
435475 /** @var self $replicator */
436476 $ replicator = $ button ->lookup (static ::class);
437- if (!is_bool ($ allowEmpty )) {
438- $ callback = Closure::fromCallable ($ allowEmpty );
439- $ allowEmpty = FALSE ;
440- }
441- if ($ allowEmpty === TRUE || $ replicator ->isAllFilled () === TRUE ) {
477+ if ($ allowEmpty || $ replicator ->isAllFilled () === TRUE ) {
442478 $ newContainer = $ replicator ->createOne ();
443- if (is_callable ( $ callback) ) {
479+ if ($ callback !== NULL ) {
444480 $ callback ($ replicator , $ newContainer );
445481 }
446482 }
0 commit comments