Skip to content

Commit 50852ed

Browse files
[DI] Add side-effect-restricted variant for autowiring, based solely on ids
1 parent e41064f commit 50852ed

File tree

10 files changed

+85
-30
lines changed

10 files changed

+85
-30
lines changed

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ private function getContainerDefinitionData(Definition $definition, $omitTags =
221221
'lazy' => $definition->isLazy(),
222222
'shared' => $definition->isShared(),
223223
'abstract' => $definition->isAbstract(),
224-
'autowire' => $definition->isAutowired(),
224+
'autowire' => $definition->isAutowired() ? (Definition::AUTOWIRE_BY_TYPE === $definition->getAutowiredBy() ? 'by-type' : 'by-id') : false,
225225
);
226226

227227
foreach ($definition->getAutowiringTypes(false) as $autowiringType) {

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ protected function describeContainerDefinition(Definition $definition, array $op
182182
."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no')
183183
."\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no')
184184
."\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no')
185-
."\n".'- Autowired: '.($definition->isAutowired() ? 'yes' : 'no')
185+
."\n".'- Autowired: '.($definition->isAutowired() ? (Definition::AUTOWIRE_BY_TYPE === $definition->getAutowiredBy() ? 'by-type' : 'by-id') : 'no')
186186
;
187187

188188
foreach ($definition->getAutowiringTypes(false) as $autowiringType) {

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ protected function describeContainerDefinition(Definition $definition, array $op
295295
$tableRows[] = array('Lazy', $definition->isLazy() ? 'yes' : 'no');
296296
$tableRows[] = array('Shared', $definition->isShared() ? 'yes' : 'no');
297297
$tableRows[] = array('Abstract', $definition->isAbstract() ? 'yes' : 'no');
298-
$tableRows[] = array('Autowired', $definition->isAutowired() ? 'yes' : 'no');
298+
$tableRows[] = array('Autowired', $definition->isAutowired() ? (Definition::AUTOWIRE_BY_TYPE === $definition->getAutowiredBy() ? 'by-type' : 'by-id') : 'no');
299299

300300
if ($autowiringTypes = $definition->getAutowiringTypes(false)) {
301301
$tableRows[] = array('Autowiring Types', implode(', ', $autowiringTypes));

src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ private function getContainerDefinitionDocument(Definition $definition, $id = nu
371371
$serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false');
372372
$serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false');
373373
$serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false');
374-
$serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false');
374+
$serviceXML->setAttribute('autowired', $definition->isAutowired() ? (Definition::AUTOWIRE_BY_TYPE === $definition->getAutowiredBy() ? 'by-type' : 'by-id') : 'false');
375375
$serviceXML->setAttribute('file', $definition->getFile());
376376

377377
$calls = $definition->getMethodCalls();

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

+15-9
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@
2020
use Symfony\Component\DependencyInjection\TypedReference;
2121

2222
/**
23-
* Guesses constructor arguments of services definitions and try to instantiate services if necessary.
23+
* Inspects existing service definitions and wires the autowired ones using the type hints of their classes.
2424
*
2525
* @author Kévin Dunglas <dunglas@gmail.com>
26+
* @author Nicolas Grekas <p@tchwork.com>
2627
*/
2728
class AutowirePass extends AbstractRecursivePass
2829
{
@@ -345,12 +346,14 @@ private function getAutowiredReference($typeName, $autoRegister = true)
345346
return new Reference($typeName);
346347
}
347348

348-
if (null === $this->types) {
349-
$this->populateAvailableTypes();
350-
}
349+
if (Definition::AUTOWIRE_BY_TYPE === $this->currentDefinition->getAutowired()) {
350+
if (null === $this->types) {
351+
$this->populateAvailableTypes();
352+
}
351353

352-
if (isset($this->types[$typeName])) {
353-
return new Reference($this->types[$typeName]);
354+
if (isset($this->types[$typeName])) {
355+
return new Reference($this->types[$typeName]);
356+
}
354357
}
355358

356359
if ($autoRegister && $class = $this->container->getReflectionClass($typeName, true)) {
@@ -459,13 +462,16 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
459462
}
460463

461464
$currentId = $this->currentId;
462-
$this->currentId = $argumentId = sprintf('autowired.%s', $typeHint->name);
465+
$this->currentId = $argumentId = $typeHint->name;
463466

464467
$argumentDefinition = $this->container->register($argumentId, $typeHint->name);
465468
$argumentDefinition->setPublic(false);
466-
$argumentDefinition->setAutowired(true);
469+
$argumentDefinition->setAutowired($this->currentDefinition->getAutowired());
470+
$argumentDefinition->addTag('container.autoregistered');
467471

468-
$this->populateAvailableType($argumentId, $argumentDefinition);
472+
if (null !== $this->types) {
473+
$this->populateAvailableType($argumentId, $argumentDefinition);
474+
}
469475

470476
$this->processValue($argumentDefinition, true);
471477
$this->currentId = $currentId;

src/Symfony/Component/DependencyInjection/Definition.php

+21-3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
*/
2222
class Definition
2323
{
24+
const AUTOWIRE_BY_TYPE = 1;
25+
const AUTOWIRE_BY_ID = 2;
26+
2427
private $class;
2528
private $file;
2629
private $factory;
@@ -38,7 +41,7 @@ class Definition
3841
private $abstract = false;
3942
private $lazy = false;
4043
private $decoratedService;
41-
private $autowired = false;
44+
private $autowired = 0;
4245
private $autowiringTypes = array();
4346

4447
protected $arguments;
@@ -736,20 +739,35 @@ public function setAutowiringTypes(array $types)
736739
* @return bool
737740
*/
738741
public function isAutowired()
742+
{
743+
return (bool) $this->autowired;
744+
}
745+
746+
/**
747+
* Gets the autowiring mode.
748+
*
749+
* @return int
750+
*/
751+
public function getAutowired()
739752
{
740753
return $this->autowired;
741754
}
742755

743756
/**
744757
* Sets autowired.
745758
*
746-
* @param bool $autowired
759+
* @param int $autowired
747760
*
748761
* @return $this
749762
*/
750763
public function setAutowired($autowired)
751764
{
752-
$this->autowired = (bool) $autowired;
765+
$autowired = (int) $autowired;
766+
767+
if ($autowired && self::AUTOWIRE_BY_TYPE !== $autowired && self::AUTOWIRE_BY_ID !== $autowired) {
768+
throw new InvalidArgumentException(sprintf('Invalid argument: Definition::AUTOWIRE_BY_TYPE (%d) or Definition::AUTOWIRE_BY_ID (%d) expected, %d given.', self::AUTOWIRE_BY_TYPE, self::AUTOWIRE_BY_ID, $autowired));
769+
}
770+
$this->autowired = $autowired;
753771

754772
return $this;
755773
}

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

+19-2
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ private function getServiceDefaults(\DOMDocument $xml, $file)
172172
}
173173
}
174174
if ($defaultsNode->hasAttribute('autowire')) {
175-
$defaults['autowire'] = XmlUtils::phpize($defaultsNode->getAttribute('autowire'));
175+
$defaults['autowire'] = $this->getAutowired($defaultsNode->getAttribute('autowire'), $file);
176176
}
177177
if ($defaultsNode->hasAttribute('public')) {
178178
$defaults['public'] = XmlUtils::phpize($defaultsNode->getAttribute('public'));
@@ -238,7 +238,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults =
238238
}
239239

240240
if ($value = $service->getAttribute('autowire')) {
241-
$definition->setAutowired(XmlUtils::phpize($value));
241+
$definition->setAutowired($this->getAutowired($value, $file));
242242
} elseif (isset($defaults['autowire'])) {
243243
$definition->setAutowired($defaults['autowire']);
244244
}
@@ -666,6 +666,23 @@ private function loadFromExtensions(\DOMDocument $xml)
666666
}
667667
}
668668

669+
private function getAutowired($value, $file)
670+
{
671+
if (is_bool($value = XmlUtils::phpize($value))) {
672+
return $value;
673+
}
674+
675+
if ('by-type' === $value) {
676+
return Definition::AUTOWIRE_BY_TYPE;
677+
}
678+
679+
if ('by-id' === $value) {
680+
return Definition::AUTOWIRE_BY_ID;
681+
}
682+
683+
throw new InvalidArgumentException(sprintf('Invalid autowire attribute: "by-type", "by-id", "true" or "false" expected, "%s" given in "%s".', $value, $file));
684+
}
685+
669686
/**
670687
* Converts a \DomElement object to a PHP array.
671688
*

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

+8
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,14 @@ private function parseDefinition($id, $service, $file, array $defaults)
500500

501501
$autowire = isset($service['autowire']) ? $service['autowire'] : (isset($defaults['autowire']) ? $defaults['autowire'] : null);
502502
if (null !== $autowire) {
503+
if ('by_type' === $autowire) {
504+
$autowire = Definition::AUTOWIRE_BY_TYPE;
505+
} elseif ('by_id' === $autowire) {
506+
$autowire = Definition::AUTOWIRE_BY_ID;
507+
} elseif (!is_bool($autowire)) {
508+
throw new InvalidArgumentException(sprintf('Invalid autowire attribute: "by_type", "by_id", true or false expected, "%s" given in "%s".', is_string($autowire) ? $autowire : gettype($autowire), $file));
509+
}
510+
503511
$definition->setAutowired($autowire);
504512
}
505513

src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd

+10-4
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@
102102
<xsd:element name="tag" type="tag" minOccurs="0" maxOccurs="unbounded" />
103103
</xsd:choice>
104104
<xsd:attribute name="public" type="boolean" />
105-
<xsd:attribute name="autowire" type="boolean" />
105+
<xsd:attribute name="autowire" type="autowire" />
106106
<xsd:attribute name="inherit-tags" type="boolean" />
107107
</xsd:complexType>
108108

@@ -131,7 +131,7 @@
131131
<xsd:attribute name="decorates" type="xsd:string" />
132132
<xsd:attribute name="decoration-inner-name" type="xsd:string" />
133133
<xsd:attribute name="decoration-priority" type="xsd:integer" />
134-
<xsd:attribute name="autowire" type="boolean" />
134+
<xsd:attribute name="autowire" type="autowire" />
135135
<xsd:attribute name="inherit-tags" type="boolean" />
136136
</xsd:complexType>
137137

@@ -151,7 +151,7 @@
151151
<xsd:attribute name="public" type="boolean" />
152152
<xsd:attribute name="lazy" type="boolean" />
153153
<xsd:attribute name="abstract" type="boolean" />
154-
<xsd:attribute name="autowire" type="boolean" />
154+
<xsd:attribute name="autowire" type="autowire" />
155155
</xsd:complexType>
156156

157157
<xsd:complexType name="prototype">
@@ -172,7 +172,7 @@
172172
<xsd:attribute name="lazy" type="boolean" />
173173
<xsd:attribute name="abstract" type="boolean" />
174174
<xsd:attribute name="parent" type="xsd:string" />
175-
<xsd:attribute name="autowire" type="boolean" />
175+
<xsd:attribute name="autowire" type="autowire" />
176176
<xsd:attribute name="inherit-tags" type="boolean" />
177177
</xsd:complexType>
178178

@@ -279,4 +279,10 @@
279279
<xsd:pattern value="(%.+%|true|false)" />
280280
</xsd:restriction>
281281
</xsd:simpleType>
282+
283+
<xsd:simpleType name="autowire">
284+
<xsd:restriction base="xsd:string">
285+
<xsd:pattern value="(true|false|by-type|by-id)" />
286+
</xsd:restriction>
287+
</xsd:simpleType>
282288
</xsd:schema>

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

+8-8
Original file line numberDiff line numberDiff line change
@@ -235,15 +235,15 @@ public function testCreateDefinition()
235235
$pass->process($container);
236236

237237
$this->assertCount(1, $container->getDefinition('coop_tilleuls')->getArguments());
238-
$this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas', $container->getDefinition('coop_tilleuls')->getArgument(0));
238+
$this->assertEquals(Dunglas::class, $container->getDefinition('coop_tilleuls')->getArgument(0));
239239

240-
$dunglasDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas');
240+
$dunglasDefinition = $container->getDefinition(Dunglas::class);
241241
$this->assertEquals(__NAMESPACE__.'\Dunglas', $dunglasDefinition->getClass());
242242
$this->assertFalse($dunglasDefinition->isPublic());
243243
$this->assertCount(1, $dunglasDefinition->getArguments());
244-
$this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille', $dunglasDefinition->getArgument(0));
244+
$this->assertEquals(Lille::class, $dunglasDefinition->getArgument(0));
245245

246-
$lilleDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille');
246+
$lilleDefinition = $container->getDefinition(Lille::class);
247247
$this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass());
248248
}
249249

@@ -532,7 +532,7 @@ public function testTypedReference()
532532
$pass = new AutowirePass();
533533
$pass->process($container);
534534

535-
$this->assertSame(A::class, $container->getDefinition('autowired.'.A::class)->getClass());
535+
$this->assertSame(A::class, $container->getDefinition(A::class)->getClass());
536536
}
537537

538538
/**
@@ -555,8 +555,8 @@ public function testGetterOverriding()
555555
$overridenGetters = $container->getDefinition('getter_overriding')->getOverriddenGetters();
556556
$this->assertEquals(array(
557557
'getexplicitlydefined' => new Reference('b'),
558-
'getfoo' => new Reference('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Foo'),
559-
'getbar' => new Reference('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Bar'),
558+
'getfoo' => new Reference(Foo::class),
559+
'getbar' => new Reference(Bar::class),
560560
), $overridenGetters);
561561
}
562562

@@ -666,7 +666,7 @@ public function testEmptyStringIsKept()
666666
* @dataProvider provideAutodiscoveredAutowiringOrder
667667
*
668668
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
669-
* @expectedExceptionMEssage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA, autowired.Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB).
669+
* @expectedExceptionMEssage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "a". Multiple services exist for this interface (Symfony\Component\DependencyInjection\Tests\Compiler\CollisionA, Symfony\Component\DependencyInjection\Tests\Compiler\CollisionB).
670670
*/
671671
public function testAutodiscoveredAutowiringOrder($class)
672672
{

0 commit comments

Comments
 (0)