From 1a3210f0f1f971db8a6e970c716c1cebd28b7ab0 Mon Sep 17 00:00:00 2001 From: David Grudl Date: Tue, 2 Mar 2021 04:26:00 +0100 Subject: [PATCH] Resolver: handles nullable or default union|types --- src/DI/Resolver.php | 8 +++--- .../ContainerBuilder.autowiring.novalue.phpt | 4 +-- tests/DI/Resolver.autowireArguments.80.phpt | 25 +++++++++++++++++-- .../DI/Resolver.autowireArguments.errors.phpt | 4 +-- 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/DI/Resolver.php b/src/DI/Resolver.php index 4a727f556..f63100dac 100644 --- a/src/DI/Resolver.php +++ b/src/DI/Resolver.php @@ -541,7 +541,8 @@ public static function autowireArguments( */ private static function autowireArgument(\ReflectionParameter $parameter, callable $getter) { - $type = Reflection::getParameterType($parameter); + $types = array_diff(Reflection::getParameterTypes($parameter), ['null']); + $type = count($types) === 1 ? reset($types) : null; $method = $parameter->getDeclaringFunction(); $desc = Reflection::toString($parameter); @@ -571,7 +572,7 @@ private static function autowireArgument(\ReflectionParameter $parameter, callab return $getter($itemType, false); } elseif ( - ($type && $parameter->allowsNull()) + ($types && $parameter->allowsNull()) || $parameter->isOptional() || $parameter->isDefaultValueAvailable() ) { @@ -582,7 +583,8 @@ private static function autowireArgument(\ReflectionParameter $parameter, callab : null; } else { - throw new ServiceCreationException("Parameter $desc has no class type hint or default value, so its value must be specified."); + $tmp = count($types) > 1 ? 'union' : 'no class'; + throw new ServiceCreationException("Parameter $desc has $tmp type hint and no default value, so its value must be specified."); } } } diff --git a/tests/DI/ContainerBuilder.autowiring.novalue.phpt b/tests/DI/ContainerBuilder.autowiring.novalue.phpt index 64ab4d011..43bb07788 100644 --- a/tests/DI/ContainerBuilder.autowiring.novalue.phpt +++ b/tests/DI/ContainerBuilder.autowiring.novalue.phpt @@ -24,7 +24,7 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('foo')->setType('Foo'); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'foo' (type of Foo): Parameter \$x in __construct() has no class type hint or default value, so its value must be specified."); +}, Nette\DI\ServiceCreationException::class, "Service 'foo' (type of Foo): Parameter \$x in __construct() has no class type hint and no default value, so its value must be specified."); class Bar @@ -38,7 +38,7 @@ Assert::exception(function () { $builder = new DI\ContainerBuilder; $builder->addDefinition('foo')->setType('Bar'); $container = createContainer($builder); -}, Nette\DI\ServiceCreationException::class, "Service 'foo' (type of Bar): Parameter \$x in __construct() has no class type hint or default value, so its value must be specified."); +}, Nette\DI\ServiceCreationException::class, "Service 'foo' (type of Bar): Parameter \$x in __construct() has no class type hint and no default value, so its value must be specified."); class Bar2 diff --git a/tests/DI/Resolver.autowireArguments.80.phpt b/tests/DI/Resolver.autowireArguments.80.phpt index 5722a1d4a..ed9bf63f1 100644 --- a/tests/DI/Resolver.autowireArguments.80.phpt +++ b/tests/DI/Resolver.autowireArguments.80.phpt @@ -16,11 +16,32 @@ require __DIR__ . '/../bootstrap.php'; class Test { - public function methodUnion(\stdClass |self $self) + public function methodUnion(\stdClass|self $self) + { + } + + + public function methodUnionNullable(\stdClass|self|null $nullable) + { + } + + + public function methodUnionDefault(\stdClass|int $default = 1) { } } + Assert::exception(function () { Resolver::autowireArguments(new ReflectionMethod('Test', 'methodUnion'), [], function () {}); -}, Nette\InvalidStateException::class, 'The $self in Test::methodUnion() is not expected to have a union type.'); +}, Nette\InvalidStateException::class, 'Parameter $self in Test::methodUnion() has union type hint and no default value, so its value must be specified.'); + +Assert::same( + [null], + Resolver::autowireArguments(new ReflectionMethod('Test', 'methodUnionNullable'), [], function () {}), +); + +Assert::same( + [], + Resolver::autowireArguments(new ReflectionMethod('Test', 'methodUnionDefault'), [], function () {}), +); diff --git a/tests/DI/Resolver.autowireArguments.errors.phpt b/tests/DI/Resolver.autowireArguments.errors.phpt index 0ac249628..7f5cdc078 100644 --- a/tests/DI/Resolver.autowireArguments.errors.phpt +++ b/tests/DI/Resolver.autowireArguments.errors.phpt @@ -25,9 +25,9 @@ Assert::exception(function () { Assert::exception(function () { Resolver::autowireArguments(new ReflectionFunction(function ($x) {}), [], function () {}); -}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}%a?% has no class type hint or default value, so its value must be specified.'); +}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}() has no class type hint and no default value, so its value must be specified.'); Assert::exception(function () { Resolver::autowireArguments(new ReflectionFunction(function (int $x) {}), [], function () {}); -}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}%a?% has no class type hint or default value, so its value must be specified.'); +}, Nette\DI\ServiceCreationException::class, 'Parameter $x in {closure}() has no class type hint and no default value, so its value must be specified.');