Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3efd930

Browse filesBrowse files
committed
[DI] Add support for getter autowiring
1 parent 9e6d6ba commit 3efd930
Copy full SHA for 3efd930

File tree

Expand file treeCollapse file tree

3 files changed

+153
-5
lines changed
Filter options
Expand file treeCollapse file tree

3 files changed

+153
-5
lines changed

‎src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+55-5Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ private function completeDefinition($id, Definition $definition, array $autowire
108108
$methodsCalled[$methodCall[0]] = true;
109109
}
110110

111+
foreach ($definition->getOverriddenGetters() as $overriddenGetter => $returnValue) {
112+
$methodsCalled[$overriddenGetter] = true;
113+
}
114+
111115
foreach ($this->getMethodsToAutowire($id, $reflectionClass, $autowiredMethods) as $reflectionMethod) {
112116
if (!isset($methodsCalled[$reflectionMethod->name])) {
113117
$this->autowireMethod($id, $definition, $reflectionMethod);
@@ -132,7 +136,7 @@ private function getMethodsToAutowire($id, \ReflectionClass $reflectionClass, ar
132136
$regexList[] = '/^'.str_replace('\*', '.*', preg_quote($pattern, '/')).'$/i';
133137
}
134138

135-
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
139+
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $reflectionMethod) {
136140
if ($reflectionMethod->isStatic()) {
137141
continue;
138142
}
@@ -164,6 +168,19 @@ private function getMethodsToAutowire($id, \ReflectionClass $reflectionClass, ar
164168
*/
165169
private function autowireMethod($id, Definition $definition, \ReflectionMethod $reflectionMethod)
166170
{
171+
if (null === $this->types) {
172+
$this->populateAvailableTypes();
173+
}
174+
175+
if ($this->overrideGetter($id, $definition, $reflectionMethod)) {
176+
return;
177+
}
178+
179+
if ($reflectionMethod->isProtected()) {
180+
// Only getter overriding is supported for protected methods
181+
return;
182+
}
183+
167184
if ($isConstructor = $reflectionMethod->isConstructor()) {
168185
$arguments = $definition->getArguments();
169186
} else {
@@ -193,10 +210,6 @@ private function autowireMethod($id, Definition $definition, \ReflectionMethod $
193210
continue;
194211
}
195212

196-
if (null === $this->types) {
197-
$this->populateAvailableTypes();
198-
}
199-
200213
if (isset($this->types[$typeHint->name])) {
201214
$value = new Reference($this->types[$typeHint->name]);
202215
$addMethodCall = true;
@@ -247,6 +260,43 @@ private function autowireMethod($id, Definition $definition, \ReflectionMethod $
247260
}
248261
}
249262

263+
/**
264+
* Getter injection.
265+
*
266+
* @param string $id
267+
* @param Definition $definition
268+
* @param \ReflectionMethod $reflectionMethod
269+
*
270+
* @return bool
271+
*/
272+
private function overrideGetter($id, Definition $definition, \ReflectionMethod $reflectionMethod)
273+
{
274+
if (!method_exists($reflectionMethod, 'getReturnType')) {
275+
return false;
276+
}
277+
278+
if (0 !== $reflectionMethod->getNumberOfParameters() || $reflectionMethod->isFinal() || $reflectionMethod->returnsReference() || !($returnType = $reflectionMethod->getReturnType())) {
279+
return false;
280+
}
281+
282+
$class = (string) $returnType;
283+
if (isset($this->types[$class])) {
284+
$value = new Reference($this->types[$class]);
285+
} else {
286+
try {
287+
$value = $this->createAutowiredDefinition(new \ReflectionClass($class), $id);
288+
} catch (\ReflectionException $e) {
289+
return false;
290+
} catch (RuntimeException $e) {
291+
return false;
292+
}
293+
}
294+
295+
$definition->setOverriddenGetter($reflectionMethod->name, $value);
296+
297+
return true;
298+
}
299+
250300
/**
251301
* Populates the list of available types.
252302
*/

‎src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
+33Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
1515
use Symfony\Component\DependencyInjection\ContainerBuilder;
1616
use Symfony\Component\DependencyInjection\Reference;
17+
use Symfony\Component\DependencyInjection\Tests\Fixtures\GetterOverriding;
18+
use Symfony\Component\HttpFoundation\RequestStack;
1719

1820
/**
1921
* @author Kévin Dunglas <dunglas@gmail.com>
@@ -497,6 +499,32 @@ public function testExplicitMethodInjection()
497499
);
498500
}
499501

502+
public function testGetterOverriding()
503+
{
504+
if (PHP_VERSION_ID < 70100) {
505+
$this->markTestSkipped('This test requires PHP 7.1 or superior');
506+
}
507+
508+
$container = new ContainerBuilder();
509+
$container->register('b', B::class);
510+
511+
$container
512+
->register('getter_overriding', GetterOverriding::class)
513+
->setOverriddenGetter('getExplicitlyDefined', new Reference('b'))
514+
->setAutowiredMethods(array('get*'))
515+
;
516+
517+
$pass = new AutowirePass();
518+
$pass->process($container);
519+
520+
$overridenGetters = $container->getDefinition('getter_overriding')->getOverriddenGetters();
521+
$this->assertEquals($overridenGetters, array(
522+
'getExplicitlyDefined' => new Reference('b'),
523+
'getFoo' => new Reference('autowired.symfony\component\dependencyinjection\tests\compiler\foo'),
524+
'getBar' => new Reference('autowired.symfony\component\dependencyinjection\tests\compiler\bar'),
525+
));
526+
}
527+
500528
/**
501529
* @dataProvider getCreateResourceTests
502530
*/
@@ -807,6 +835,11 @@ public function notASetter(A $a)
807835
{
808836
// should be called only when explicitly specified
809837
}
838+
839+
protected function setProtectedMethod(A $a)
840+
{
841+
// should not be called
842+
}
810843
}
811844

812845
class SetterInjectionCollision
+65Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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\Fixtures;
13+
14+
if (PHP_VERSION_ID >= 70100) {
15+
// define the class only when PHP >= 7.1
16+
return;
17+
}
18+
19+
/**
20+
* To test getter autowiring with PHP >= 7.1.
21+
*
22+
* @author Kévin Dunglas <dunglas@gmail.com>
23+
*/
24+
class GetterOverriding
25+
{
26+
public function getFoo(): ?Foo
27+
{
28+
// should be called
29+
}
30+
31+
protected function getBar(): Bar
32+
{
33+
// should be called
34+
}
35+
36+
public function getNoTypeHint()
37+
{
38+
// should not be called
39+
}
40+
41+
public function getUnknown(): NotExist
42+
{
43+
// should not be called
44+
}
45+
46+
public function getExplicitlyDefined(): B
47+
{
48+
// should be called but not autowired
49+
}
50+
51+
public function getScalar(): string
52+
{
53+
// should not be called
54+
}
55+
56+
final public function getFinal(): A
57+
{
58+
// should not be called
59+
}
60+
61+
public function &getReference(): A
62+
{
63+
// should not be called
64+
}
65+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.