bug #39251 [DependencyInjection] Fix container linter for union types (derrabus)
This PR was merged into the 4.4 branch.
Discussion
----------
[DependencyInjection] Fix container linter for union types
| Q | A
| ------------- | ---
| Branch? | 4.4
| Bug fix? | yes
| New feature? | no
| Deprecations? | no
| Tickets | Fix #39233
| License | MIT
| Doc PR | N/A
Commits
-------
e26893b122
[DependencyInjection] Fix container linter for union types.
This commit is contained in:
commit
bda2dcdf93
|
@ -30,6 +30,7 @@ foreach ($loader->getClassMap() as $class => $file) {
|
|||
case false !== strpos($file, '/src/Symfony/Component/Config/Tests/Fixtures/ParseError.php'):
|
||||
case false !== strpos($file, '/src/Symfony/Component/Debug/Tests/Fixtures/'):
|
||||
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Compiler/OptionalServiceClass.php'):
|
||||
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/CheckTypeDeclarationsPass/UnionConstructor.php'):
|
||||
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php'):
|
||||
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/uniontype_classes.php'):
|
||||
case false !== strpos($file, '/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ParentNotExists.php'):
|
||||
|
|
|
@ -153,26 +153,27 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
|
|||
/**
|
||||
* @throws InvalidParameterTypeException When a parameter is not compatible with the declared type
|
||||
*/
|
||||
private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix, string $type = null): void
|
||||
private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix, \ReflectionType $reflectionType = null): void
|
||||
{
|
||||
if (null === $type) {
|
||||
$type = $parameter->getType();
|
||||
$reflectionType = $reflectionType ?? $parameter->getType();
|
||||
|
||||
if ($type instanceof \ReflectionUnionType) {
|
||||
foreach ($type->getTypes() as $type) {
|
||||
try {
|
||||
$this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $type);
|
||||
if ($reflectionType instanceof \ReflectionUnionType) {
|
||||
foreach ($reflectionType->getTypes() as $t) {
|
||||
try {
|
||||
$this->checkType($checkedDefinition, $value, $parameter, $envPlaceholderUniquePrefix, $t);
|
||||
|
||||
return;
|
||||
} catch (InvalidParameterTypeException $e) {
|
||||
}
|
||||
return;
|
||||
} catch (InvalidParameterTypeException $e) {
|
||||
}
|
||||
|
||||
throw new InvalidParameterTypeException($this->currentId, $e->getCode(), $parameter);
|
||||
}
|
||||
|
||||
$type = $type->getName();
|
||||
throw new InvalidParameterTypeException($this->currentId, $e->getCode(), $parameter);
|
||||
}
|
||||
if (!$reflectionType instanceof \ReflectionNamedType) {
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $reflectionType->getName();
|
||||
|
||||
if ($value instanceof Reference) {
|
||||
if (!$this->container->has($value = (string) $value)) {
|
||||
|
@ -285,7 +286,7 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
|
|||
|
||||
$checkFunction = sprintf('is_%s', $type);
|
||||
|
||||
if (!$parameter->getType()->isBuiltin() || !$checkFunction($value)) {
|
||||
if (!$reflectionType->isBuiltin() || !$checkFunction($value)) {
|
||||
throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? $class : \gettype($value), $parameter);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPa
|
|||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarOptionalArgumentNotNull;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\FooObject;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\UnionConstructor;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Waldo;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Wobble;
|
||||
use Symfony\Component\ExpressionLanguage\Expression;
|
||||
|
@ -803,4 +804,72 @@ class CheckTypeDeclarationsPassTest extends TestCase
|
|||
|
||||
putenv('ARRAY=');
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 8
|
||||
*/
|
||||
public function testUnionTypePassesWithReference()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('foo', Foo::class);
|
||||
$container->register('union', UnionConstructor::class)
|
||||
->setArguments([new Reference('foo')]);
|
||||
|
||||
(new CheckTypeDeclarationsPass(true))->process($container);
|
||||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 8
|
||||
*/
|
||||
public function testUnionTypePassesWithBuiltin()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('union', UnionConstructor::class)
|
||||
->setArguments([42]);
|
||||
|
||||
(new CheckTypeDeclarationsPass(true))->process($container);
|
||||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 8
|
||||
*/
|
||||
public function testUnionTypeFailsWithReference()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('waldo', Waldo::class);
|
||||
$container->register('union', UnionConstructor::class)
|
||||
->setArguments([new Reference('waldo')]);
|
||||
|
||||
$this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\UnionConstructor::__construct" accepts "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo|int", "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Waldo" passed.');
|
||||
|
||||
(new CheckTypeDeclarationsPass(true))->process($container);
|
||||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @requires PHP 8
|
||||
*/
|
||||
public function testUnionTypeFailsWithBuiltin()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$container->register('union', UnionConstructor::class)
|
||||
->setArguments([[1, 2, 3]]);
|
||||
|
||||
$this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class);
|
||||
$this->expectExceptionMessage('Invalid definition for service "union": argument 1 of "Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CheckTypeDeclarationsPass\\UnionConstructor::__construct" accepts "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo|int", "array" passed.');
|
||||
|
||||
(new CheckTypeDeclarationsPass(true))->process($container);
|
||||
|
||||
$this->addToAssertionCount(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass;
|
||||
|
||||
class UnionConstructor
|
||||
{
|
||||
public function __construct(Foo|int $arg)
|
||||
{
|
||||
}
|
||||
}
|
Reference in New Issue