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 c298f2a

Browse filesBrowse files
[DI] Add "by-id" autowiring: a side-effect free variant of it based on the class<>id convention
1 parent 2dfd136 commit c298f2a
Copy full SHA for c298f2a

File tree

18 files changed

+135
-25
lines changed
Filter options

18 files changed

+135
-25
lines changed

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php
+1-1Lines changed: 1 addition & 1 deletion
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->getAutowired() ? 'by-type' : 'by-id') : false,
225225
);
226226

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

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php
+1-1Lines changed: 1 addition & 1 deletion
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->getAutowired() ? 'by-type' : 'by-id') : 'no')
186186
;
187187

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

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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
+1-1Lines changed: 1 addition & 1 deletion
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->getAutowired() ? '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

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php
+1-1Lines changed: 1 addition & 1 deletion
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->getAutowired() ? 'by-type' : 'by-id') : 'false');
375375
$serviceXML->setAttribute('file', $definition->getFile());
376376

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

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+14-2Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,10 @@ private function getAutowiredReference($type, $autoRegister = true)
355355
return new Reference($type);
356356
}
357357

358+
if (Definition::AUTOWIRE_BY_ID === $this->currentDefinition->getAutowired()) {
359+
return;
360+
}
361+
358362
if (null === $this->types) {
359363
$this->populateAvailableTypes();
360364
}
@@ -505,10 +509,18 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
505509

506510
private function createTypeNotFoundMessage($type, $label)
507511
{
508-
if (!$classOrInterface = class_exists($type, false) ? 'class' : (interface_exists($type, false) ? 'interface' : null)) {
512+
$autowireById = Definition::AUTOWIRE_BY_ID === $this->currentDefinition->getAutowired();
513+
if (!$classOrInterface = class_exists($type, $autowireById) ? 'class' : (interface_exists($type, false) ? 'interface' : null)) {
509514
return sprintf('Cannot autowire service "%s": %s has type "%s" but this class does not exist.', $this->currentId, $label, $type);
510515
}
511-
$message = sprintf('no services were found matching the "%s" %s and it cannot be auto-registered for %s.', $type, $classOrInterface, $label);
516+
if (null === $this->types) {
517+
$this->populateAvailableTypes();
518+
}
519+
if ($autowireById) {
520+
$message = sprintf('%s references %s "%s" but no such service exists.%s', $label, $classOrInterface, $type, $this->createTypeAlternatives($type));
521+
} else {
522+
$message = sprintf('no services were found matching the "%s" %s and it cannot be auto-registered for %s.', $type, $classOrInterface, $label);
523+
}
512524

513525
return sprintf('Cannot autowire service "%s": %s', $this->currentId, $message);
514526
}

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/ResolveDefinitionTemplatesPass.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ private function doResolveDefinition(ChildDefinition $definition)
101101
$def->setFile($parentDef->getFile());
102102
$def->setPublic($parentDef->isPublic());
103103
$def->setLazy($parentDef->isLazy());
104-
$def->setAutowired($parentDef->isAutowired());
104+
$def->setAutowired($parentDef->getAutowired());
105105

106106
self::mergeDefinition($def, $definition);
107107

@@ -147,7 +147,7 @@ public static function mergeDefinition(Definition $def, ChildDefinition $definit
147147
$def->setDeprecated($definition->isDeprecated(), $definition->getDeprecationMessage('%service_id%'));
148148
}
149149
if (isset($changes['autowired'])) {
150-
$def->setAutowired($definition->isAutowired());
150+
$def->setAutowired($definition->getAutowired());
151151
}
152152
if (isset($changes['decorated_service'])) {
153153
$decoratedService = $definition->getDecoratedService();

‎src/Symfony/Component/DependencyInjection/Definition.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Definition.php
+21-3Lines changed: 21 additions & 3 deletions
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 bool|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/Dumper/PhpDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,10 +734,11 @@ private function addService($id, Definition $definition)
734734
}
735735

736736
if ($definition->isAutowired()) {
737+
$autowired = Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'types' : 'ids';
737738
$doc .= <<<EOF
738739
739740
*
740-
* This service is autowired.
741+
* This service is autowired by {$autowired}.
741742
EOF;
742743
}
743744

‎src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ private function addService($definition, $id, \DOMElement $parent)
199199
}
200200

201201
if ($definition->isAutowired()) {
202-
$service->setAttribute('autowire', 'true');
202+
$service->setAttribute('autowire', Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by-type' : 'by-id');
203203
}
204204

205205
foreach ($definition->getAutowiringTypes(false) as $autowiringTypeValue) {

‎src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ private function addService($id, $definition)
106106
}
107107

108108
if ($definition->isAutowired()) {
109-
$code .= " autowire: true\n";
109+
$code .= sprintf(" autowire: %s\n", Definition::AUTOWIRE_BY_TYPE === $definition->getAutowired() ? 'by_type' : 'by_id');
110110
}
111111

112112
$autowiringTypesCode = '';

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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+19-2Lines changed: 19 additions & 2 deletions
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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php
+8Lines changed: 8 additions & 0 deletions
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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
+10-4Lines changed: 10 additions & 4 deletions
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

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
+48Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
1616
use Symfony\Component\DependencyInjection\ContainerBuilder;
17+
use Symfony\Component\DependencyInjection\Definition;
1718
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
1819
use Symfony\Component\DependencyInjection\Reference;
1920
use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic;
@@ -755,6 +756,53 @@ public function testAlternatives()
755756
$pass = new AutowirePass();
756757
$pass->process($container);
757758
}
759+
760+
public function testById()
761+
{
762+
$container = new ContainerBuilder();
763+
764+
$container->register(A::class, A::class);
765+
$container->register(DInterface::class, F::class);
766+
$container->register('d', D::class)
767+
->setAutowired(Definition::AUTOWIRE_BY_ID);
768+
769+
$pass = new AutowirePass();
770+
$pass->process($container);
771+
772+
$this->assertSame(array('service_container', A::class, DInterface::class, 'd'), array_keys($container->getDefinitions()));
773+
$this->assertEquals(array(new Reference(A::class), new Reference(DInterface::class)), $container->getDefinition('d')->getArguments());
774+
}
775+
776+
public function testByIdDoesNotAutoregister()
777+
{
778+
$container = new ContainerBuilder();
779+
780+
$container->register('f', F::class);
781+
$container->register('e', E::class)
782+
->setAutowired(Definition::AUTOWIRE_BY_ID);
783+
784+
$pass = new AutowirePass();
785+
$pass->process($container);
786+
787+
$this->assertSame(array('service_container', 'f', 'e'), array_keys($container->getDefinitions()));
788+
}
789+
790+
/**
791+
* @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException
792+
* @expectedExceptionMessage Cannot autowire service "j": argument $i of method Symfony\Component\DependencyInjection\Tests\Compiler\J::__construct() references class "Symfony\Component\DependencyInjection\Tests\Compiler\I" but no such service exists. This type-hint could be aliased to the existing "i" service; or be updated to "Symfony\Component\DependencyInjection\Tests\Compiler\IInterface".
793+
*/
794+
public function testByIdAlternative()
795+
{
796+
$container = new ContainerBuilder();
797+
798+
$container->setAlias(IInterface::class, 'i');
799+
$container->register('i', I::class);
800+
$container->register('j', J::class)
801+
->setAutowired(Definition::AUTOWIRE_BY_ID);
802+
803+
$pass = new AutowirePass();
804+
$pass->process($container);
805+
}
758806
}
759807

760808
class Foo

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services24.php
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public function isFrozen()
7070
* This service is shared.
7171
* This method always returns the same instance of the service.
7272
*
73-
* This service is autowired.
73+
* This service is autowired by types.
7474
*
7575
* @return \Foo A Foo instance
7676
*/

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ protected function getTestServiceSubscriberService()
9191
* This service is shared.
9292
* This method always returns the same instance of the service.
9393
*
94-
* This service is autowired.
94+
* This service is autowired by types.
9595
*
9696
* @return \TestServiceSubscriber A TestServiceSubscriber instance
9797
*/
@@ -118,7 +118,7 @@ protected function getFooServiceService()
118118
* If you want to be able to request this service from the container directly,
119119
* make it public, otherwise you might end up with broken code.
120120
*
121-
* This service is autowired.
121+
* This service is autowired by types.
122122
*
123123
* @return \stdClass A stdClass instance
124124
*/

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services24.xml

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services24.xml
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
33
<services>
44
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" synthetic="true"/>
5-
<service id="foo" class="Foo" autowire="true"/>
5+
<service id="foo" class="Foo" autowire="by-type"/>
66
<service id="Psr\Container\ContainerInterface" alias="service_container" public="false"/>
77
<service id="Symfony\Component\DependencyInjection\ContainerInterface" alias="service_container" public="false"/>
88
</services>

‎src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services24.yml

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services24.yml
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ services:
55
synthetic: true
66
foo:
77
class: Foo
8-
autowire: true
8+
autowire: by_type
99
Psr\Container\ContainerInterface:
1010
alias: service_container
1111
public: false

0 commit comments

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