Skip to content

Commit

Permalink
make it possible to dump inlined services to XML
Browse files Browse the repository at this point in the history
  • Loading branch information
xabbuh committed Mar 23, 2015
1 parent 1a4d7d7 commit 504e338
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 92 deletions.
Expand Up @@ -62,6 +62,12 @@ public function process(ContainerBuilder $container)
$definition->setProperties(
$this->inlineArguments($container, $definition->getProperties())
);

$configurator = $this->inlineArguments($container, array($definition->getConfigurator()));
$definition->setConfigurator($configurator[0]);

$factory = $this->inlineArguments($container, array($definition->getFactory()));
$definition->setFactory($factory[0]);
}
}

Expand Down
12 changes: 10 additions & 2 deletions src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php
Expand Up @@ -178,7 +178,11 @@ private function addService($definition, $id, \DOMElement $parent)

if ($callable = $definition->getFactory()) {
$factory = $this->document->createElement('factory');
if (is_array($callable)) {

if (is_array($callable) && $callable[0] instanceof Definition) {
$this->addService($callable[0], null, $factory);
$factory->setAttribute('method', $callable[1]);
} elseif (is_array($callable)) {
$factory->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]);
$factory->setAttribute('method', $callable[1]);
} else {
Expand All @@ -189,7 +193,11 @@ private function addService($definition, $id, \DOMElement $parent)

if ($callable = $definition->getConfigurator()) {
$configurator = $this->document->createElement('configurator');
if (is_array($callable)) {

if (is_array($callable) && $callable[0] instanceof Definition) {
$this->addService($callable[0], null, $configurator);
$configurator->setAttribute('method', $callable[1]);
} elseif (is_array($callable)) {
$configurator->setAttribute($callable[0] instanceof Reference ? 'service' : 'class', $callable[0]);
$configurator->setAttribute('method', $callable[1]);
} else {
Expand Down
32 changes: 22 additions & 10 deletions src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
Expand Up @@ -116,25 +116,27 @@ private function parseDefinitions(\DOMDocument $xml, $file)
}

foreach ($services as $service) {
$this->parseDefinition((string) $service->getAttribute('id'), $service, $file);
if (null !== $definition = $this->parseDefinition($service, $file)) {
$this->container->setDefinition((string) $service->getAttribute('id'), $definition);
}
}
}

/**
* Parses an individual Definition.
*
* @param string $id
* @param \DOMElement $service
* @param string $file
*
* @return Definition|null
*/
private function parseDefinition($id, \DOMElement $service, $file)
private function parseDefinition(\DOMElement $service)
{
if ($alias = $service->getAttribute('alias')) {
$public = true;
if ($publicAttr = $service->getAttribute('public')) {
$public = XmlUtils::phpize($publicAttr);
}
$this->container->setAlias($id, new Alias($alias, $public));
$this->container->setAlias((string) $service->getAttribute('id'), new Alias($alias, $public));

return;
}
Expand All @@ -153,7 +155,7 @@ private function parseDefinition($id, \DOMElement $service, $file)
}

if ($value = $service->getAttribute('synchronized')) {
$definition->setSynchronized(XmlUtils::phpize($value), 'request' !== $id);
$definition->setSynchronized(XmlUtils::phpize($value), 'request' !== (string) $service->getAttribute('id'));
}

if ($files = $this->getChildren($service, 'file')) {
Expand All @@ -168,7 +170,11 @@ private function parseDefinition($id, \DOMElement $service, $file)
if ($function = $factory->getAttribute('function')) {
$definition->setFactory($function);
} else {
if ($childService = $factory->getAttribute('service')) {
$factoryService = $this->getChildren($factory, 'service');

if (isset($factoryService[0])) {
$class = $this->parseDefinition($factoryService[0]);
} elseif ($childService = $factory->getAttribute('service')) {
$class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
} else {
$class = $factory->getAttribute('class');
Expand All @@ -183,7 +189,11 @@ private function parseDefinition($id, \DOMElement $service, $file)
if ($function = $configurator->getAttribute('function')) {
$definition->setConfigurator($function);
} else {
if ($childService = $configurator->getAttribute('service')) {
$configuratorService = $this->getChildren($configurator, 'service');

if (isset($configuratorService[0])) {
$class = $this->parseDefinition($configuratorService[0]);
} elseif ($childService = $configurator->getAttribute('service')) {
$class = new Reference($childService, ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false);
} else {
$class = $configurator->getAttribute('class');
Expand Down Expand Up @@ -219,7 +229,7 @@ private function parseDefinition($id, \DOMElement $service, $file)
$definition->setDecoratedService($value, $renameId);
}

$this->container->setDefinition($id, $definition);
return $definition;
}

/**
Expand Down Expand Up @@ -295,7 +305,9 @@ private function processAnonymousServices(\DOMDocument $xml, $file)
// we could not use the constant false here, because of XML parsing
$domElement->setAttribute('public', 'false');

$this->parseDefinition($id, $domElement, $file);
if (null !== $definition = $this->parseDefinition($domElement, $file)) {
$this->container->setDefinition($id, $definition);
}

if (true === $wild) {
$tmpDomElement = new \DOMElement('_services', null, self::NS);
Expand Down
Expand Up @@ -65,6 +65,9 @@
</xsd:complexType>

<xsd:complexType name="callable">
<xsd:choice minOccurs="0" maxOccurs="1">
<xsd:element name="service" type="service" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<xsd:attribute name="id" type="xsd:string" />
<xsd:attribute name="service" type="xsd:string" />
<xsd:attribute name="class" type="xsd:string" />
Expand Down
Expand Up @@ -237,40 +237,6 @@ public function testProcessDoesNotInlineWhenServiceReferencesItself()
$this->assertSame($ref, $calls[0][1][0]);
}

public function testProcessDoesNotInlineFactories()
{
$container = new ContainerBuilder();
$container
->register('foo.factory')
->setPublic(false)
;
$container
->register('foo')
->setFactory(array(new Reference('foo.factory'), 'getFoo'))
;
$this->process($container);

$factory = $container->getDefinition('foo')->getFactory();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $factory[0]);
}

public function testProcessDoesNotInlineConfigurators()
{
$container = new ContainerBuilder();
$container
->register('foo.configurator')
->setPublic(false)
;
$container
->register('foo')
->setConfigurator(array(new Reference('foo.configurator'), 'getFoo'))
;
$this->process($container);

$configurator = $container->getDefinition('foo')->getConfigurator();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Reference', $configurator[0]);
}

protected function process(ContainerBuilder $container)
{
$repeatedPass = new RepeatedPass(array(new AnalyzeServiceReferencesPass(), new InlineServiceDefinitionsPass()));
Expand Down
Expand Up @@ -175,4 +175,12 @@ public function provideCompiledContainerData()
array('container14'),
);
}

public function testDumpInlinedServices()
{
$container = include self::$fixturesPath.'/containers/container21.php';
$dumper = new XmlDumper($container);

$this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services21.xml'), $dumper->dump());
}
}
@@ -0,0 +1,20 @@
<?php

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;

$container = new ContainerBuilder();

$bar = new Definition('Bar');
$bar->setConfigurator(array(new Definition('Baz'), 'configureBar'));

$fooFactory = new Definition('FooFactory');
$fooFactory->setFactory(array(new Definition('Foobar'), 'createFooFactory'));

$container
->register('foo', 'Foo')
->setFactory(array($fooFactory, 'createFoo'))
->setConfigurator(array($bar, 'configureFoo'))
;

return $container;
Expand Up @@ -37,7 +37,6 @@ public function __construct()
$this->methodMap = array(
'bar' => 'getBarService',
'baz' => 'getBazService',
'configurator_service' => 'getConfiguratorServiceService',
'configured_service' => 'getConfiguredServiceService',
'decorator_service' => 'getDecoratorServiceService',
'decorator_service_with_name' => 'getDecoratorServiceWithNameService',
Expand All @@ -47,7 +46,6 @@ public function __construct()
'foo_bar' => 'getFooBarService',
'foo_with_inline' => 'getFooWithInlineService',
'method_call1' => 'getMethodCall1Service',
'new_factory' => 'getNewFactoryService',
'new_factory_service' => 'getNewFactoryServiceService',
'request' => 'getRequestService',
'service_from_static_method' => 'getServiceFromStaticMethodService',
Expand Down Expand Up @@ -113,9 +111,12 @@ protected function getBazService()
*/
protected function getConfiguredServiceService()
{
$a = new \ConfClass();
$a->setFoo($this->get('baz'));

$this->services['configured_service'] = $instance = new \stdClass();

$this->get('configurator_service')->configureStdClass($instance);
$a->configureStdClass($instance);

return $instance;
}
Expand Down Expand Up @@ -263,7 +264,10 @@ protected function getMethodCall1Service()
*/
protected function getNewFactoryServiceService()
{
$this->services['new_factory_service'] = $instance = $this->get('new_factory')->getInstance();
$a = new \FactoryClass();
$a->foo = 'bar';

$this->services['new_factory_service'] = $instance = $a->getInstance();

$instance->foo = 'bar';

Expand Down Expand Up @@ -296,48 +300,6 @@ protected function getServiceFromStaticMethodService()
return $this->services['service_from_static_method'] = \Bar\FooClass::getInstance();
}

/**
* Gets the 'configurator_service' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* This service is private.
* If you want to be able to request this service from the container directly,
* make it public, otherwise you might end up with broken code.
*
* @return \ConfClass A ConfClass instance.
*/
protected function getConfiguratorServiceService()
{
$this->services['configurator_service'] = $instance = new \ConfClass();

$instance->setFoo($this->get('baz'));

return $instance;
}

/**
* Gets the 'new_factory' service.
*
* This service is shared.
* This method always returns the same instance of the service.
*
* This service is private.
* If you want to be able to request this service from the container directly,
* make it public, otherwise you might end up with broken code.
*
* @return \FactoryClass A FactoryClass instance.
*/
protected function getNewFactoryService()
{
$this->services['new_factory'] = $instance = new \FactoryClass();

$instance->foo = 'bar';

return $instance;
}

/**
* {@inheritdoc}
*/
Expand Down
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<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">
<services>
<service id="foo" class="Foo">
<factory method="createFoo">
<service class="FooFactory">
<factory method="createFooFactory">
<service class="Foobar"/>
</factory>
</service>
</factory>
<configurator method="configureFoo">
<service class="Bar">
<configurator method="configureBar">
<service class="Baz"/>
</configurator>
</service>
</configurator>
</service>
</services>
</container>
Expand Up @@ -467,4 +467,33 @@ public function testLoadIndexedArguments()

$this->assertEquals(array('index_0' => 'app'), $container->findDefinition('logger')->getArguments());
}

public function testLoadInlinedServices()
{
$container = new ContainerBuilder();
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
$loader->load('services21.xml');

$foo = $container->getDefinition('foo');

$fooFactory = $foo->getFactory();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $fooFactory[0]);
$this->assertSame('FooFactory', $fooFactory[0]->getClass());
$this->assertSame('createFoo', $fooFactory[1]);

$fooFactoryFactory = $fooFactory[0]->getFactory();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $fooFactoryFactory[0]);
$this->assertSame('Foobar', $fooFactoryFactory[0]->getClass());
$this->assertSame('createFooFactory', $fooFactoryFactory[1]);

$fooConfigurator = $foo->getConfigurator();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $fooConfigurator[0]);
$this->assertSame('Bar', $fooConfigurator[0]->getClass());
$this->assertSame('configureFoo', $fooConfigurator[1]);

$barConfigurator = $fooConfigurator[0]->getConfigurator();
$this->assertInstanceOf('Symfony\Component\DependencyInjection\Definition', $barConfigurator[0]);
$this->assertSame('Baz', $barConfigurator[0]->getClass());
$this->assertSame('configureBar', $barConfigurator[1]);
}
}

0 comments on commit 504e338

Please sign in to comment.