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 f5b09f4

Browse filesBrowse files
committed
[DI] Add support for getter autowiring
1 parent 2183f98 commit f5b09f4
Copy full SHA for f5b09f4

File tree

3 files changed

+152
-7
lines changed
Filter options

3 files changed

+152
-7
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+56-7Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function process(ContainerBuilder $container)
4242
} finally {
4343
spl_autoload_unregister($throwingAutoloader);
4444

45-
// Free memory and remove circular reference to container
45+
// Free memory
4646
$this->reflectionClasses = array();
4747
$this->definedTypes = array();
4848
$this->types = null;
@@ -97,6 +97,7 @@ protected function processValue($value, $isRoot = false)
9797
}
9898

9999
$methodCalls = $this->autowireMethodCalls($reflectionClass, $methodCalls, $autowiredMethods);
100+
$overriddenGetters = $this->autowireOverridenGetters($value->getOverriddenGetters(), $autowiredMethods);
100101

101102
if ($constructor) {
102103
list(, $arguments) = array_shift($methodCalls);
@@ -110,6 +111,10 @@ protected function processValue($value, $isRoot = false)
110111
$value->setMethodCalls($methodCalls);
111112
}
112113

114+
if ($overriddenGetters !== $value->getOverriddenGetters()) {
115+
$value->setOverriddenGetters($overriddenGetters);
116+
}
117+
113118
return parent::processValue($value, $isRoot);
114119
}
115120

@@ -131,7 +136,7 @@ private function getMethodsToAutowire(\ReflectionClass $reflectionClass, array $
131136
$regexList[] = '/^'.str_replace('\*', '.*', preg_quote($pattern, '/')).'$/i';
132137
}
133138

134-
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) {
139+
foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $reflectionMethod) {
135140
if ($reflectionMethod->isStatic()) {
136141
continue;
137142
}
@@ -171,7 +176,7 @@ private function autowireMethodCalls(\ReflectionClass $reflectionClass, array $m
171176
list($method, $arguments) = $call;
172177
$method = $parameterBag->resolveValue($method);
173178

174-
if (isset($autowiredMethods[$lcMethod = strtolower($method)])) {
179+
if (isset($autowiredMethods[$lcMethod = strtolower($method)]) && $autowiredMethods[$lcMethod]->isPublic()) {
175180
$reflectionMethod = $autowiredMethods[$lcMethod];
176181
unset($autowiredMethods[$lcMethod]);
177182
} else {
@@ -184,15 +189,15 @@ private function autowireMethodCalls(\ReflectionClass $reflectionClass, array $m
184189
}
185190
}
186191

187-
$arguments = $this->autowireMethod($reflectionMethod, $arguments, true);
192+
$arguments = $this->autowireMethodCall($reflectionMethod, $arguments, true);
188193

189194
if ($arguments !== $call[1]) {
190195
$methodCalls[$i][1] = $arguments;
191196
}
192197
}
193198

194199
foreach ($autowiredMethods as $reflectionMethod) {
195-
if ($arguments = $this->autowireMethod($reflectionMethod, array(), false)) {
200+
if ($reflectionMethod->isPublic() && $arguments = $this->autowireMethodCall($reflectionMethod, array(), false)) {
196201
$methodCalls[] = array($reflectionMethod->name, $arguments);
197202
}
198203
}
@@ -201,7 +206,7 @@ private function autowireMethodCalls(\ReflectionClass $reflectionClass, array $m
201206
}
202207

203208
/**
204-
* Autowires the constructor or a setter.
209+
* Autowires the constructor or a method.
205210
*
206211
* @param \ReflectionMethod $reflectionMethod
207212
* @param array $arguments
@@ -211,7 +216,7 @@ private function autowireMethodCalls(\ReflectionClass $reflectionClass, array $m
211216
*
212217
* @throws RuntimeException
213218
*/
214-
private function autowireMethod(\ReflectionMethod $reflectionMethod, array $arguments, $mustAutowire)
219+
private function autowireMethodCall(\ReflectionMethod $reflectionMethod, array $arguments, $mustAutowire)
215220
{
216221
$didAutowire = false; // Whether any arguments have been autowired or not
217222
foreach ($reflectionMethod->getParameters() as $index => $parameter) {
@@ -292,6 +297,50 @@ private function autowireMethod(\ReflectionMethod $reflectionMethod, array $argu
292297
return $arguments;
293298
}
294299

300+
/**
301+
* Autowires getters.
302+
*
303+
* @param array $overridenGetters
304+
* @param array $autowiredMethod
305+
*
306+
* @return array
307+
*/
308+
private function autowireOverridenGetters(array $overridenGetters, array $autowiredMethod)
309+
{
310+
foreach ($autowiredMethod as $reflectionMethod) {
311+
if (isset($overridenGetters[strtolower($reflectionMethod->name)])
312+
|| !method_exists($reflectionMethod, 'getReturnType')
313+
|| 0 !== $reflectionMethod->getNumberOfParameters()
314+
|| $reflectionMethod->isFinal()
315+
|| $reflectionMethod->returnsReference()
316+
|| !($returnType = $reflectionMethod->getReturnType())
317+
) {
318+
continue;
319+
}
320+
321+
if (null === $this->types) {
322+
$this->populateAvailableTypes();
323+
}
324+
325+
$class = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType->__toString();
326+
if (isset($this->types[$class])) {
327+
$value = new Reference($this->types[$class]);
328+
} else {
329+
try {
330+
$value = $this->createAutowiredDefinition(new \ReflectionClass($class));
331+
} catch (\ReflectionException $e) {
332+
continue;
333+
} catch (RuntimeException $e) {
334+
continue;
335+
}
336+
}
337+
338+
$overridenGetters[$reflectionMethod->name] = $value;
339+
}
340+
341+
return $overridenGetters;
342+
}
343+
295344
/**
296345
* Populates the list of available types.
297346
*/

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
+31Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\DependencyInjection\ContainerBuilder;
1616
use Symfony\Component\DependencyInjection\Reference;
1717
use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic;
18+
use Symfony\Component\DependencyInjection\Tests\Fixtures\GetterOverriding;
1819

1920
/**
2021
* @author Kévin Dunglas <dunglas@gmail.com>
@@ -515,6 +516,31 @@ public function testExplicitMethodInjection()
515516
);
516517
}
517518

519+
/**
520+
* @requires PHP 7.1
521+
*/
522+
public function testGetterOverriding()
523+
{
524+
$container = new ContainerBuilder();
525+
$container->register('b', B::class);
526+
527+
$container
528+
->register('getter_overriding', GetterOverriding::class)
529+
->setOverriddenGetter('getExplicitlyDefined', new Reference('b'))
530+
->setAutowiredMethods(array('get*'))
531+
;
532+
533+
$pass = new AutowirePass();
534+
$pass->process($container);
535+
536+
$overridenGetters = $container->getDefinition('getter_overriding')->getOverriddenGetters();
537+
$this->assertEquals(array(
538+
'getexplicitlydefined' => new Reference('b'),
539+
'getfoo' => new Reference('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Foo'),
540+
'getbar' => new Reference('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Bar'),
541+
), $overridenGetters);
542+
}
543+
518544
/**
519545
* @dataProvider getCreateResourceTests
520546
*/
@@ -852,6 +878,11 @@ public function notASetter(A $a)
852878
{
853879
// should be called only when explicitly specified
854880
}
881+
882+
protected function setProtectedMethod(A $a)
883+
{
884+
// should not be called
885+
}
855886
}
856887

857888
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+
use Symfony\Component\DependencyInjection\Tests\Compiler\A;
15+
use Symfony\Component\DependencyInjection\Tests\Compiler\B;
16+
use Symfony\Component\DependencyInjection\Tests\Compiler\Bar;
17+
use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
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.