[DI] Fix handling of inlined definitions by ContainerBuilder
This commit is contained in:
parent
9d68751431
commit
c9c18ac7f3
|
@ -441,7 +441,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
$this->loading[$id] = true;
|
$this->loading[$id] = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$service = $this->createService($definition, $id);
|
$service = $this->createService($definition, new \SplObjectStorage(), $id);
|
||||||
} catch (\Exception $e) {
|
} catch (\Exception $e) {
|
||||||
unset($this->loading[$id]);
|
unset($this->loading[$id]);
|
||||||
|
|
||||||
|
@ -827,8 +827,12 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
*
|
*
|
||||||
* @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code
|
* @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code
|
||||||
*/
|
*/
|
||||||
public function createService(Definition $definition, $id, $tryProxy = true)
|
public function createService(Definition $definition, \SplObjectStorage $inlinedDefinitions, $id = null, $tryProxy = true)
|
||||||
{
|
{
|
||||||
|
if (null === $id && isset($inlinedDefinitions[$definition])) {
|
||||||
|
return $inlinedDefinitions[$definition];
|
||||||
|
}
|
||||||
|
|
||||||
if ($definition instanceof DefinitionDecorator) {
|
if ($definition instanceof DefinitionDecorator) {
|
||||||
throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
|
throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id));
|
||||||
}
|
}
|
||||||
|
@ -845,11 +849,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
->instantiateProxy(
|
->instantiateProxy(
|
||||||
$container,
|
$container,
|
||||||
$definition,
|
$definition,
|
||||||
$id, function () use ($definition, $id, $container) {
|
$id, function () use ($definition, $inlinedDefinitions, $id, $container) {
|
||||||
return $container->createService($definition, $id, false);
|
return $container->createService($definition, $inlinedDefinitions, $id, false);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
$this->shareService($definition, $proxy, $id);
|
$this->shareService($definition, $proxy, $id, $inlinedDefinitions);
|
||||||
|
|
||||||
return $proxy;
|
return $proxy;
|
||||||
}
|
}
|
||||||
|
@ -860,11 +864,11 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
require_once $parameterBag->resolveValue($definition->getFile());
|
require_once $parameterBag->resolveValue($definition->getFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
$arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())));
|
$arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlinedDefinitions);
|
||||||
|
|
||||||
if (null !== $factory = $definition->getFactory()) {
|
if (null !== $factory = $definition->getFactory()) {
|
||||||
if (is_array($factory)) {
|
if (is_array($factory)) {
|
||||||
$factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]);
|
$factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlinedDefinitions), $factory[1]);
|
||||||
} elseif (!is_string($factory)) {
|
} elseif (!is_string($factory)) {
|
||||||
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
|
throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id));
|
||||||
}
|
}
|
||||||
|
@ -888,16 +892,16 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
|
|
||||||
if ($tryProxy || !$definition->isLazy()) {
|
if ($tryProxy || !$definition->isLazy()) {
|
||||||
// share only if proxying failed, or if not a proxy
|
// share only if proxying failed, or if not a proxy
|
||||||
$this->shareService($definition, $service, $id);
|
$this->shareService($definition, $service, $id, $inlinedDefinitions);
|
||||||
}
|
}
|
||||||
|
|
||||||
$properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())));
|
$properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlinedDefinitions);
|
||||||
foreach ($properties as $name => $value) {
|
foreach ($properties as $name => $value) {
|
||||||
$service->$name = $value;
|
$service->$name = $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($definition->getMethodCalls() as $call) {
|
foreach ($definition->getMethodCalls() as $call) {
|
||||||
$this->callMethod($service, $call);
|
$this->callMethod($service, $call, $inlinedDefinitions);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($callable = $definition->getConfigurator()) {
|
if ($callable = $definition->getConfigurator()) {
|
||||||
|
@ -907,7 +911,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
if ($callable[0] instanceof Reference) {
|
if ($callable[0] instanceof Reference) {
|
||||||
$callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
|
$callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior());
|
||||||
} elseif ($callable[0] instanceof Definition) {
|
} elseif ($callable[0] instanceof Definition) {
|
||||||
$callable[0] = $this->createService($callable[0], null);
|
$callable[0] = $this->createService($callable[0], $inlinedDefinitions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,15 +934,20 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
* the real service instances and all expressions evaluated
|
* the real service instances and all expressions evaluated
|
||||||
*/
|
*/
|
||||||
public function resolveServices($value)
|
public function resolveServices($value)
|
||||||
|
{
|
||||||
|
return $this->doResolveServices($value, new \SplObjectStorage());
|
||||||
|
}
|
||||||
|
|
||||||
|
private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions)
|
||||||
{
|
{
|
||||||
if (is_array($value)) {
|
if (is_array($value)) {
|
||||||
foreach ($value as $k => $v) {
|
foreach ($value as $k => $v) {
|
||||||
$value[$k] = $this->resolveServices($v);
|
$value[$k] = $this->doResolveServices($v, $inlinedDefinitions);
|
||||||
}
|
}
|
||||||
} elseif ($value instanceof Reference) {
|
} elseif ($value instanceof Reference) {
|
||||||
$value = $this->get((string) $value, $value->getInvalidBehavior());
|
$value = $this->get((string) $value, $value->getInvalidBehavior());
|
||||||
} elseif ($value instanceof Definition) {
|
} elseif ($value instanceof Definition) {
|
||||||
$value = $this->createService($value, null);
|
$value = $this->createService($value, $inlinedDefinitions);
|
||||||
} elseif ($value instanceof Expression) {
|
} elseif ($value instanceof Expression) {
|
||||||
$value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this));
|
$value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this));
|
||||||
}
|
}
|
||||||
|
@ -1065,14 +1074,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
foreach ($definition->getMethodCalls() as $call) {
|
foreach ($definition->getMethodCalls() as $call) {
|
||||||
foreach ($call[1] as $argument) {
|
foreach ($call[1] as $argument) {
|
||||||
if ($argument instanceof Reference && $id == (string) $argument) {
|
if ($argument instanceof Reference && $id == (string) $argument) {
|
||||||
$this->callMethod($this->get($definitionId), $call);
|
$this->callMethod($this->get($definitionId), $call, new \SplObjectStorage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function callMethod($service, $call)
|
private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitions)
|
||||||
{
|
{
|
||||||
$services = self::getServiceConditionals($call[1]);
|
$services = self::getServiceConditionals($call[1]);
|
||||||
|
|
||||||
|
@ -1082,7 +1091,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1]))));
|
call_user_func_array(array($service, $call[0]), $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlinedDefinitions));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1094,9 +1103,14 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
|
||||||
*
|
*
|
||||||
* @throws InactiveScopeException
|
* @throws InactiveScopeException
|
||||||
*/
|
*/
|
||||||
private function shareService(Definition $definition, $service, $id)
|
private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions)
|
||||||
{
|
{
|
||||||
if (null !== $id && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) {
|
if (self::SCOPE_PROTOTYPE === $scope = $definition->getScope()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (null === $id) {
|
||||||
|
$inlinedDefinitions[$definition] = $service;
|
||||||
|
} else {
|
||||||
if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
|
if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) {
|
||||||
throw new InactiveScopeException($id, $scope);
|
throw new InactiveScopeException($id, $scope);
|
||||||
}
|
}
|
||||||
|
|
|
@ -827,6 +827,28 @@ class ContainerBuilderTest extends TestCase
|
||||||
$this->assertTrue($classInList);
|
$this->assertTrue($classInList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testInlinedDefinitions()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
|
||||||
|
$definition = new Definition('BarClass');
|
||||||
|
|
||||||
|
$container->register('bar_user', 'BarUserClass')
|
||||||
|
->addArgument($definition)
|
||||||
|
->setProperty('foo', $definition);
|
||||||
|
|
||||||
|
$container->register('bar', 'BarClass')
|
||||||
|
->setProperty('foo', $definition)
|
||||||
|
->addMethodCall('setBaz', array($definition));
|
||||||
|
|
||||||
|
$barUser = $container->get('bar_user');
|
||||||
|
$bar = $container->get('bar');
|
||||||
|
|
||||||
|
$this->assertSame($barUser->foo, $barUser->bar);
|
||||||
|
$this->assertSame($bar->foo, $bar->getBaz());
|
||||||
|
$this->assertNotSame($bar->foo, $barUser->foo);
|
||||||
|
}
|
||||||
|
|
||||||
public function testInitializePropertiesBeforeMethodCalls()
|
public function testInitializePropertiesBeforeMethodCalls()
|
||||||
{
|
{
|
||||||
$container = new ContainerBuilder();
|
$container = new ContainerBuilder();
|
||||||
|
|
|
@ -8,7 +8,7 @@ function sc_configure($instance)
|
||||||
$instance->configure();
|
$instance->configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
class BarClass
|
class BarClass extends BazClass
|
||||||
{
|
{
|
||||||
protected $baz;
|
protected $baz;
|
||||||
public $foo = 'foo';
|
public $foo = 'foo';
|
||||||
|
|
Reference in New Issue