diff --git a/src/ServiceProvider/AbstractServiceProvider.php b/src/ServiceProvider/AbstractServiceProvider.php index 96cc703..de5e26b 100644 --- a/src/ServiceProvider/AbstractServiceProvider.php +++ b/src/ServiceProvider/AbstractServiceProvider.php @@ -24,4 +24,12 @@ public function provides($alias = null) return $this->provides; } + + /** + * {@inheritdoc} + */ + public function signature() + { + return get_class($this); + } } diff --git a/src/ServiceProvider/ServiceProviderAggregate.php b/src/ServiceProvider/ServiceProviderAggregate.php index 665ac2d..27ce91e 100644 --- a/src/ServiceProvider/ServiceProviderAggregate.php +++ b/src/ServiceProvider/ServiceProviderAggregate.php @@ -72,12 +72,12 @@ public function register($service) $provider = $this->providers[$service]; // ensure that the provider hasn't already been invoked by any other service request - if (in_array(get_class($provider), $this->registered)) { + if (in_array($provider->signature(), $this->registered)) { return; } $provider->register(); - $this->registered[] = get_class($provider); + $this->registered[] = $provider->signature(); } } diff --git a/src/ServiceProvider/ServiceProviderInterface.php b/src/ServiceProvider/ServiceProviderInterface.php index a48ccfe..522e427 100644 --- a/src/ServiceProvider/ServiceProviderInterface.php +++ b/src/ServiceProvider/ServiceProviderInterface.php @@ -23,4 +23,13 @@ public function provides($service = null); * @return void */ public function register(); + + /** + * The signature of the service provider uniquely identifies it, so + * that we can quickly determine if it has already been registered. + * Defaults to get_class($provider). + * + * @return string + */ + public function signature(); } diff --git a/tests/Asset/SharedServiceProviderFake.php b/tests/Asset/SharedServiceProviderFake.php index 52bb666..31e9e3b 100644 --- a/tests/Asset/SharedServiceProviderFake.php +++ b/tests/Asset/SharedServiceProviderFake.php @@ -16,16 +16,22 @@ class SharedServiceProviderFake extends AbstractServiceProvider */ private $item; + /** + * @var string + */ + private $signature; + /** * @param string $alias * @param mixed $item */ - public function __construct($alias, $item) + public function __construct($alias, $item, $signature = false) { $this->alias = $alias; $this->item = $item; $this->provides[] = $alias; + $this->signature = $signature ?: get_class($this); } public function register() @@ -36,4 +42,9 @@ public function register() return true; } + + public function signature() + { + return $this->signature; + } } diff --git a/tests/ContainerTest.php b/tests/ContainerTest.php index c60b12d..8926c8b 100644 --- a/tests/ContainerTest.php +++ b/tests/ContainerTest.php @@ -152,6 +152,51 @@ public function testGetReturnsSharedItemFromServiceProvider() $this->assertSame($item, $container->get($alias)); } + /** + * Asserts that the same service provider class cannot be used to + * register two different sets of services. + */ + public function testSameServiceProviderClassCannotBeUsedTwice() + { + $alias = 'foo'; + $item = new \stdClass; + + $alias2 = 'bar'; + $item2 = new \stdClass; + + $container = new Container; + $container->addServiceProvider(new Asset\SharedServiceProviderFake($alias, $item)); + $container->addServiceProvider(new Asset\SharedServiceProviderFake($alias2, $item2)); + + $this->assertSame($item, $container->get($alias)); + + $this->setExpectedException('League\Container\Exception\NotFoundException'); + + $container->get($alias2); + } + + /** + * Asserts that the same service provider class cannot be used to + * register two different sets of services. + */ + public function testSameServiceProviderClassCanBeUsedTwiceWithDifferentSignatures() + { + $alias = 'foo'; + $item = new \stdClass; + $signature1 = 'foo'; + + $alias2 = 'bar'; + $item2 = new \stdClass; + $signature2 = 'bar'; + + $container = new Container; + $container->addServiceProvider(new Asset\SharedServiceProviderFake($alias, $item, $signature1)); + $container->addServiceProvider(new Asset\SharedServiceProviderFake($alias2, $item2, $signature2)); + + $this->assertSame($item, $container->get($alias)); + $this->assertSame($item2, $container->get($alias2)); + } + /** * Asserts that the container to which is delegated can resolve items from the delegating container. */