Skip to content

Commit daded0b

Browse files
committed
[DependencyInjection] Allow AutowireCallable without method
1 parent cc74385 commit daded0b

File tree

5 files changed

+122
-3
lines changed

5 files changed

+122
-3
lines changed

Attribute/AutowireCallable.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@ public function __construct(
3232
if (!(null !== $callable xor null !== $service)) {
3333
throw new LogicException('#[AutowireCallable] attribute must declare exactly one of $callable or $service.');
3434
}
35-
if (!(null !== $callable xor null !== $method)) {
36-
throw new LogicException('#[AutowireCallable] attribute must declare one of $callable or $method.');
35+
if (null === $service && null !== $method) {
36+
throw new LogicException('#[AutowireCallable] attribute cannot have a $method without a $service.');
3737
}
3838

3939
parent::__construct($callable ?? [new Reference($service), $method ?? '__invoke'], lazy: $lazy);
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Attribute;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\DependencyInjection\Attribute\AutowireCallable;
16+
use Symfony\Component\DependencyInjection\Exception\LogicException;
17+
use Symfony\Component\DependencyInjection\Reference;
18+
19+
class AutowireCallableTest extends TestCase
20+
{
21+
public function testNoArguments()
22+
{
23+
$this->expectException(LogicException::class);
24+
25+
new AutowireCallable();
26+
}
27+
28+
public function testCallableAndService()
29+
{
30+
$this->expectException(LogicException::class);
31+
32+
new AutowireCallable(callable: 'my_callable', service: 'my_service', method: 'my_method');
33+
}
34+
35+
public function testMethodOnly()
36+
{
37+
$this->expectException(LogicException::class);
38+
39+
new AutowireCallable(method: 'my_method');
40+
}
41+
42+
public function testCallableAndMethod()
43+
{
44+
$this->expectException(LogicException::class);
45+
46+
new AutowireCallable(callable: 'my_callable', method: 'my_method');
47+
}
48+
49+
public function testStringCallable()
50+
{
51+
$attribute = new AutowireCallable(callable: 'my_callable');
52+
53+
self::assertSame('my_callable', $attribute->value);
54+
self::assertFalse($attribute->lazy);
55+
}
56+
57+
public function testArrayCallable()
58+
{
59+
$attribute = new AutowireCallable(callable: ['My\StaticClass', 'my_callable']);
60+
61+
self::assertSame(['My\StaticClass', 'my_callable'], $attribute->value);
62+
self::assertFalse($attribute->lazy);
63+
}
64+
65+
public function testArrayCallableWithReferenceAndMethod()
66+
{
67+
$attribute = new AutowireCallable(callable: [new Reference('my_service'), 'my_callable']);
68+
69+
self::assertEquals([new Reference('my_service'), 'my_callable'], $attribute->value);
70+
self::assertFalse($attribute->lazy);
71+
}
72+
73+
public function testArrayCallableWithReferenceOnly()
74+
{
75+
$attribute = new AutowireCallable(callable: [new Reference('my_service')]);
76+
77+
self::assertEquals([new Reference('my_service')], $attribute->value);
78+
self::assertFalse($attribute->lazy);
79+
}
80+
81+
public function testArrayCallableWithServiceAndMethod()
82+
{
83+
$attribute = new AutowireCallable(service: 'my_service', method: 'my_callable');
84+
85+
self::assertEquals([new Reference('my_service'), 'my_callable'], $attribute->value);
86+
self::assertFalse($attribute->lazy);
87+
}
88+
89+
public function testArrayCallableWithServiceOnly()
90+
{
91+
$attribute = new AutowireCallable(service: 'my_service');
92+
93+
self::assertEquals([new Reference('my_service'), '__invoke'], $attribute->value);
94+
self::assertFalse($attribute->lazy);
95+
}
96+
}

Tests/Dumper/PhpDumperTest.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
4949
use Symfony\Component\DependencyInjection\Tests\Compiler\FooAnnotation;
5050
use Symfony\Component\DependencyInjection\Tests\Compiler\IInterface;
51+
use Symfony\Component\DependencyInjection\Tests\Compiler\MyCallable;
5152
use Symfony\Component\DependencyInjection\Tests\Compiler\SingleMethodInterface;
5253
use Symfony\Component\DependencyInjection\Tests\Compiler\Wither;
5354
use Symfony\Component\DependencyInjection\Tests\Compiler\WitherAnnotation;
@@ -1720,6 +1721,8 @@ public function testAutowireClosure()
17201721
$container = new ContainerBuilder();
17211722
$container->register('foo', Foo::class)
17221723
->setPublic('true');
1724+
$container->register('my_callable', MyCallable::class)
1725+
->setPublic('true');
17231726
$container->register('baz', \Closure::class)
17241727
->setFactory(['Closure', 'fromCallable'])
17251728
->setArguments(['var_dump'])
@@ -1873,6 +1876,8 @@ public function __construct(
18731876
public \Closure $baz,
18741877
#[AutowireCallable(service: 'foo', method: 'cloneFoo')]
18751878
public \Closure $buz,
1879+
#[AutowireCallable(service: 'my_callable')]
1880+
public \Closure $bar,
18761881
) {
18771882
}
18781883
}

Tests/Fixtures/includes/autowiring_classes.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -558,3 +558,10 @@ interface SingleMethodInterface
558558
{
559559
public function theMethod();
560560
}
561+
562+
class MyCallable
563+
{
564+
public function __invoke(): void
565+
{
566+
}
567+
}

Tests/Fixtures/php/autowire_closure.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ public function __construct()
2525
'bar' => 'getBarService',
2626
'baz' => 'getBazService',
2727
'foo' => 'getFooService',
28+
'my_callable' => 'getMyCallableService',
2829
];
2930

3031
$this->aliases = [];
@@ -53,7 +54,7 @@ protected static function getBarService($container)
5354
$container = $containerRef->get();
5455

5556
return ($container->services['foo'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo());
56-
}, ($container->services['baz'] ?? self::getBazService($container)), ($container->services['foo'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo())->cloneFoo(...));
57+
}, ($container->services['baz'] ?? self::getBazService($container)), ($container->services['foo'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo())->cloneFoo(...), ($container->services['my_callable'] ??= new \Symfony\Component\DependencyInjection\Tests\Compiler\MyCallable())->__invoke(...));
5758
}
5859

5960
/**
@@ -75,4 +76,14 @@ protected static function getFooService($container)
7576
{
7677
return $container->services['foo'] = new \Symfony\Component\DependencyInjection\Tests\Compiler\Foo();
7778
}
79+
80+
/**
81+
* Gets the public 'my_callable' shared service.
82+
*
83+
* @return \Symfony\Component\DependencyInjection\Tests\Compiler\MyCallable
84+
*/
85+
protected static function getMyCallableService($container)
86+
{
87+
return $container->services['my_callable'] = new \Symfony\Component\DependencyInjection\Tests\Compiler\MyCallable();
88+
}
7889
}

0 commit comments

Comments
 (0)