From 8f15db3debe79adb7325bc3f41a86fa50e51f21e Mon Sep 17 00:00:00 2001 From: David Grudl Date: Mon, 2 Oct 2023 18:48:23 +0200 Subject: [PATCH] ComponentReflection: merged getParameterType & getPropertyType --- src/Application/UI/ComponentReflection.php | 31 +++++++------------ src/Application/UI/Presenter.php | 2 +- tests/UI/ComponentReflection.combineArgs.phpt | 20 ++++++------ tests/UI/Presenter.link().phpt | 22 ++++++------- tests/UI/Presenter.paramChecking.phpt | 2 +- 5 files changed, 34 insertions(+), 43 deletions(-) diff --git a/src/Application/UI/ComponentReflection.php b/src/Application/UI/ComponentReflection.php index dca9c5041..0c7d8b004 100644 --- a/src/Application/UI/ComponentReflection.php +++ b/src/Application/UI/ComponentReflection.php @@ -37,7 +37,6 @@ public function getParameters(): array $params = []; $isPresenter = $this->isSubclassOf(Presenter::class); - $defaults = $this->getDefaultProperties(); foreach ($this->getProperties(\ReflectionProperty::IS_PUBLIC) as $prop) { if ($prop->isStatic()) { continue; @@ -45,10 +44,9 @@ public function getParameters(): array self::parseAnnotation($prop, 'persistent') || $prop->getAttributes(Nette\Application\Attributes\Persistent::class) ) { - $default = $defaults[$prop->getName()] ?? null; $params[$prop->getName()] = [ - 'def' => $default, - 'type' => self::getPropertyType($prop, $default), + 'def' => $prop->getDefaultValue(), + 'type' => self::getType($prop), 'since' => $isPresenter ? Nette\Utils\Reflection::getPropertyDeclaringClass($prop)->getName() : null, ]; } elseif ($prop->getAttributes(Nette\Application\Attributes\Parameter::class)) { @@ -169,7 +167,7 @@ public static function combineArgs(\ReflectionFunctionAbstract $method, array $a $res = []; foreach ($method->getParameters() as $i => $param) { $name = $param->getName(); - $type = self::getParameterType($param); + $type = self::getType($param); if (isset($args[$name])) { $res[$i] = $args[$name]; if (!self::convertType($res[$i], $type)) { @@ -274,22 +272,15 @@ public static function parseAnnotation(\Reflector $ref, string $name): ?array } - public static function getParameterType(\ReflectionParameter $param): string + public static function getType(\ReflectionParameter|\ReflectionProperty $item): string { - $default = $param->isDefaultValueAvailable() ? $param->getDefaultValue() : null; - $type = $param->getType(); - return $type - ? ($type instanceof \ReflectionNamedType ? $type->getName() : (string) $type) - : ($default === null ? 'scalar' : get_debug_type($default)); - } - - - public static function getPropertyType(\ReflectionProperty $prop, mixed $default): string - { - $type = $prop->getType(); - return $type - ? ($type instanceof \ReflectionNamedType ? $type->getName() : (string) $type) - : ($default === null ? 'scalar' : get_debug_type($default)); + if ($type = $item->getType()) { + return (string) $type; + } + $default = $item instanceof \ReflectionProperty || $item->isDefaultValueAvailable() + ? $item->getDefaultValue() + : null; + return $default === null ? 'scalar' : get_debug_type($default); } diff --git a/src/Application/UI/Presenter.php b/src/Application/UI/Presenter.php index 7fb5a8742..b883d69b4 100644 --- a/src/Application/UI/Presenter.php +++ b/src/Application/UI/Presenter.php @@ -1010,7 +1010,7 @@ public static function argsToParams( $i = 0; $rm = new \ReflectionMethod($class, $method); foreach ($rm->getParameters() as $param) { - $type = ComponentReflection::getParameterType($param); + $type = ComponentReflection::getType($param); $name = $param->getName(); if (array_key_exists($i, $args)) { diff --git a/tests/UI/ComponentReflection.combineArgs.phpt b/tests/UI/ComponentReflection.combineArgs.phpt index aa22439b6..f4153a359 100644 --- a/tests/UI/ComponentReflection.combineArgs.phpt +++ b/tests/UI/ComponentReflection.combineArgs.phpt @@ -143,31 +143,31 @@ test('', function () { Assert::exception( fn() => Reflection::combineArgs($method, ['int' => '']), Nette\InvalidArgumentException::class, - 'Argument $int passed to MyPresenter::hintsNulls() must be int, string given.', + 'Argument $int passed to MyPresenter::hintsNulls() must be ?int, string given.', ); Assert::exception( fn() => Reflection::combineArgs($method, ['int' => new stdClass]), Nette\InvalidArgumentException::class, - 'Argument $int passed to MyPresenter::hintsNulls() must be int, stdClass given.', + 'Argument $int passed to MyPresenter::hintsNulls() must be ?int, stdClass given.', ); Assert::exception( fn() => Reflection::combineArgs($method, ['int' => []]), Nette\InvalidArgumentException::class, - 'Argument $int passed to MyPresenter::hintsNulls() must be int, array given.', + 'Argument $int passed to MyPresenter::hintsNulls() must be ?int, array given.', ); Assert::exception( fn() => Reflection::combineArgs($method, ['int' => '1', 'bool' => '']), Nette\InvalidArgumentException::class, - 'Argument $bool passed to MyPresenter::hintsNulls() must be bool, string given.', + 'Argument $bool passed to MyPresenter::hintsNulls() must be ?bool, string given.', ); Assert::exception( fn() => Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => '']), Nette\InvalidArgumentException::class, - 'Argument $arr passed to MyPresenter::hintsNulls() must be array, string given.', + 'Argument $arr passed to MyPresenter::hintsNulls() must be ?array, string given.', ); }); @@ -183,31 +183,31 @@ test('', function () { Assert::exception( fn() => Reflection::combineArgs($method, ['int' => '']), Nette\InvalidArgumentException::class, - 'Argument $int passed to MyPresenter::hintsNullable() must be int, string given.', + 'Argument $int passed to MyPresenter::hintsNullable() must be ?int, string given.', ); Assert::exception( fn() => Reflection::combineArgs($method, ['int' => new stdClass]), Nette\InvalidArgumentException::class, - 'Argument $int passed to MyPresenter::hintsNullable() must be int, stdClass given.', + 'Argument $int passed to MyPresenter::hintsNullable() must be ?int, stdClass given.', ); Assert::exception( fn() => Reflection::combineArgs($method, ['int' => []]), Nette\InvalidArgumentException::class, - 'Argument $int passed to MyPresenter::hintsNullable() must be int, array given.', + 'Argument $int passed to MyPresenter::hintsNullable() must be ?int, array given.', ); Assert::exception( fn() => Reflection::combineArgs($method, ['int' => '1', 'bool' => '']), Nette\InvalidArgumentException::class, - 'Argument $bool passed to MyPresenter::hintsNullable() must be bool, string given.', + 'Argument $bool passed to MyPresenter::hintsNullable() must be ?bool, string given.', ); Assert::exception( fn() => Reflection::combineArgs($method, ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => '']), Nette\InvalidArgumentException::class, - 'Argument $arr passed to MyPresenter::hintsNullable() must be array, string given.', + 'Argument $arr passed to MyPresenter::hintsNullable() must be ?array, string given.', ); }); diff --git a/tests/UI/Presenter.link().phpt b/tests/UI/Presenter.link().phpt index aaad438c7..6b98062db 100644 --- a/tests/UI/Presenter.link().phpt +++ b/tests/UI/Presenter.link().phpt @@ -115,7 +115,7 @@ class TestPresenter extends Application\UI\Presenter Assert::same(['pbooln' => true, 'parrn' => [1], 'pint' => null, 'parr' => null, 'pbool' => null, 'action' => 'params'], $this->getLastCreatedRequest()->getParameters()); Assert::same('/index.php?pbooln=0&action=params&presenter=Test', $this->link('params', ['pbooln' => '0', 'parrn' => []])); Assert::same(['pbooln' => false, 'parrn' => [], 'pint' => null, 'parr' => null, 'pbool' => null, 'action' => 'params'], $this->getLastCreatedRequest()->getParameters()); - Assert::same("#error: Value passed to persistent parameter 'pbooln' in presenter Test must be bool, string given.", $this->link('params', ['pbooln' => 'a'])); + Assert::same("#error: Value passed to persistent parameter 'pbooln' in presenter Test must be ?bool, string given.", $this->link('params', ['pbooln' => 'a'])); Assert::same("#error: Value passed to persistent parameter 'parrn' in presenter Test must be array, string given.", $this->link('params', ['parrn' => 'a'])); // Other presenter & action link @@ -176,21 +176,21 @@ class TestPresenter extends Application\UI\Presenter Assert::same('/index.php?action=hintsNulls&presenter=Test', $this->link('hintsNulls', ['int' => null, 'bool' => null, 'str' => null, 'arr' => null])); Assert::same('/index.php?int=1&bool=1&str=abc&arr%5B0%5D=1&action=hintsNulls&presenter=Test', $this->link('hintsNulls', ['int' => '1', 'bool' => '1', 'str' => 'abc', 'arr' => [1]])); Assert::same('/index.php?int=0&bool=0&action=hintsNulls&presenter=Test', $this->link('hintsNulls', ['int' => 0, 'bool' => false, 'str' => '', 'arr' => []])); - Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNulls() must be int, string given.', $this->link('hintsNulls', ['int' => ''])); - Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNulls() must be int, stdClass given.', $this->link('hintsNulls', ['int' => new stdClass])); - Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNulls() must be int, array given.', $this->link('hintsNulls', ['int' => []])); - Assert::same('#error: Argument $bool passed to TestPresenter::actionHintsNulls() must be bool, string given.', $this->link('hintsNulls', ['int' => '1', 'bool' => ''])); - Assert::same('#error: Argument $arr passed to TestPresenter::actionHintsNulls() must be array, string given.', $this->link('hintsNulls', ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => ''])); + Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNulls() must be ?int, string given.', $this->link('hintsNulls', ['int' => ''])); + Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNulls() must be ?int, stdClass given.', $this->link('hintsNulls', ['int' => new stdClass])); + Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNulls() must be ?int, array given.', $this->link('hintsNulls', ['int' => []])); + Assert::same('#error: Argument $bool passed to TestPresenter::actionHintsNulls() must be ?bool, string given.', $this->link('hintsNulls', ['int' => '1', 'bool' => ''])); + Assert::same('#error: Argument $arr passed to TestPresenter::actionHintsNulls() must be ?array, string given.', $this->link('hintsNulls', ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => ''])); Assert::same('/index.php?action=hintsNullable&presenter=Test', $this->link('hintsNullable', [])); Assert::same('/index.php?action=hintsNullable&presenter=Test', $this->link('hintsNullable', ['int' => null, 'bool' => null, 'str' => null, 'arr' => null])); Assert::same('/index.php?int=1&bool=1&str=abc&arr%5B0%5D=1&action=hintsNullable&presenter=Test', $this->link('hintsNullable', ['int' => '1', 'bool' => '1', 'str' => 'abc', 'arr' => [1]])); Assert::same('/index.php?int=0&bool=0&action=hintsNullable&presenter=Test', $this->link('hintsNullable', ['int' => 0, 'bool' => false, 'str' => '', 'arr' => []])); - Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNullable() must be int, string given.', $this->link('hintsNullable', ['int' => ''])); - Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNullable() must be int, stdClass given.', $this->link('hintsNullable', ['int' => new stdClass])); - Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNullable() must be int, array given.', $this->link('hintsNullable', ['int' => []])); - Assert::same('#error: Argument $bool passed to TestPresenter::actionHintsNullable() must be bool, string given.', $this->link('hintsNullable', ['int' => '1', 'bool' => ''])); - Assert::same('#error: Argument $arr passed to TestPresenter::actionHintsNullable() must be array, string given.', $this->link('hintsNullable', ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => ''])); + Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNullable() must be ?int, string given.', $this->link('hintsNullable', ['int' => ''])); + Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNullable() must be ?int, stdClass given.', $this->link('hintsNullable', ['int' => new stdClass])); + Assert::same('#error: Argument $int passed to TestPresenter::actionHintsNullable() must be ?int, array given.', $this->link('hintsNullable', ['int' => []])); + Assert::same('#error: Argument $bool passed to TestPresenter::actionHintsNullable() must be ?bool, string given.', $this->link('hintsNullable', ['int' => '1', 'bool' => ''])); + Assert::same('#error: Argument $arr passed to TestPresenter::actionHintsNullable() must be ?array, string given.', $this->link('hintsNullable', ['int' => '1', 'bool' => '1', 'str' => '', 'arr' => ''])); Assert::same('/index.php?action=hintsDefaults&presenter=Test', $this->link('hintsDefaults', [])); Assert::same('/index.php?action=hintsDefaults&presenter=Test', $this->link('hintsDefaults', ['int' => null, 'bool' => null, 'str' => null, 'arr' => null])); diff --git a/tests/UI/Presenter.paramChecking.phpt b/tests/UI/Presenter.paramChecking.phpt index dd433575d..958171c55 100644 --- a/tests/UI/Presenter.paramChecking.phpt +++ b/tests/UI/Presenter.paramChecking.phpt @@ -57,7 +57,7 @@ Assert::exception(function () use ($presenter) { Assert::exception(function () use ($presenter) { $request = new Application\Request('Test', Http\Request::Get, ['d' => 1]); $presenter->run($request); -}, Nette\Application\BadRequestException::class, 'Argument $d passed to ParamPresenter::actionDefault() must be array, int given.'); +}, Nette\Application\BadRequestException::class, 'Argument $d passed to ParamPresenter::actionDefault() must be ?array, int given.'); Assert::exception(function () use ($presenter) {