8000 [DI] leverage Contracts\Service by nicolas-grekas · Pull Request #28207 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DI] leverage Contracts\Service #28207

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 5, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[DI] leverage Contracts\Service
  • Loading branch information
nicolas-grekas committed Sep 4, 2018
commit 87392ab30dedc51ec4f07e917f80f0bebe7a04f8
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\Finder\Finder;
Expand Down Expand Up @@ -102,6 +101,7 @@
use Symfony\Component\Yaml\Command\LintCommand as BaseYamlLintCommand;
use Symfony\Component\Yaml\Yaml;
use Symfony\Contracts\Service\ResetInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

/**
* FrameworkExtension.
Expand Down
4 changes: 2 additions & 2 deletions src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@

use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ResettableContainerInterface;
use Symfony\Component\HttpKernel\KernelInterface;
use Symfony\Contracts\Service\ResetInterface;

/**
* KernelTestCase is the base class for tests needing a Kernel.
Expand Down Expand Up @@ -119,7 +119,7 @@ protected static function ensureKernelShutdown()
if (null !== static::$kernel) {
$container = static::$kernel->getContainer();
static::$kernel->shutdown();
if ($container instanceof ResettableContainerInterface) {
if ($container instanceof ResetInterface) {
$container->reset();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@

namespace Symfony\Component\Config\Resource;

use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface as LegacyServiceSubscriberInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

/**
* @author Nicolas Grekas <p@tchwork.com>
Expand Down Expand Up @@ -157,7 +158,10 @@ private function generateSignature(\ReflectionClass $class)
yield print_r(\call_user_func(array($class->name, 'getSubscribedEvents')), true);
}

if (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
if (interface_exists(LegacyServiceSubscriberInterface::class, false) && $class->isSubclassOf(LegacyServiceSubscriberInterface::class)) {
yield LegacyServiceSubscriberInterface::class;
yield print_r(\call_user_func(array($class->name, 'getSubscribedServices')), true);
} elseif (interface_exists(ServiceSubscriberInterface::class, false) && $class->isSubclassOf(ServiceSubscriberInterface::class)) {
yield ServiceSubscriberInterface::class;
yield print_r(\call_user_func(array($class->name, 'getSubscribedServices')), true);
}
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/DependencyInjection/CHANGELOG.md
8000
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ CHANGELOG
* added `ServiceLocatorArgument` and `!service_locator` config tag for creating optimized service-locators
* added support for autoconfiguring bindings
* added `%env(key:...)%` processor to fetch a specific key from an array
* deprecated `ServiceSubscriberInterface`, use the same interface from the `Symfony\Contracts\Service` namespace instead
* deprecated `ResettableContainerInterface`, use `Symfony\Contracts\Service\ResetInterface` instead

4.1.0
-----
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

/**
* Compiler pass to register tagged services that require a service locator.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
* not needed anymore.
*
* @author Christophe Coevoet <stof@notk.org>
*
* @deprecated since Symfony 4.2, use "Symfony\Contracts\Service\ResetInterface" instead.
*/
interface ResettableContainerInterface extends ContainerInterface, ResetInterface
{
Expand Down
66 changes: 23 additions & 43 deletions src/Symfony/Component/DependencyInjection/ServiceLocator.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,62 +11,37 @@

namespace Symfony\Component\DependencyInjection;

use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface as PsrContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Contracts\Service\ServiceLocatorTrait;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

/**
* @author Robin Chalas <robin.chalas@gmail.com>
* @author Nicolas Grekas <p@tchwork.com>
*/
class ServiceLocator implements PsrContainerInterface
{
private $factories;
private $loading = array();
private $externalId;
private $container;

/**
* @param callable[] $factories
*/
public function __construct(array $factories)
{
$this->factories = $factories;
use ServiceLocatorTrait {
get as private doGet;
}

/**
* {@inheritdoc}
*/
public function has($id)
{
return isset($this->factories[$id]);
}
private $externalId;
private $container;

/**
* {@inheritdoc}
*/
public function get($id)
{
if (!isset($this->factories[$id])) {
throw new ServiceNotFoundException($id, end($this->loading) ?: null, null, array(), $this->createServiceNotFoundMessage($id));
}

if (isset($this->loading[$id])) {
$ids = array_values($this->loading);
$ids = \array_slice($this->loading, array_search($id, $ids));
$ids[] = $id;

throw new ServiceCircularReferenceException($id, $ids);
if (!$this->externalId) {
return $this->doGet($id);
}

$this->loading[$id] = $id;
try {
return $this->factories[$id]();
return $this->doGet($id);
} catch (RuntimeException $e) {
if (!$this->externalId) {
throw $e;
}
$what = sprintf('service "%s" required by "%s"', $id, $this->externalId);
$message = preg_replace('/service "\.service_locator\.[^"]++"/', $what, $e->getMessage());

Expand All @@ -79,8 +54,6 @@ public function get($id)
$r->setValue($e, $message);

throw $e;
} finally {
unset($this->loading[$id]);
}
}

Expand All @@ -101,14 +74,16 @@ public function withContext($externalId, Container $container)
return $locator;
}

private function createServiceNotFoundMessage($id)
private function createNotFoundException(string $id): NotFoundExceptionInterface
{
if ($this->loading) {
return sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $this->formatAlternatives());
$msg = sprintf('The service "%s" has a dependency on a non-existent service "%s". This locator %s', end($this->loading), $id, $this->formatAlternatives());

return new ServiceNotFoundException($id, end($this->loading) ?: null, null, array(), $msg);
}

$class = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, 3);
$class = isset($class[2]['object']) ? \get_class($class[2]['object']) : null;
$class = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS, 4);
$class = isset($class[3]['object']) ? \get_class($class[3]['object']) : null;
$externalId = $this->externalId ?: $class;

$msg = sprintf('Service "%s" not found: ', $id);
Expand Down Expand Up @@ -143,7 +118,12 @@ private function createServiceNotFoundMessage($id)
$msg .= 'Try using dependency injection instead.';
}

return $msg;
return new ServiceNotFoundException($id, end($this->loading) ?: null, null, array(), $msg);
}

private function createCircularReferenceException(string $id, array $path): ContainerExceptionInterface
{
return new ServiceCircularReferenceException($id, $path);
}

private function formatAlternatives(array $alternatives = null, $separator = 'and')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,13 @@

namespace Symfony\Component\DependencyInjection;

use Symfony\Contracts\Service\ServiceSubscriberInterface as BaseServiceSubscriberInterface;

/**
* A ServiceSubscriber exposes its dependencies via the static {@link getSubscribedServices} method.
*
* The getSubscribedServices method returns an array of service types required by such instances,
* optionally keyed by the service names used internally. Service types that start with an interrogation
* mark "?" are optional, while the other ones are mandatory service dependencies.
*
* The injected service locators SHOULD NOT allow access to any other services not specified by the method.
*
* It is expected that ServiceSubscriber instances consume PSR-11-based service locators internally.
* This interface does not dictate any injection method for these service locators, although constructor
* injection is recommended.
* {@inheritdoc}
*
* @author Nicolas Grekas <p@tchwork.com>
* @deprecated since Symfony 4.2, use Symfony\Contracts\Service\ServiceSubscriberInterface instead.
*/
interface ServiceSubscriberInterface
interface ServiceSubscriberInterface extends BaseServiceSubscriberInterface
{
/**
* Returns an array of service types required by such instances, optionally keyed by the service names used internally.
*
* For mandatory dependencies:
*
* * array('logger' => 'Psr\Log\LoggerInterface') means the objects use the "logger" name
* internally to fetch a service which must implement Psr\Log\LoggerInterface.
* * array('Psr\Log\LoggerInterface') is a shortcut for
* * array('Psr\Log\LoggerInterface' => 'Psr\Log\LoggerInterface')
*
* otherwise:
*
* * array('logger' => '?Psr\Log\LoggerInterface') denotes an optional dependency
* * array('?Psr\Log\LoggerInterface') is a shortcut for
* * array('Psr\Log\LoggerInterface' => '?Psr\Log\LoggerInterface')
*
* @return array The required service types, optionally keyed by service names
*/
public static function getSubscribedServices();
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class RegisterServiceSubscribersPassTest extends TestCase
{
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
* @expectedExceptionMessage Service "foo" must implement interface "Symfony\Component\DependencyInjection\ServiceSubscriberInterface".
* @expectedExceptionMessage Service "foo" must implement interface "Symfony\Contracts\Service\ServiceSubscriberInterface".
*/
public function testInvalidClass()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

class TestServiceSubscriber implements ServiceSubscriberInterface
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberTrait;

class TestServiceSubscriberParent implements ServiceSubscriberInterface
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

function sc_configure($instance)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
use Symfony\Contracts\Tests\Service\ServiceLocatorTest as BaseServiceLocatorTest;

class ServiceLocatorTest extends BaseServiceLocatorTest
Expand Down Expand Up @@ -74,7 +74,7 @@ public function testInvoke()
}
}

class SomeServiceSubscriber implements ServiceSubscriberinterface
class SomeServiceSubscriber implements ServiceSubscriberInterface
{
public $container;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
namespace Symfony\Component\HttpKernel\Tests\EventListener;

use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
Expand Down Expand Up @@ -144,15 +143,6 @@ public function testUnstartedSessionIsNotSave()
$this->filterResponse(new Request());
}

public function testDoesNotImplementServiceSubscriberInterface()
{
$this->assertTrue(interface_exists(ServiceSubscriberInterface::class));
$this->assertTrue(class_exists(SessionListener::class));
$this->assertTrue(class_exists(TestSessionListener::class));
$this->assertFalse(is_subclass_of(SessionListener::class, ServiceSubscriberInterface::class), 'Implementing ServiceSubscriberInterface would create a dep on the DI component, which eg Silex cannot afford');
$this->assertFalse(is_subclass_of(TestSessionListener::class, ServiceSubscriberInterface::class, 'Implementing ServiceSubscriberInterface would create a dep on the DI component, which eg Silex cannot afford'));
}

public function testDoesNotThrowIfRequestDoesNotHaveASession()
{
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
Expand Down
0