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 59a4bf7

Browse filesBrowse files
[DI] Add side-effect-restricted variant for autowiring, based solely on ids
1 parent 4d48b58 commit 59a4bf7
Copy full SHA for 59a4bf7

File tree

17 files changed

+145
-74
lines changed
Filter options

17 files changed

+145
-74
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
+62-41Lines changed: 62 additions & 41 deletions
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
{
@@ -257,9 +258,9 @@ private function autowireMethod(\ReflectionMethod $reflectionMethod, array $argu
257258
continue;
258259
}
259260

260-
$typeName = InheritanceProxyHelper::getTypeHint($reflectionMethod, $parameter, true);
261+
$type = InheritanceProxyHelper::getTypeHint($reflectionMethod, $parameter, true);
261262

262-
if (!$typeName) {
263+
if (!$type) {
263264
// no default value? Then fail
264265
if (!$parameter->isOptional()) {
265266
throw new RuntimeException(sprintf('Cannot autowire service "%s": argument $%s of method %s::%s() must have a type-hint or be given a value explicitly.', $this->currentId, $parameter->name, $reflectionMethod->class, $reflectionMethod->name));
@@ -273,20 +274,14 @@ private function autowireMethod(\ReflectionMethod $reflectionMethod, array $argu
273274
continue;
274275
}
275276

276-
if ($value = $this->getAutowiredReference($typeName)) {
277-
$this->usedTypes[$typeName] = $this->currentId;
277+
if ($value = $this->getAutowiredReference($type)) {
278+
$this->usedTypes[$type] = $this->currentId;
278279
} elseif ($parameter->isDefaultValueAvailable()) {
279280
$value = $parameter->getDefaultValue();
280281
} elseif ($parameter->allowsNull()) {
281282
$value = null;
282283
} else {
283-
if ($classOrInterface = class_exists($typeName, false) ? 'class' : (interface_exists($typeName, false) ? 'interface' : null)) {
284-
$message = sprintf('Unable to autowire argument of type "%s" for the service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeName, $this->currentId, $classOrInterface);
285-
} else {
286-
$message = sprintf('Cannot autowire argument $%s of method %s::%s() for service "%s": Class %s does not exist.', $parameter->name, $reflectionMethod->class, $reflectionMethod->name, $this->currentId, $typeName);
287-
}
288-
289-
throw new RuntimeException($message);
284+
throw $this->createTypeNotFoundException($type, 'argument $'.$parameter->name.' of method '.$reflectionMethod->class.'::'.$reflectionMethod->name.'()');
290285
}
291286

292287
$arguments[$index] = $value;
@@ -313,24 +308,18 @@ private function autowireOverridenGetters(array $overridenGetters, array $autowi
313308
if (isset($overridenGetters[$lcMethod]) || $reflectionMethod->getNumberOfParameters() || $reflectionMethod->isConstructor()) {
314309
continue;
315310
}
316-
if (!$typeName = InheritanceProxyHelper::getTypeHint($reflectionMethod, null, true)) {
317-
$typeName = InheritanceProxyHelper::getTypeHint($reflectionMethod);
311+
if (!$type = InheritanceProxyHelper::getTypeHint($reflectionMethod, null, true)) {
312+
$type = InheritanceProxyHelper::getTypeHint($reflectionMethod);
318313

319-
throw new RuntimeException(sprintf('Cannot autowire service "%s": getter %s::%s() must%s be given a return value explicitly.', $this->currentId, $reflectionMethod->class, $reflectionMethod->name, $typeName ? '' : ' have a return-type hint or'));
314+
throw new RuntimeException(sprintf('Cannot autowire service "%s": getter %s::%s() must%s be given a return value explicitly.', $this->currentId, $reflectionMethod->class, $reflectionMethod->name, $type ? '' : ' have a return-type hint or'));
320315
}
321316

322-
if (!$typeRef = $this->getAutowiredReference($typeName)) {
323-
if ($classOrInterface = class_exists($typeName, false) ? 'class' : (interface_exists($typeName, false) ? 'interface' : null)) {
324-
$message = sprintf('Unable to autowire return type "%s" for service "%s". No services were found matching this %s and it cannot be auto-registered.', $typeName, $this->currentId, $classOrInterface);
325-
} else {
326-
$message = sprintf('Cannot autowire return type of getter %s::%s() for service "%s": Class %s does not exist.', $reflectionMethod->class, $reflectionMethod->name, $this->currentId, $typeName);
327-
}
328-
329-
throw new RuntimeException($message);
317+
if (!$typeRef = $this->getAutowiredReference($type)) {
318+
throw $this->createTypeNotFoundException($type, 'return type of getter '.$reflectionMethod->class.'::'.$reflectionMethod->name.'()');
330319
}
331320

332321
$overridenGetters[$lcMethod] = $typeRef;
333-
$this->usedTypes[$typeName] = $this->currentId;
322+
$this->usedTypes[$type] = $this->currentId;
334323
}
335324

336325
return $overridenGetters;
@@ -339,21 +328,23 @@ private function autowireOverridenGetters(array $overridenGetters, array $autowi
339328
/**
340329
* @return Reference|null A reference to the service matching the given type, if any
341330
*/
342-
private function getAutowiredReference($typeName, $autoRegister = true)
331+
private function getAutowiredReference($type, $autoRegister = true)
343332
{
344-
if ($this->container->has($typeName) && !$this->container->findDefinition($typeName)->isAbstract()) {
345-
return new Reference($typeName);
333+
if ($this->container->has($type) && !$this->container->findDefinition($type)->isAbstract()) {
334+
return new Reference($type);
346335
}
347336

348-
if (null === $this->types) {
349-
$this->populateAvailableTypes();
350-
}
337+
if (Definition::AUTOWIRE_BY_TYPE === $this->currentDefinition->getAutowired()) {
338+
if (null === $this->types) {
339+
$this->populateAvailableTypes();
340+
}
351341

352-
if (isset($this->types[$typeName])) {
353-
return new Reference($this->types[$typeName]);
342+
if (isset($this->types[$type])) {
343+
return new Reference($this->types[$type]);
344+
}
354345
}
355346

356-
if ($autoRegister && $class = $this->container->getReflectionClass($typeName, true)) {
347+
if ($autoRegister && $class = $this->container->getReflectionClass($type, true)) {
357348
return $this->createAutowiredDefinition($class);
358349
}
359350
}
@@ -459,18 +450,48 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
459450
}
460451

461452
$currentId = $this->currentId;
462-
$this->currentId = $argumentId = sprintf('autowired.%s', $typeHint->name);
453+
$this->currentId = $type = $typeHint->name;
463454

464-
$argumentDefinition = $this->container->register($argumentId, $typeHint->name);
465-
$argumentDefinition->setPublic(false);
466-
$argumentDefinition->setAutowired(true);
455+
$typeDefinition = (new Definition($typeHint->name))
456+
->setPublic(false)
457+
->setAutowired($this->currentDefinition->getAutowired())
458+
->addTag('container.autoregistered');
467459

468-
$this->populateAvailableType($argumentId, $argumentDefinition);
460+
if (null !== $this->types) {
461+
$this->populateAvailableType($type, $typeDefinition);
462+
}
469463

470-
$this->processValue($argumentDefinition, true);
471-
$this->currentId = $currentId;
464+
try {
465+
$this->processValue($typeDefinition, true);
466+
$this->container->setDefinition($type, $typeDefinition);
467+
} catch (RuntimeException $e) {
468+
return;
469+
} finally {
470+
$this->currentId = $currentId;
471+
}
472+
473+
return new Reference($type);
474+
}
475+
476+
private function createTypeNotFoundException($type, $label)
477+
{
478+
if (!$classOrInterface = class_exists($type, false) ? 'class' : (interface_exists($type, false) ? 'interface' : null)) {
479+
return new RuntimeException(sprintf('Cannot autowire %s for service "%s": Class or interface "%s" does not exist.', $label, $this->currentId, $type));
480+
}
481+
if (null === $this->types) {
482+
$this->populateAvailableTypes();
483+
}
484+
if (Definition::AUTOWIRE_BY_TYPE === $this->currentDefinition->getAutowired()) {
485+
$message = sprintf('No services were found matching the "%s" %s and it cannot be auto-registered', $type, $classOrInterface);
486+
} elseif (isset($this->ambiguousServiceTypes[$type])) {
487+
$message = sprintf('Service "%s" does not exist and it cannot be auto-registered. This type could be aliased to any of these existing services: "%s"', $type, implode('", "', $this->ambiguousServiceTypes[$type]));
488+
} elseif (isset($this->types[$type])) {
489+
$message = sprintf('Service "%s" does not exist and it cannot be auto-registered. This type could be aliased to the existing "%s" service', $type, $this->types[$type]);
490+
} else {
491+
$message = sprintf('Service "%s" does not exist and it cannot be auto-registered', $type);
492+
}
472493

473-
return new Reference($argumentId);
494+
return new RuntimeException(sprintf('Cannot autowire %s for service "%s": %s.', $label, $this->currentId, $message));
474495
}
475496

476497
/**

‎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

0 commit comments

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