diff --git a/phpstan.neon b/phpstan.neon index 8ee0af89..d841dda9 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -113,11 +113,6 @@ parameters: message: '#^Parameter \#1 \$returnType of method Nette\\Forms\\Container::(getValues|getUntrustedValues)\(\) expects#' path: src/Forms/Container.php - - # Complex template type T cannot be fully tracked through getValues delegation - message: '#^Method Nette\\Forms\\Container::getValues\(\) should return#' - path: src/Forms/Container.php - count: 1 - - message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' identifier: function.alreadyNarrowedType diff --git a/src/Bridges/FormsDI/FormsExtension.php b/src/Bridges/FormsDI/FormsExtension.php index cff15e24..8591ee9d 100644 --- a/src/Bridges/FormsDI/FormsExtension.php +++ b/src/Bridges/FormsDI/FormsExtension.php @@ -20,7 +20,7 @@ class FormsExtension extends Nette\DI\CompilerExtension public function __construct() { $this->config = new class { - /** @var string[] */ + /** @var array */ public array $messages = []; }; } diff --git a/src/Bridges/FormsLatte/Runtime.php b/src/Bridges/FormsLatte/Runtime.php index 670589da..8fb0206b 100644 --- a/src/Bridges/FormsLatte/Runtime.php +++ b/src/Bridges/FormsLatte/Runtime.php @@ -19,7 +19,7 @@ */ class Runtime { - /** @var Container[] */ + /** @var list */ private array $stack = []; /** @var list parallel to $stack; non-null element = id of a detached form */ @@ -28,7 +28,7 @@ class Runtime /** @var list parallel to $stack; true = scope the template's $form variable was bound to */ private array $formBindings = []; - /** @var Nette\Forms\Repeater[] */ + /** @var list */ private array $repeaters = []; diff --git a/src/Forms/Container.php b/src/Forms/Container.php index 590efa9f..1ea6e2e9 100644 --- a/src/Forms/Container.php +++ b/src/Forms/Container.php @@ -18,7 +18,7 @@ * * @property-read string $name * @property ArrayHash $values - * @property-read \Iterator $controls + * @property-read \Iterator $controls * @property-read ?Form $form * @implements \ArrayAccess */ @@ -118,7 +118,7 @@ public function setValues(array|object $values, bool $erase = false, bool $onlyD * @template T of object * @param class-string|T|'array'|null $returnType * @param ?list $controls - * @return ($returnType is class-string|T ? T : ($returnType is 'array' ? mixed[] : ArrayHash)) + * @return ($returnType is 'array' ? array : ($returnType is class-string|T ? T : ArrayHash)) */ public function getValues(string|object|null $returnType = null, ?array $controls = null): object|array { @@ -154,7 +154,7 @@ public function getValues(string|object|null $returnType = null, ?array $control * @template T of object * @param class-string|T|'array'|null $returnType * @param ?list $controls - * @return ($returnType is class-string|T ? T : ($returnType is 'array' ? mixed[] : ArrayHash)) + * @return ($returnType is 'array' ? array : ($returnType is class-string|T ? T : ArrayHash)) */ public function getUntrustedValues(string|object|null $returnType = null, ?array $controls = null): object|array { @@ -356,13 +356,15 @@ public function addComponent( /** * Iterates over all form controls including nested. Keys are control names and are not unique across containers. - * @return iterable + * @return iterable */ public function getControls(): iterable { foreach ($this->getComponentTree() as $component) { if ($component instanceof Control) { - yield $component->getName() => $component; + $name = $component->getName(); + assert($name !== null); + yield $name => $component; } } } diff --git a/src/Forms/Controls/BaseControl.php b/src/Forms/Controls/BaseControl.php index b35f8777..be2dab0f 100644 --- a/src/Forms/Controls/BaseControl.php +++ b/src/Forms/Controls/BaseControl.php @@ -31,7 +31,7 @@ * @property-read Html $labelPrototype * @property bool $required * @property-deprecated bool $filled - * @property-read string[] $errors + * @property-read list $errors * @property-deprecated array $options * @property-read string $error */ diff --git a/src/Forms/Controls/UploadControl.php b/src/Forms/Controls/UploadControl.php index 286cb0da..f27f6c54 100644 --- a/src/Forms/Controls/UploadControl.php +++ b/src/Forms/Controls/UploadControl.php @@ -79,7 +79,7 @@ public function setValue(mixed $value): static /** * Returns the uploaded file(s), a dummy FileUpload(null) when nothing was uploaded, or null when nullable is set. - * @return FileUpload|FileUpload[]|null + * @return FileUpload|list|null */ public function getValue(): FileUpload|array|null { diff --git a/src/Forms/Form.php b/src/Forms/Form.php index b9de3b9c..88c13398 100644 --- a/src/Forms/Form.php +++ b/src/Forms/Form.php @@ -18,8 +18,8 @@ * by default the form reads its own HTTP request (standalone usage), inside Nette Application * use Nette\Application\UI\Form, other sources are set via setSubmissionSource(). * - * @property-read string[] $errors - * @property-read array $ownErrors + * @property-read list $errors + * @property-read list $ownErrors * @property-read Html $elementPrototype * @property-deprecated FormRenderer $renderer * @property-deprecated string $action diff --git a/tests/types/forms-types.php b/tests/types/forms-types.php index 396147fa..4f087fdf 100644 --- a/tests/types/forms-types.php +++ b/tests/types/forms-types.php @@ -19,15 +19,18 @@ class FormDto function testFormContainerGetValues(Container $container): void { assertType('Nette\Utils\ArrayHash', $container->getValues()); - assertType('array|array', $container->getValues('array')); + assertType('array', $container->getValues('array')); + assertType('array', $container->getValues(Container::Array)); assertType(FormDto::class, $container->getValues(FormDto::class)); + assertType('array|Nette\Utils\ArrayHash', $container->getValues(rand() ? 'array' : null)); + assertType('array|FormDto', $container->getValues(rand() ? 'array' : FormDto::class)); } function testFormContainerGetUntrustedValues(Container $container): void { assertType('Nette\Utils\ArrayHash', $container->getUntrustedValues()); - assertType('array|array', $container->getUntrustedValues('array')); + assertType('array', $container->getUntrustedValues('array')); assertType(FormDto::class, $container->getUntrustedValues(FormDto::class)); } @@ -64,3 +67,24 @@ function testFormGetSubmittedData(Form $form, Nette\Forms\Container $container): assertType('array', $form->getSubmittedData()); assertType('array', $container->getSubmittedData()); } + + +function testFormContainerControls(Container $container): void +{ + assertType('Iterator', $container->controls); + assertType('iterable', $container->getControls()); +} + + +function testFormErrors(Form $form, Nette\Forms\Controls\TextInput $input): void +{ + assertType('list', $form->errors); + assertType('list', $form->ownErrors); + assertType('list', $input->errors); +} + + +function testUploadControlGetValue(Nette\Forms\Controls\UploadControl $upload): void +{ + assertType('list|Nette\Http\FileUpload|null', $upload->getValue()); +}