diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 0dc715bd6c..18251f064c 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -201,7 +201,7 @@ class PhpDumper extends Dumper $nbOccurrences->offsetSet($definition, 1); } else { $i = $nbOccurrences->offsetGet($definition); - $nbOccurrences->offsetSet($definition, $i+1); + $nbOccurrences->offsetSet($definition, $i + 1); } } @@ -212,7 +212,7 @@ class PhpDumper extends Dumper $processed->offsetSet($sDefinition); $class = $this->dumpValue($sDefinition->getClass()); - if ($nbOccurrences->offsetGet($sDefinition) > 1 || count($sDefinition->getMethodCalls()) > 0 || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) { + if ($nbOccurrences->offsetGet($sDefinition) > 1 || $sDefinition->getMethodCalls() || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) { $name = $this->getNextVariableName(); $variableMap->offsetSet($sDefinition, new Variable($name)); @@ -246,7 +246,7 @@ class PhpDumper extends Dumper $code .= sprintf(" \$%s = new \\%s(%s);\n", $name, substr(str_replace('\\\\', '\\', $class), 1, -1), implode(', ', $arguments)); } - if (!$this->hasReference($id, $sDefinition->getMethodCalls()) && !$this->hasReference($id, $sDefinition->getProperties())) { + if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) { $code .= $this->addServiceMethodCalls(null, $sDefinition, $name); $code .= $this->addServiceProperties(null, $sDefinition, $name); $code .= $this->addServiceConfigurator(null, $sDefinition, $name); @@ -415,16 +415,14 @@ class PhpDumper extends Dumper } $processed->offsetSet($iDefinition); - if (!$this->hasReference($id, $iDefinition->getMethodCalls())) { + if (!$this->hasReference($id, $iDefinition->getMethodCalls(), true) && !$this->hasReference($id, $iDefinition->getProperties(), true)) { continue; } - if ($iDefinition->getMethodCalls()) { - $code .= $this->addServiceMethodCalls(null, $iDefinition, (string) $this->definitionVariables->offsetGet($iDefinition)); - } - if ($iDefinition->getConfigurator()) { - $code .= $this->addServiceConfigurator(null, $iDefinition, (string) $this->definitionVariables->offsetGet($iDefinition)); - } + $name = (string) $this->definitionVariables->offsetGet($iDefinition); + $code .= $this->addServiceMethodCalls(null, $iDefinition, $name); + $code .= $this->addServiceProperties(null, $iDefinition, $name); + $code .= $this->addServiceConfigurator(null, $iDefinition, $name); } if ('' !== $code) { @@ -960,17 +958,26 @@ EOF; * * @return Boolean */ - private function hasReference($id, array $arguments) + private function hasReference($id, array $arguments, $deep = false) { foreach ($arguments as $argument) { if (is_array($argument)) { - if ($this->hasReference($id, $argument)) { + if ($this->hasReference($id, $argument, $deep)) { return true; } } elseif ($argument instanceof Reference) { if ($id === (string) $argument) { return true; } + + if ($deep) { + $service = $this->container->getDefinition((string) $argument); + $arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties()); + + if ($this->hasReference($id, $arguments, $deep)) { + return true; + } + } } } diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Dumper/PhpDumperTest.php b/tests/Symfony/Tests/Component/DependencyInjection/Dumper/PhpDumperTest.php index ed2228a523..ad5270f5de 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Dumper/PhpDumperTest.php +++ b/tests/Symfony/Tests/Component/DependencyInjection/Dumper/PhpDumperTest.php @@ -96,10 +96,17 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase public function testAddService() { + // without compilation $container = include self::$fixturesPath.'/containers/container9.php'; $dumper = new PhpDumper($container); $this->assertEquals(str_replace('%path%', str_replace('\\','\\\\',self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9.php')), $dumper->dump(), '->dump() dumps services'); + // with compilation + $container = include self::$fixturesPath.'/containers/container9.php'; + $container->compile(); + $dumper = new PhpDumper($container); + $this->assertEquals(str_replace('%path%', str_replace('\\','\\\\',self::$fixturesPath.DIRECTORY_SEPARATOR.'includes'.DIRECTORY_SEPARATOR), file_get_contents(self::$fixturesPath.'/php/services9_compiled.php')), $dumper->dump(), '->dump() dumps services'); + $dumper = new PhpDumper($container = new ContainerBuilder()); $container->register('foo', 'FooClass')->addArgument(new \stdClass()); try { diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/container9.php b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/container9.php index 663f2a7fd9..71d29f209b 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/container9.php +++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/containers/container9.php @@ -14,9 +14,8 @@ $container-> addTag('foo', array('bar' => 'bar'))-> setFactoryClass('FooClass')-> setFactoryMethod('getInstance')-> - setArguments(array('foo', new Reference('foo.baz'), array('%foo%' => 'foo is %foo%', 'bar' => '%foo%'), true, new Reference('service_container')))-> + setArguments(array('foo', new Reference('foo.baz'), array('%foo%' => 'foo is %foo%', 'foobar' => '%foo%'), true, new Reference('service_container')))-> setProperties(array('foo' => 'bar', 'moo' => new Reference('foo.baz')))-> - setScope('prototype')-> addMethodCall('setBar', array(new Reference('bar')))-> addMethodCall('initialize')-> setConfigurator('sc_configure') @@ -33,7 +32,10 @@ $container-> setFactoryMethod('getInstance')-> setConfigurator(array('%baz_class%', 'configureStatic1')) ; -$container->register('foo_bar', '%foo_class%'); +$container-> + register('foo_bar', '%foo_class%')-> + setScope('prototype') +; $container->getParameterBag()->clear(); $container->getParameterBag()->add(array( 'baz_class' => 'BazClass', @@ -50,9 +52,24 @@ $container-> addMethodCall('setBar', array(new Reference('foobaz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))) ; $container-> - register('factory_service')-> + register('factory_service', 'Bar')-> setFactoryService('foo.baz')-> setFactoryMethod('getInstance') ; +$container + ->register('foo_with_inline', 'Foo') + ->addMethodCall('setBar', array(new Reference('inlined'))) +; +$container + ->register('inlined', 'Bar') + ->setProperty('pub', 'pub') + ->addMethodCall('setBaz', array(new Reference('baz'))) + ->setPublic(false) +; +$container + ->register('baz', 'Baz') + ->addMethodCall('setFoo', array(new Reference('foo_with_inline'))) +; + return $container; diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/graphviz/services9.dot b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/graphviz/services9.dot index fdff2219ef..73608e27fc 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/graphviz/services9.dot +++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/graphviz/services9.dot @@ -3,12 +3,15 @@ digraph sc { node [fontsize="11" fontname="Arial" shape="record"]; edge [fontsize="9" fontname="Arial" color="grey" arrowhead="open" arrowsize="0.5"]; - node_foo [label="foo (alias_for_foo)\nFooClass\n", shape=record, fillcolor="#eeeeee", style="dotted"]; + node_foo [label="foo (alias_for_foo)\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_bar [label="bar\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_foo_baz [label="foo.baz\nBazClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_foo_bar [label="foo_bar\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_foo_bar [label="foo_bar\nFooClass\n", shape=record, fillcolor="#eeeeee", style="dotted"]; node_method_call1 [label="method_call1\nFooClass\n", shape=record, fillcolor="#eeeeee", style="filled"]; - node_factory_service [label="factory_service\n\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_factory_service [label="factory_service\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_foo_with_inline [label="foo_with_inline\nFoo\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_inlined [label="inlined\nBar\n", shape=record, fillcolor="#eeeeee", style="filled"]; + node_baz [label="baz\nBaz\n", shape=record, fillcolor="#eeeeee", style="filled"]; node_service_container [label="service_container\nSymfony\\Component\\DependencyInjection\\ContainerBuilder\n", shape=record, fillcolor="#9999ff", style="filled"]; node_foo2 [label="foo2\n\n", shape=record, fillcolor="#ff9999", style="filled"]; node_foo3 [label="foo3\n\n", shape=record, fillcolor="#ff9999", style="filled"]; @@ -22,4 +25,7 @@ digraph sc { node_method_call1 -> node_foo2 [label="setBar()" style="dashed"]; node_method_call1 -> node_foo3 [label="setBar()" style="dashed"]; node_method_call1 -> node_foobaz [label="setBar()" style="dashed"]; + node_foo_with_inline -> node_inlined [label="setBar()" style="dashed"]; + node_inlined -> node_baz [label="setBaz()" style="dashed"]; + node_baz -> node_foo_with_inline [label="setFoo()" style="dashed"]; } diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/includes/classes.php b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/includes/classes.php index 514df23e51..fb6d4cf19d 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/includes/classes.php +++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/includes/classes.php @@ -7,10 +7,23 @@ function sc_configure($instance) class BarClass { + protected $baz; + + public function setBaz(BazClass $baz) + { + $this->baz = $baz; + } } class BazClass { + protected $foo; + + public function setFoo(Foo $foo) + { + $this->foo = $foo; + } + public function configure($instance) { $instance->configure(); diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9.php b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9.php index dc62d54ffd..0d4008583e 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9.php +++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9.php @@ -40,13 +40,30 @@ class ProjectServiceContainer extends Container return $instance; } + /** + * Gets the 'baz' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return Baz A Baz instance. + */ + protected function getBazService() + { + $this->services['baz'] = $instance = new \Baz(); + + $instance->setFoo($this->get('foo_with_inline')); + + return $instance; + } + /** * Gets the 'factory_service' service. * * This service is shared. * This method always returns the same instance of the service. * - * @return Object An instance returned by foo.baz::getInstance(). + * @return Bar A Bar instance. */ protected function getFactoryServiceService() { @@ -56,13 +73,16 @@ class ProjectServiceContainer extends Container /** * Gets the 'foo' service. * + * This service is shared. + * This method always returns the same instance of the service. + * * @return FooClass A FooClass instance. */ protected function getFooService() { $a = $this->get('foo.baz'); - $instance = call_user_func(array('FooClass', 'getInstance'), 'foo', $a, array($this->getParameter('foo') => 'foo is '.$this->getParameter('foo'), 'bar' => $this->getParameter('foo')), true, $this); + $this->services['foo'] = $instance = call_user_func(array('FooClass', 'getInstance'), 'foo', $a, array($this->getParameter('foo') => 'foo is '.$this->getParameter('foo'), 'foobar' => $this->getParameter('foo')), true, $this); $instance->setBar($this->get('bar')); $instance->initialize(); @@ -93,15 +113,29 @@ class ProjectServiceContainer extends Container /** * Gets the 'foo_bar' service. * - * This service is shared. - * This method always returns the same instance of the service. - * * @return Object A %foo_class% instance. */ protected function getFooBarService() { $class = $this->getParameter('foo_class'); - return $this->services['foo_bar'] = new $class(); + return new $class(); + } + + /** + * Gets the 'foo_with_inline' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return Foo A Foo instance. + */ + protected function getFooWithInlineService() + { + $this->services['foo_with_inline'] = $instance = new \Foo(); + + $instance->setBar($this->get('inlined')); + + return $instance; } /** @@ -140,6 +174,28 @@ class ProjectServiceContainer extends Container return $this->get('foo'); } + /** + * Gets the 'inlined' 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 Bar A Bar instance. + */ + protected function getInlinedService() + { + $this->services['inlined'] = $instance = new \Bar(); + + $instance->setBaz($this->get('baz')); + $instance->pub = 'pub'; + + return $instance; + } + /** * Gets the default parameters. * diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9_compiled.php b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9_compiled.php new file mode 100644 index 0000000000..f41d4b23d8 --- /dev/null +++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/php/services9_compiled.php @@ -0,0 +1,238 @@ +parameters = $this->getDefaultParameters(); + + $this->services = + $this->scopedServices = + $this->scopeStacks = array(); + + $this->set('service_container', $this); + + $this->scopes = array(); + $this->scopeChildren = array(); + } + + /** + * Gets the 'bar' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return FooClass A FooClass instance. + */ + protected function getBarService() + { + $this->services['bar'] = $instance = new \FooClass('foo', $this->get('foo.baz'), $this->getParameter('foo_bar')); + + $this->get('foo.baz')->configure($instance); + + return $instance; + } + + /** + * Gets the 'baz' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return Baz A Baz instance. + */ + protected function getBazService() + { + $this->services['baz'] = $instance = new \Baz(); + + $instance->setFoo($this->get('foo_with_inline')); + + return $instance; + } + + /** + * Gets the 'factory_service' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return Bar A Bar instance. + */ + protected function getFactoryServiceService() + { + return $this->services['factory_service'] = $this->get('foo.baz')->getInstance(); + } + + /** + * Gets the 'foo' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return FooClass A FooClass instance. + */ + protected function getFooService() + { + $a = $this->get('foo.baz'); + + $this->services['foo'] = $instance = call_user_func(array('FooClass', 'getInstance'), 'foo', $a, array('bar' => 'foo is bar', 'foobar' => 'bar'), true, $this); + + $instance->setBar($this->get('bar')); + $instance->initialize(); + $instance->foo = 'bar'; + $instance->moo = $a; + sc_configure($instance); + + return $instance; + } + + /** + * Gets the 'foo.baz' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return BazClass A BazClass instance. + */ + protected function getFoo_BazService() + { + $this->services['foo.baz'] = $instance = call_user_func(array('BazClass', 'getInstance')); + + call_user_func(array('BazClass', 'configureStatic1'), $instance); + + return $instance; + } + + /** + * Gets the 'foo_bar' service. + * + * @return FooClass A FooClass instance. + */ + protected function getFooBarService() + { + return new \FooClass(); + } + + /** + * Gets the 'foo_with_inline' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return Foo A Foo instance. + */ + protected function getFooWithInlineService() + { + $a = new \Bar(); + + $this->services['foo_with_inline'] = $instance = new \Foo(); + + $a->setBaz($this->get('baz')); + $a->pub = 'pub'; + + $instance->setBar($a); + + return $instance; + } + + /** + * Gets the 'method_call1' service. + * + * This service is shared. + * This method always returns the same instance of the service. + * + * @return FooClass A FooClass instance. + */ + protected function getMethodCall1Service() + { + require_once '%path%foo.php'; + + $this->services['method_call1'] = $instance = new \FooClass(); + + $instance->setBar($this->get('foo')); + $instance->setBar(NULL); + + return $instance; + } + + /** + * Gets the alias_for_foo service alias. + * + * @return FooClass An instance of the foo service + */ + protected function getAliasForFooService() + { + return $this->get('foo'); + } + + /** + * {@inheritdoc} + */ + public function getParameter($name) + { + $name = strtolower($name); + + if (!array_key_exists($name, $this->parameters)) { + throw new \InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name)); + } + + return $this->parameters[$name]; + } + + /** + * {@inheritdoc} + */ + public function hasParameter($name) + { + return array_key_exists(strtolower($name), $this->parameters); + } + + /** + * {@inheritdoc} + */ + public function setParameter($name, $value) + { + throw new \LogicException('Impossible to call set() on a frozen ParameterBag.'); + } + + /** + * {@inheritDoc} + */ + public function getParameterBag() + { + if (null === $this->parameterBag) { + $this->parameterBag = new FrozenParameterBag($this->parameters); + } + + return $this->parameterBag; + } + /** + * Gets the default parameters. + * + * @return array An array of the default parameters + */ + protected function getDefaultParameters() + { + return array( + 'baz_class' => 'BazClass', + 'foo_class' => 'FooClass', + 'foo' => 'bar', + ); + } +} diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/xml/services9.xml b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/xml/services9.xml index a73fb3e7d1..58eb6d79a3 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/xml/services9.xml +++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/xml/services9.xml @@ -6,14 +6,14 @@ bar - + foo foo is %foo% - %foo% + %foo% true @@ -34,7 +34,7 @@ - + %path%foo.php @@ -50,7 +50,23 @@ - + + + + + + + + pub + + + + + + + + + diff --git a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/yaml/services9.yml b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/yaml/services9.yml index 6f0eca9038..d0085536ac 100644 --- a/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/yaml/services9.yml +++ b/tests/Symfony/Tests/Component/DependencyInjection/Fixtures/yaml/services9.yml @@ -10,13 +10,12 @@ services: - { name: foo, foo: foo } - { name: foo, bar: bar } factory_method: getInstance - arguments: [foo, '@foo.baz', { '%foo%': 'foo is %foo%', bar: '%foo%' }, true, '@service_container'] + arguments: [foo, '@foo.baz', { '%foo%': 'foo is %foo%', foobar: '%foo%' }, true, '@service_container'] properties: { foo: bar, moo: '@foo.baz' } calls: - [setBar, ['@bar']] - [initialize, { }] - scope: prototype configurator: sc_configure bar: class: FooClass @@ -28,6 +27,7 @@ services: configurator: ['%baz_class%', configureStatic1] foo_bar: class: %foo_class% + scope: prototype method_call1: class: FooClass file: %path%foo.php @@ -38,6 +38,23 @@ services: - [setBar, ['@?foobaz']] factory_service: + class: Bar factory_method: getInstance factory_service: foo.baz + foo_with_inline: + class: Foo + calls: + - [setBar, ['@inlined']] + + inlined: + class: Bar + properties: { pub: pub } + calls: + - [setBaz, ['@baz']] + + baz: + class: Baz + calls: + - [setFoo, ['@foo_with_inline']] + alias_for_foo: @foo