Skip to content

Commit 6ff44c4

Browse files
mateuszsipnicolas-grekas
authored andcommitted
[DI][Contracts] add and implement ServiceProviderInterface
1 parent d4326b2 commit 6ff44c4

File tree

8 files changed

+78
-5
lines changed

8 files changed

+78
-5
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ CHANGELOG
1010
* added support for deprecating aliases
1111
* made `ContainerParametersResource` final and not implement `Serializable` anymore
1212
* added ability to define an index for a tagged collection
13+
* made `ServiceLocator` implement `ServiceProviderInterface`
1314

1415
4.2.0
1516
-----

src/Symfony/Component/DependencyInjection/Compiler/ResolveServiceSubscribersPass.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Psr\Container\ContainerInterface;
1515
use Symfony\Component\DependencyInjection\Definition;
1616
use Symfony\Component\DependencyInjection\Reference;
17+
use Symfony\Contracts\Service\ServiceProviderInterface;
1718

1819
/**
1920
* Compiler pass to inject their service locator to service subscribers.
@@ -26,7 +27,7 @@ class ResolveServiceSubscribersPass extends AbstractRecursivePass
2627

2728
protected function processValue($value, $isRoot = false)
2829
{
29-
if ($value instanceof Reference && $this->serviceLocator && ContainerInterface::class === (string) $value) {
30+
if ($value instanceof Reference && $this->serviceLocator && \in_array((string) $value, [ContainerInterface::class, ServiceProviderInterface::class], true)) {
3031
return new Reference($this->serviceLocator);
3132
}
3233

src/Symfony/Component/DependencyInjection/ServiceLocator.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,19 @@
1212
namespace Symfony\Component\DependencyInjection;
1313

1414
use Psr\Container\ContainerExceptionInterface;
15-
use Psr\Container\ContainerInterface as PsrContainerInterface;
1615
use Psr\Container\NotFoundExceptionInterface;
1716
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
1817
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
1918
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
2019
use Symfony\Contracts\Service\ServiceLocatorTrait;
20+
use Symfony\Contracts\Service\ServiceProviderInterface;
2121
use Symfony\Contracts\Service\ServiceSubscriberInterface;
2222

2323
/**
2424
* @author Robin Chalas <robin.chalas@gmail.com>
2525
* @author Nicolas Grekas <p@tchwork.com>
2626
*/
27-
class ServiceLocator implements PsrContainerInterface
27+
class ServiceLocator implements ServiceProviderInterface
2828
{
2929
use ServiceLocatorTrait {
3030
get as private doGet;

src/Symfony/Component/DependencyInjection/Tests/ServiceLocatorTest.php

+15
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,21 @@ public function testInvoke()
8686
$this->assertSame('baz', $locator('bar'));
8787
$this->assertNull($locator('dummy'), '->__invoke() should return null on invalid service');
8888
}
89+
90+
public function testProvidesServicesInformation()
91+
{
92+
$locator = new ServiceLocator([
93+
'foo' => function () { return 'bar'; },
94+
'bar' => function (): string { return 'baz'; },
95+
'baz' => function (): ?string { return 'zaz'; },
96+
]);
97+
98+
$this->assertSame($locator->getProvidedServices(), [
99+
'foo' => '?',
100+
'bar' => 'string',
101+
'baz' => '?string',
102+
]);
103+
}
89104
}
90105

91106
class SomeServiceSubscriber implements ServiceSubscriberInterface

src/Symfony/Component/DependencyInjection/composer.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"require": {
1919
"php": "^7.1.3",
2020
"psr/container": "^1.0",
21-
"symfony/contracts": "^1.0"
21+
"symfony/contracts": "^1.1"
2222
},
2323
"require-dev": {
2424
"symfony/yaml": "~3.4|~4.0",

src/Symfony/Contracts/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
-----
66

77
* added `HttpClient` namespace with contracts for implementing flexible HTTP clients
8+
* added `ServiceProviderInterface`
89

910
1.0.0
1011
-----

src/Symfony/Contracts/Service/ServiceLocatorTrait.php

+20-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use Psr\Container\NotFoundExceptionInterface;
1616

1717
/**
18-
* A trait to help implement PSR-11 service locators.
18+
* A trait to help implement ServiceProviderInterface.
1919
*
2020
* @author Robin Chalas <robin.chalas@gmail.com>
2121
* @author Nicolas Grekas <p@tchwork.com>
@@ -24,6 +24,7 @@ trait ServiceLocatorTrait
2424
{
2525
private $factories;
2626
private $loading = [];
27+
private $providedTypes;
2728

2829
/**
2930
* @param callable[] $factories
@@ -66,6 +67,24 @@ public function get($id)
6667
}
6768
}
6869

70+
/**
71+
* {@inheritdoc}
72+
*/
73+
public function getProvidedServices(): array
74+
{
75+
if (null === $this->providedTypes) {
76+
$this->providedTypes = [];
77+
78+
foreach ($this->factories as $name => $factory) {
79+
$type = (new \ReflectionFunction($factory))->getReturnType();
80+
81+
$this->providedTypes[$name] = $type ? ($type->allowsNull() ? '?' : '').$type->getName() : '?';
82+
}
83+
}
84+
85+
return $this->providedTypes;
86+
}
87+
6988
private function createNotFoundException(string $id): NotFoundExceptionInterface
7089
{
7190
if (!$alternatives = array_keys($this->factories)) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Contracts\Service;
13+
14+
use Psr\Container\ContainerInterface;
15+
16+
/**
17+
* A ServiceProviderInterface exposes the identifiers and the types of services provided by a container.
18+
*
19+
* @author Nicolas Grekas <p@tchwork.com>
20+
* @author Mateusz Sip <mateusz.sip@gmail.com>
21+
*/
22+
interface ServiceProviderInterface extends ContainerInterface
23+
{
24+
/**
25+
* Returns an associative array of service types keyed by the identifiers provided by the current container.
26+
*
27+
* Examples:
28+
*
29+
* * ['logger' => 'Psr\Log\LoggerInterface'] means the object provides a service named "logger" that implements Psr\Log\LoggerInterface
30+
* * ['foo' => '?'] means the container provides service name "foo" of unspecified type
31+
* * ['bar' => '?Bar\Baz'] means the container provides a service "bar" of type Bar\Baz|null
32+
*
33+
* @return string[] The provided service types, keyed by service names
34+
*/
35+
public function getProvidedServices(): array;
36+
}

0 commit comments

Comments
 (0)