Skip to content

Loading…

[DependencyInjection] call synchronize{$id} from get{$id}Service method #8545

Closed
wants to merge 5 commits into from

3 participants

@jaypea

this calls the synchronize method for services that are marked as synchronized but are not synthetic.

when the scope of the requested service is not active, the container won't create the instance nor call the synchronize method.
when the scope gets entered and the service is fetched from container afterwards, the synchronize{$id}Service method is called to update all dependent services.

Jan Prieser call synchronize{$id} from get{$id}Service method
this calls the synchronize method for services that are marked as synchronized but are not synthetic.
when the scope of the requested service is not active, the container won't create the instance nor call the synchronize method.
when the scope gets entered and the service is injected afterwards, the synchronize{$id}Service method is called to update all dependent services.
e8930fa
@stof
Symfony member

Please test this

Jan Prieser added some commits
@jaypea

the tests fail with a segmentation fault for php 5.3.3. its running in the other versions jobs.
but this has nothing to do with my code, the master branch is failing since yesterday: https://travis-ci.org/symfony/symfony/builds

@stof stof commented on an outdated diff
...ny/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -420,6 +420,18 @@ private function addServiceProperties($id, $definition, $variableName = 'instanc
return $code;
}
+ private function addServiceSynchronizeCall($id, $definition)
@stof Symfony member
stof added a note

could you typehint the Definition ?

@jaypea
jaypea added a note

there are lots of similar methods in this class without typehints.
if was thinking about it, but decided to stick with the convention in the class.

@stof Symfony member
stof added a note

I think typehinting the object arguments is better (and SensioLabs Insight agrees with me as it checks for it). So I think the new code should use the typehint (changing the existing code is probably outside the scope of this PR).

@fabpot Symfony member
fabpot added a note

Type hinting is indeed a good idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff
...nt/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -181,4 +182,20 @@ public function testOverrideServiceWhenUsingADumpedContainerAndServiceIsUsedFrom
$this->assertSame($bar, $container->get('foo')->bar, '->set() overrides an already defined service');
}
+
+ public function testSynchronizedServiceUpdatesDependencies() {
@stof Symfony member
stof added a note

the curly brace should be on its own line

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff
...nt/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\DependencyInjection\Tests\Dumper;
+use Symfony\Component\DependencyInjection\Container;
@stof Symfony member
stof added a note

is it used ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@stof stof commented on an outdated diff
...cyInjection/Tests/Fixtures/containers/container15.php
((3 lines not shown))
+require_once __DIR__.'/../includes/classes.php';
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Parameter;
+
+$container = new ContainerBuilder();
+$container->addScope(new \Symfony\Component\DependencyInjection\Scope('request'));
+$container
+ ->register('synchronizedService', 'BarClass')
+ ->setSynchronized(true)
+ ->setScope('request')
+;
+$container
+ ->register('dependsOnSynchronized', 'FooClass')
@stof Symfony member
stof added a note

Please use underscored names instead of camel cased names to follow the DIC conventions (camelCase does nto really make sense for case insensitive ids)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@fabpot fabpot commented on the diff
...cyInjection/Tests/Fixtures/containers/container15.php
((1 lines not shown))
+<?php
+
+require_once __DIR__.'/../includes/classes.php';
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Parameter;
+
+$container = new ContainerBuilder();
+$container->addScope(new \Symfony\Component\DependencyInjection\Scope('request'));
+$container
+ ->register('synchronized_service', 'BarClass')
+ ->setSynchronized(true)
+ ->setScope('request')
+;
@fabpot Symfony member
fabpot added a note

If a service is synchronized, it should not be in the request scope. A service should be either in the request scope or synchrnonized, not both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@fabpot
Symfony member

Closing this one as there is no feedback and because there is a better way in Symfony 2.4 with the request stack service.

@fabpot fabpot closed this
@jaypea jaypea deleted the jaypea:synchronize branch
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jul 23, 2013
  1. call synchronize{$id} from get{$id}Service method

    Jan Prieser committed
    this calls the synchronize method for services that are marked as synchronized but are not synthetic.
    when the scope of the requested service is not active, the container won't create the instance nor call the synchronize method.
    when the scope gets entered and the service is injected afterwards, the synchronize{$id}Service method is called to update all dependent services.
  2. fix output

    Jan Prieser committed
  3. adds unit test for synchronizing services

    Jan Prieser committed
  4. fix code review findings

    Jan Prieser committed
  5. fix another instance of camelcase service name usage

    Jan Prieser committed
View
15 src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -378,7 +378,7 @@ private function isSimpleInstance($id, $definition)
continue;
}
- if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator()) {
+ if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator() || $sDefinition->isSynchronized()) {
return false;
}
}
@@ -420,6 +420,18 @@ private function addServiceProperties($id, $definition, $variableName = 'instanc
return $code;
}
+ private function addServiceSynchronizeCall($id, Definition $definition)
+ {
+ if (!$definition->isSynchronized()) {
+ return '';
+ }
+
+ $name = 'synchronize'.$this->camelize($id).'Service';
+ $code = sprintf(" \$this->%s();\n", $name);
+
+ return $code;
+ }
+
/**
* Generates the inline definition setup.
*
@@ -585,6 +597,7 @@ private function addService($id, $definition)
$this->addServiceMethodCalls($id, $definition).
$this->addServiceProperties($id, $definition).
$this->addServiceConfigurator($id, $definition).
+ $this->addServiceSynchronizeCall($id, $definition).
$this->addServiceReturn($id, $definition)
;
}
View
17 src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -181,4 +181,21 @@ public function testOverrideServiceWhenUsingADumpedContainerAndServiceIsUsedFrom
$this->assertSame($bar, $container->get('foo')->bar, '->set() overrides an already defined service');
}
+
+ public function testSynchronizedServiceUpdatesDependencies()
+ {
+ require_once self::$fixturesPath.'/includes/foo.php';
+ require_once self::$fixturesPath.'/includes/classes.php';
+ require_once self::$fixturesPath.'/php/services15.php';
+
+ $container = new \AnotherProjectServiceContainer();
+ $dependentService = $container->get('depends_on_synchronized');
+ $this->assertNull($dependentService->bar);
+
+ $container->enterScope('request');
+ $synchronizedService = $container->get('synchronized_service');
+
+ $this->assertEquals($dependentService->bar, $synchronizedService);
+
+ }
}
View
22 src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container15.php
@@ -0,0 +1,22 @@
+<?php
+
+require_once __DIR__.'/../includes/classes.php';
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Parameter;
+
+$container = new ContainerBuilder();
+$container->addScope(new \Symfony\Component\DependencyInjection\Scope('request'));
+$container
+ ->register('synchronized_service', 'BarClass')
+ ->setSynchronized(true)
+ ->setScope('request')
+;
@fabpot Symfony member
fabpot added a note

If a service is synchronized, it should not be in the request scope. A service should be either in the request scope or synchrnonized, not both.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+$container
+ ->register('depends_on_synchronized', 'FooClass')
+ ->addMethodCall('setBar', array(new Reference('synchronized_service', ContainerInterface::NULL_ON_INVALID_REFERENCE, false)))
+;
+
+return $container;
View
91 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services15.php
@@ -0,0 +1,91 @@
+<?php
+
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
+use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
+use Symfony\Component\DependencyInjection\Exception\LogicException;
+use Symfony\Component\DependencyInjection\Exception\RuntimeException;
+use Symfony\Component\DependencyInjection\Reference;
+use Symfony\Component\DependencyInjection\Parameter;
+use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
+
+/**
+ * AnotherProjectServiceContainer
+ *
+ * This class has been auto-generated
+ * by the Symfony Dependency Injection Component.
+ */
+class AnotherProjectServiceContainer extends Container
+{
+ /**
+ * Constructor.
+ */
+ public function __construct()
+ {
+ $this->services =
+ $this->scopedServices =
+ $this->scopeStacks = array();
+
+ $this->set('service_container', $this);
+
+ $this->scopes = array('request' => 'container');
+ $this->scopeChildren = array('request' => array());
+ $this->methodMap = array(
+ 'depends_on_synchronized' => 'getDependsonsynchronizedService',
+ 'synchronized_service' => 'getSynchronizedserviceService',
+ );
+
+ $this->aliases = array();
+ }
+
+ /**
+ * Gets the 'dependsonsynchronized' service.
+ *
+ * This service is shared.
+ * This method always returns the same instance of the service.
+ *
+ * @return FooClass A FooClass instance.
+ */
+ protected function getDependsonsynchronizedService()
+ {
+ $this->services['depends_on_synchronized'] = $instance = new \FooClass();
+
+ $instance->setBar($this->get('synchronized_service', ContainerInterface::NULL_ON_INVALID_REFERENCE));
+
+ return $instance;
+ }
+
+ /**
+ * Gets the 'synchronizedservice' service.
+ *
+ * This service is shared.
+ * This method always returns the same instance of the service.
+ *
+ * @return BarClass A BarClass instance.
+ *
+ * @throws InactiveScopeException when the 'synchronizedservice' service is requested while the 'request' scope is not active
+ */
+ protected function getSynchronizedserviceService()
+ {
+ if (!isset($this->scopedServices['request'])) {
+ throw new InactiveScopeException('synchronized_service', 'request');
+ }
+
+ $this->services['synchronized_service'] = $this->scopedServices['request']['synchronized_service'] = $instance = new \BarClass();
+
+ $this->synchronizeSynchronizedserviceService();
+
+ return $instance;
+ }
+
+ /**
+ * Updates the 'synchronizedservice' service.
+ */
+ protected function synchronizeSynchronizedserviceService()
+ {
+ if ($this->initialized('depends_on_synchronized')) {
+ $this->get('depends_on_synchronized')->setBar($this->get('synchronized_service', ContainerInterface::NULL_ON_INVALID_REFERENCE));
+ }
+ }
+}
Something went wrong with that request. Please try again.