Skip to content

Commit

Permalink
ComponentReflection: merged getParameterType & getPropertyType
Browse files Browse the repository at this point in the history
  • Loading branch information
dg committed Dec 15, 2023
1 parent 4180167 commit 8f15db3
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 43 deletions.
31 changes: 11 additions & 20 deletions src/Application/UI/ComponentReflection.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,16 @@ 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;
} elseif (
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)) {
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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);
}


Expand Down
2 changes: 1 addition & 1 deletion src/Application/UI/Presenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
20 changes: 10 additions & 10 deletions tests/UI/ComponentReflection.combineArgs.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
);
});

Expand All @@ -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.',
);
});

Expand Down
22 changes: 11 additions & 11 deletions tests/UI/Presenter.link().phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]));
Expand Down
2 changes: 1 addition & 1 deletion tests/UI/Presenter.paramChecking.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 8f15db3

Please sign in to comment.