8000 [DI] Allow extensions to create ServiceLocator as services · symfony/symfony@7ccc6aa · GitHub
[go: up one dir, main page]

Skip to content

Commit 7ccc6aa

Browse files
[DI] Allow extensions to create ServiceLocator as services
1 parent e58be70 commit 7ccc6aa

18 files changed

+120
-134
lines changed

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ private function getContainerDefinitionData(Definition $definition, $omitTags =
232232
}
233233

234234
if ($showArguments) {
235-
$data['arguments'] = $this->describeValue($definition->getArguments(), $omitTags, $showArguments);
235+
$data['arguments'] = $this->describeValue($definition instanceof ArgumentInterface ? $definition->getValues() : $definition->getArguments(), $omitTags, $showArguments);
236236
}
237237

238238
$data['file'] = $definition->getFile();
@@ -399,14 +399,14 @@ private function describeValue($value, $omitTags, $showArguments)
399399
);
400400
}
401401

402-
if ($value instanceof Definition) {
403-
return $this->getContainerDefinitionData($value, $omitTags, $showArguments);
404-
}
405-
406402
if ($value instanceof ArgumentInterface) {
407403
return $this->describeValue($value->getValues(), $omitTags, $showArguments);
408404
}
409405

406+
if ($value instanceof Definition) {
407+
return $this->getContainerDefinitionData($value, $omitTags, $showArguments);
408+
}
409+
410410
return $value;
411411
}
412412
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
1313

1414
use Symfony\Component\DependencyInjection\Alias;
15+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1516
use Symfony\Component\DependencyInjection\ContainerBuilder;
1617
use Symfony\Component\DependencyInjection\Definition;
1718
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
@@ -197,7 +198,7 @@ protected function describeContainerDefinition(Definition $definition, array $op
197198
}
198199

199200
if (isset($options['show_arguments']) && $options['show_arguments']) {
200-
$output .= "\n".'- Arguments: '.($definition->getArguments() ? 'yes' : 'no');
201+
$output .= "\n".'- Arguments: '.(($definition instanceof ArgumentInterface ? $definition->getValues() : $definition->getArguments()) ? 'yes' : 'no');
201202
}
202203

203204
if ($definition->getFile()) {

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Console\Helper\Table;
1515
use Symfony\Component\Console\Style\SymfonyStyle;
1616
use Symfony\Component\DependencyInjection\Alias;
17+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1718
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
1819
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
1920
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
@@ -326,19 +327,19 @@ protected function describeContainerDefinition(Definition $definition, array $op
326327

327328
$showArguments = isset($options['show_arguments']) && $options['show_arguments'];
328329
$argumentsInformation = array();
329-
if ($showArguments && ($arguments = $definition->getArguments())) {
330+
if ($showArguments && $arguments = $definition instanceof ArgumentInterface ? $definition->getValues() : $definition->getArguments()) {
330331
foreach ($arguments as $argument) {
331332
if ($argument instanceof Reference) {
332333
$argumentsInformation[] = sprintf('Service(%s)', (string) $argument);
333-
} elseif ($argument instanceof Definition) {
334-
$argumentsInformation[] = 'Inlined Service';
335334
} elseif ($argument instanceof IteratorArgument) {
336335
$argumentsInformation[] = sprintf('Iterator (%d element(s))', count($argument->getValues()));
337336
} elseif ($argument instanceof ServiceLocatorArgument) {
338337
$argumentsInformation[] = sprintf('ServiceLocator (%d service(s))', count($argument->getValues()));
339338
} elseif ($argument instanceof ClosureProxyArgument) {
340339
list($reference, $method) = $argument->getValues();
341340
$argumentsInformation[] = sprintf('ClosureProxy(Service(%s)::%s())', $reference, $method);
341+
} elseif ($argument instanceof Definition) {
342+
$argumentsInformation[] = 'Inlined Service';
342343
} else {
343344
$argumentsInformation[] = is_array($argument) ? sprintf('Array (%d element(s))', count($argument)) : $argument;
344345
}

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

Lines changed: 4 additions & 3 deletions
E377
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor;
1313

1414
use Symfony\Component\DependencyInjection\Alias;
15+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1516
use Symfony\Component\DependencyInjection\Argument\ClosureProxyArgument;
1617
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
1718
use Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument;
@@ -396,7 +397,7 @@ private function getContainerDefinitionDocument(Definition $definition, $id = nu
396397
}
397398

398399
if ($showArguments) {
399-
foreach ($this->getArgumentNodes($definition->getArguments(), $dom) as $node) {
400+
foreach ($this->getArgumentNodes($definition instanceof ArgumentInterface ? $definition->getValues() : $definition->getArguments(), $dom) as $node) {
400401
$serviceXML->appendChild($node);
401402
}
402403
}
@@ -440,8 +441,6 @@ private function getArgumentNodes(array $arguments, \DOMDocument $dom)
440441
if ($argument instanceof Reference) {
441442
$argumentXML->setAttribute('type', 'service');
442443
$argumentXML->setAttribute('id', (string) $argument);
443-
} elseif ($argument instanceof Definition) {
444-
$argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true)->childNodes->item(0), true));
445444
} elseif ($argument instanceof IteratorArgument) {
446445
$argumentXML->setAttribute('type', 'iterator');
447446

@@ -459,6 +458,8 @@ private function getArgumentNodes(array $arguments, \DOMDocument $dom)
459458
$argumentXML->setAttribute('type', 'closure-proxy');
460459
$argumentXML->setAttribute('id', (string) $reference);
461460
$argumentXML->setAttribute('method', $method);
461+
} elseif ($argument instanceof Definition) {
462+
$argumentXML->appendChild($dom->importNode($this->getContainerDefinitionDocument($argument, null, false, true)->childNodes->item(0), true));
462463
} elseif (is_array($argument)) {
463464
$argumentXML->setAttribute('type', 'collection');
464465

src/Symfony/Component/DependencyInjection/Argument/ServiceLocatorArgument.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Argument;
1313

14-
use Symfony\Component\DependencyInjection\Reference;
14+
use Symfony\Component\DependencyInjection\Definition;
1515
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
16+
use Symfony\Component\DependencyInjection\Reference;
17+
use Symfony\Component\DependencyInjection\ServiceLocator;
1618

1719
/**
1820
* Represents a service locator able to lazy load a given range of services.
@@ -21,7 +23,7 @@
2123
*
2224
* @experimental in version 3.3
2325
*/
24-
class ServiceLocatorArgument implements ArgumentInterface
26+
class ServiceLocatorArgument extends Definition implements ArgumentInterface
2527
{
2628
private $values;
2729

@@ -31,6 +33,8 @@ class ServiceLocatorArgument implements ArgumentInterface
3133
public function __construct(array $values)
3234
{
3335
$this->setValues($values);
36+
37+
parent::__construct(ServiceLocator::class);
3438
}
3539

3640
public function getValues()

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,11 @@ protected function processValue($value, $isRoot = false)
7373
$lazy = $this->lazy;
7474

7575
if ($value instanceof ArgumentInterface) {
76+
if ($isRoot && $value instanceof Definition) {
77+
$this->currentDefinition = $value;
78+
}
7679
$this->lazy = true;
77-
parent::processValue($value);
80+
parent::processValue($value->getValues());
7881
$this->lazy = $lazy;
7982

8083
return $value;

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

Lines changed: 38 additions & 88 deletions
356
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\DependencyInjection\ContainerBuilder;
1616
use Symfony\Component\DependencyInjection\Definition;
1717
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
18+
use Symfony\Component\DependencyInjection\LazyProxy\InheritanceProxyHelper;
1819
use Symfony\Component\DependencyInjection\Reference;
1920

2021
/**
@@ -248,13 +249,7 @@ private function autowireMethod(\ReflectionMethod $reflectionMethod, array $argu
248249
continue;
249250
}
250251

251-
if (method_exists($parameter, 'getType')) {
252-
if ($typeName = $parameter->getType()) {
253-
$typeName = $typeName->isBuiltin() ? null : ($typeName instanceof \ReflectionNamedType ? $typeName->getName() : $typeName->__toString());
254-
}
255-
} elseif (preg_match('/^(?:[^ ]++ ){4}([a-zA-Z_\x7F-\xFF][^ ]++)/', $parameter, $typeName)) {
256-
$typeName = 'callable' === $typeName[1] || 'array' === $typeName[1] ? null : $typeName[1];
257-
}
252+
$typeName = InheritanceProxyHelper::getTypeHint($reflectionMethod, $parameter, true);
258253

259254
if (!$typeName) {
260255
// no default value? Then fail
@@ -274,52 +269,17 @@ private function autowireMethod(\ReflectionMethod $reflectionMethod, array $argu
274269
continue;
275270
}
276271

277-
if ($this->container->has($typeName) && !$this->container->findDefinition($typeName)->isAbstract()) {
278-
$arguments[$index] = new Reference($typeName);
279-
$didAutowire = true;
280-
281-
continue;
282-
}
283-
284-
if (null === $this->types) {
285-
$this->populateAvailableTypes();
286-
}
287-
288-
if (isset($this->types[$typeName])) {
289-
$value = new Reference($this->types[$typeName]);
272+
if ($value = $this->getAutowiredReference($typeName)) {
290273
$didAutowire = true;
291274
$this->usedTypes[$typeName] = $this->currentId;
292-
} elseif ($typeHint = $this->container->getReflectionClass($typeName, true)) {
293-
try {
294-
$value = $this->createAutowiredDefinition($typeHint);
295-
$didAutowire = true;
296-
$this->usedTypes[$typeName] = $this->currentId;
297-
} catch (RuntimeException $e) {
298-
if ($parameter->allowsNull()) {
299-
$value = null;
300-
} elseif ($parameter->isDefaultValueAvailable()) {
301-
$value = $parameter->getDefaultValue();
302-
} else {
303-
// The exception code is set to 1 if the exception must be thrown even if it's an optional setter
304 10000 -
if (1 === $e->getCode() || self::MODE_REQUIRED === $mode) {
305-
throw $e;
306-
}
307-
308-
return array();
309-
}
310-
}
311-
} else {
312-
// Typehint against a non-existing class
313-
314-
if (!$parameter->isDefaultValueAvailable()) {
315-
if (self::MODE_REQUIRED === $mode) {
316-
throw new RuntimeException(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));
317-
}
318-
319-
return array();
320-
}
321-
275+
} elseif ($parameter->allowsNull()) {
276+
$value = null;
277+
} elseif ($parameter->isDefaultValueAvailable()) {
322278
$value = $parameter->getDefaultValue();
279+
} elseif (self::MODE_REQUIRED === $mode) {
280+
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". No matching services were found and it cannot be auto-registered.', $typeName, $this->currentId));
281+
} else {
282+
return array();
323283
}
324284

325285
$arguments[$index] = $value;
@@ -352,42 +312,39 @@ private function autowireOverridenGetters(array $overridenGetters, array $autowi
352312
|| 0 !== $reflectionMethod->getNumberOfParameters()
353313
|| $reflectionMethod->isFinal()
354314
|| $reflectionMethod->returnsReference()
355-
|| !$returnType = $reflectionMethod->getReturnType()
315+
|| !($typeName = InheritanceProxyHelper::getTypeHint($reflectionMethod, null, true))
316+
|| !($typeRef = $this->getAutowiredReference($typeName))
317
) {
357318
continue;
358319
}
359-
$typeName = $returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType->__toString();
360320

361-
if ($this->container->has($typeName) && !$this->container->findDefinition($typeName)->isAbstract()) {
362-
$overridenGetters[$lcMethod] = new Reference($typeName);
363-
continue;
364-
}
321+
$overridenGetters[$lcMethod] = $typeRef;
322+
$this->usedTypes[$typeName] = $this->currentId;
323+
}
365324

366-
if (null === $this->types) {
367-
$this->populateAvailableTypes();
368-
}
325+
return $overridenGetters;
326+
}
369327

370-
if (isset($this->types[$typeName])) {
371-
$value = new Reference($this->types[$typeName]);
372-
} elseif ($returnType = $this->container->getReflectionClass($typeName, true)) {
373-
try {
374-
$value = $this->createAutowiredDefinition($returnType);
375-
} catch (RuntimeException $e) {
376-
if (1 === $e->getCode()) {
377-
throw $e;
378-
}
328+
/**
329+
* @return Reference|null A reference to the service matching the given type, if any
330+
*/
331+
private function getAutowiredReference($typeName, $autoRegister = true)
332+
{
333+
if ($this->container->has($typeName) && !$this->container->findDefinition($typeName)->isAbstract()) {
334+
return new Reference($typeName);
335+
}
379336

380-
continue;
381-
}
382-
} else {
383-
continue;
384-
}
337+
if (null === $this->types) {
338+
$this->populateAvailableTypes();
339+
}
385340

386-
$overridenGetters[$lcMethod] = $value;
387-
$this->usedTypes[$typeName] = $this->currentId;
341+
if (isset($this->types[$typeName])) {
342+
return new Reference($this->types[$typeName]);
388343
}
389344

390-
return $overridenGetters;
345+
if ($autoRegister && $class = $this->container->getReflectionClass($typeName, true)) {
346+
return $this->createAutowiredDefinition($class);
347+
}
391348
}
392349

393350
/**
@@ -473,7 +430,7 @@ private function set($type, $id)
473430
*
474431
* @param \ReflectionClass $typeHint
475432
*
476-
* @return Reference A reference to the registered definition
433+
* @return Reference|null A reference to the registered definition
477434
*
478435
* @throws RuntimeException
479436
*/
@@ -483,12 +440,11 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
483440
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
484441
$matchingServices = implode(', ', $this->ambiguousServiceTypes[$typeHint->name]);
485442

486-
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $this->currentId, $classOrInterface, $matchingServices), 1);
443+
throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the ser F438 vice "%s". Multiple services exist for this %s (%s).', $typeHint->name, $this->currentId, $classOrInterface, $matchingServices));
487444
}
488445

489446
if (!$typeHint->isInstantiable()) {
490-
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
491-
throw new RuntimeException(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.', $typeHint->name, $this->currentId, $classOrInterface));
447+
return;
492448
}
493449

494450
$currentId = $this->currentId;
@@ -500,14 +456,8 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint)
500456

501457
$this->populateAvailableType($argumentId, $argumentDefinition);
502458

503-
try {
504-
$this->processValue($argumentDefinition, true);
505-
$this->currentId = $currentId;
506-
} catch (RuntimeException $e) {
507-
$classOrInterface = $typeHint->isInterface() ? 'interface' : 'class';
508-
$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.', $typeHint->name, $this->currentId, $classOrInterface);
509-
throw new RuntimeException($message, 0, $e);
510-
}
459+
$this->processValue($argumentDefinition, true);
460+
$this->currentId = $currentId;
511461

512462
return new Reference($argumentId);
513463
}

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ public function process(ContainerBuilder $container)
5353
*/
5454
private function processValue($value, $rootLevel = 0, $level = 0)
5555
{
56-
if ($value instanceof Definition) {
56+
if ($value instanceof ArgumentInterface) {
57+
$value->setValues($this->processValue($value->getValues(), $rootLevel, 1 + $level));
58+
} elseif ($value instanceof Definition) {
5759
if ($value->isSynthetic() || $value->isAbstract()) {
5860
return $value;
5961
}
@@ -87,8 +89,6 @@ private function processValue($value, $rootLevel = 0, $level = 0)
8789
if (false !== $i) {
8890
$value = array_values($value);
8991
}
90-
} elseif ($value instanceof ArgumentInterface) {
91-
$value->setValues($this->processValue($value->getValues(), $rootLevel, 1 + $level));
9292
} elseif ($value instanceof Reference) {
9393
$id = (string) $value;
9494

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14-
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1514
use Symfony\Component\DependencyInjection\Alias;
15+
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
1616
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
1717
use Symfony\Component\DependencyInjection\Reference;
1818
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -39,6 +39,10 @@ public function process(ContainerBuilder $container)
3939
if ($definition->isSynthetic() || $definition->isAbstract()) {
4040
continue;
4141
}
42+
if ($definition instanceof ArgumentInterface) {
43+
$definition->setValues($this->processArguments($definition->getValues()));
44+
continue;
45+
}
4246

4347
$definition->setArguments($this->processArguments($definition->getArguments()));
4448
$definition->setMethodCalls($this->processArguments($definition->getMethodCalls()));

0 commit comments

Comments
 (0)
0