[HttpKernel] Move services reset to Kernel
This commit is contained in:
parent
fdac9e3911
commit
4501a3688b
@ -75,10 +75,6 @@
|
||||
<tag name="config_cache.resource_checker" priority="-990" />
|
||||
</service>
|
||||
|
||||
<service id="Symfony\Component\HttpKernel\EventListener\ServiceResetListener">
|
||||
<argument /> <!-- ResettableServicePass will inject an iterator of initialized services here ($serviceId => $serviceInstance) -->
|
||||
<argument type="collection" /> <!-- ResettableServicePass will inject an array of reset methods here ($serviceId => $method) -->
|
||||
<tag name="kernel.event_subscriber" />
|
||||
</service>
|
||||
<service id="services_resetter" class="Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter" public="true" />
|
||||
</services>
|
||||
</container>
|
||||
|
@ -17,7 +17,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpKernel\EventListener\ServiceResetListener;
|
||||
|
||||
/**
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
@ -26,9 +25,6 @@ class ResettableServicePass implements CompilerPassInterface
|
||||
{
|
||||
private $tagName;
|
||||
|
||||
/**
|
||||
* @param string $tagName
|
||||
*/
|
||||
public function __construct($tagName = 'kernel.reset')
|
||||
{
|
||||
$this->tagName = $tagName;
|
||||
@ -39,7 +35,7 @@ class ResettableServicePass implements CompilerPassInterface
|
||||
*/
|
||||
public function process(ContainerBuilder $container)
|
||||
{
|
||||
if (!$container->has(ServiceResetListener::class)) {
|
||||
if (!$container->has('services_resetter')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -57,13 +53,13 @@ class ResettableServicePass implements CompilerPassInterface
|
||||
}
|
||||
|
||||
if (empty($services)) {
|
||||
$container->removeDefinition(ServiceResetListener::class);
|
||||
$container->removeDefinition('services_resetter');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$container->findDefinition(ServiceResetListener::class)
|
||||
->replaceArgument(0, new IteratorArgument($services))
|
||||
->replaceArgument(1, $methods);
|
||||
$container->findDefinition('services_resetter')
|
||||
->setArgument(0, new IteratorArgument($services))
|
||||
->setArgument(1, $methods);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\DependencyInjection;
|
||||
|
||||
/**
|
||||
* Resets provided services.
|
||||
*
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class ServicesResetter
|
||||
{
|
||||
private $resettableServices;
|
||||
private $resetMethods;
|
||||
|
||||
public function __construct(\Traversable $resettableServices, array $resetMethods)
|
||||
{
|
||||
$this->resettableServices = $resettableServices;
|
||||
$this->resetMethods = $resetMethods;
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
foreach ($this->resettableServices as $id => $service) {
|
||||
$service->{$this->resetMethods[$id]}();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\EventListener;
|
||||
|
||||
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
use Symfony\Component\HttpKernel\KernelEvents;
|
||||
|
||||
/**
|
||||
* Clean up services between requests.
|
||||
*
|
||||
* @author Alexander M. Turek <me@derrabus.de>
|
||||
*/
|
||||
class ServiceResetListener implements EventSubscriberInterface
|
||||
{
|
||||
private $services;
|
||||
private $resetMethods;
|
||||
|
||||
public function __construct(\Traversable $services, array $resetMethods)
|
||||
{
|
||||
$this->services = $services;
|
||||
$this->resetMethods = $resetMethods;
|
||||
}
|
||||
|
||||
public function onKernelTerminate()
|
||||
{
|
||||
foreach ($this->services as $id => $service) {
|
||||
$method = $this->resetMethods[$id];
|
||||
$service->$method();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
KernelEvents::TERMINATE => array('onKernelTerminate', -2048),
|
||||
);
|
||||
}
|
||||
}
|
@ -64,6 +64,8 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
|
||||
|
||||
private $projectDir;
|
||||
private $warmupDir;
|
||||
private $requestStackSize = 0;
|
||||
private $resetServices = false;
|
||||
|
||||
const VERSION = '3.4.0-DEV';
|
||||
const VERSION_ID = 30400;
|
||||
@ -99,6 +101,8 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
|
||||
|
||||
$this->booted = false;
|
||||
$this->container = null;
|
||||
$this->requestStackSize = 0;
|
||||
$this->resetServices = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,8 +111,20 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
|
||||
public function boot()
|
||||
{
|
||||
if (true === $this->booted) {
|
||||
if (!$this->requestStackSize && $this->resetServices) {
|
||||
if ($this->container->has('services_resetter')) {
|
||||
$this->container->get('services_resetter')->reset();
|
||||
}
|
||||
$this->resetServices = false;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if ($this->debug && !isset($_SERVER['SHELL_VERBOSITY'])) {
|
||||
putenv('SHELL_VERBOSITY=3');
|
||||
$_ENV['SHELL_VERBOSITY'] = 3;
|
||||
$_SERVER['SHELL_VERBOSITY'] = 3;
|
||||
}
|
||||
|
||||
if ($this->loadClassCache) {
|
||||
$this->doLoadClassCache($this->loadClassCache[0], $this->loadClassCache[1]);
|
||||
@ -169,6 +185,8 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
|
||||
}
|
||||
|
||||
$this->container = null;
|
||||
$this->requestStackSize = 0;
|
||||
$this->resetServices = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -176,17 +194,15 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
|
||||
*/
|
||||
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
|
||||
{
|
||||
if (false === $this->booted) {
|
||||
if ($this->debug && !isset($_SERVER['SHELL_VERBOSITY'])) {
|
||||
putenv('SHELL_VERBOSITY=3');
|
||||
$_ENV['SHELL_VERBOSITY'] = 3;
|
||||
$_SERVER['SHELL_VERBOSITY'] = 3;
|
||||
}
|
||||
$this->boot();
|
||||
++$this->requestStackSize;
|
||||
$this->resetServices = true;
|
||||
|
||||
$this->boot();
|
||||
try {
|
||||
return $this->getHttpKernel()->handle($request, $type, $catch);
|
||||
} finally {
|
||||
--$this->requestStackSize;
|
||||
}
|
||||
|
||||
return $this->getHttpKernel()->handle($request, $type, $catch);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -8,7 +8,7 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
|
||||
use Symfony\Component\HttpKernel\EventListener\ServiceResetListener;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
|
||||
|
||||
@ -24,14 +24,14 @@ class ResettableServicePassTest extends TestCase
|
||||
->setPublic(true)
|
||||
->addTag('kernel.reset', array('method' => 'clear'));
|
||||
|
||||
$container->register(ServiceResetListener::class)
|
||||
$container->register('services_resetter', ServicesResetter::class)
|
||||
->setPublic(true)
|
||||
->setArguments(array(null, array()));
|
||||
$container->addCompilerPass(new ResettableServicePass('kernel.reset'));
|
||||
$container->addCompilerPass(new ResettableServicePass());
|
||||
|
||||
$container->compile();
|
||||
|
||||
$definition = $container->getDefinition(ServiceResetListener::class);
|
||||
$definition = $container->getDefinition('services_resetter');
|
||||
|
||||
$this->assertEquals(
|
||||
array(
|
||||
@ -57,9 +57,9 @@ class ResettableServicePassTest extends TestCase
|
||||
$container = new ContainerBuilder();
|
||||
$container->register(ResettableService::class)
|
||||
->addTag('kernel.reset');
|
||||
$container->register(ServiceResetListener::class)
|
||||
$container->register('services_resetter', ServicesResetter::class)
|
||||
->setArguments(array(null, array()));
|
||||
$container->addCompilerPass(new ResettableServicePass('kernel.reset'));
|
||||
$container->addCompilerPass(new ResettableServicePass());
|
||||
|
||||
$container->compile();
|
||||
}
|
||||
@ -67,22 +67,12 @@ class ResettableServicePassTest extends TestCase
|
||||
public function testCompilerPassWithoutResetters()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register(ServiceResetListener::class)
|
||||
$container->register('services_resetter', ServicesResetter::class)
|
||||
->setArguments(array(null, array()));
|
||||
$container->addCompilerPass(new ResettableServicePass());
|
||||
|
||||
$container->compile();
|
||||
|
||||
$this->assertFalse($container->has(ServiceResetListener::class));
|
||||
}
|
||||
|
||||
public function testCompilerPassWithoutListener()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->addCompilerPass(new ResettableServicePass());
|
||||
|
||||
$container->compile();
|
||||
|
||||
$this->assertFalse($container->has(ServiceResetListener::class));
|
||||
$this->assertFalse($container->has('services_resetter'));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
|
||||
|
||||
class ServicesResetterTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
ResettableService::$counter = 0;
|
||||
ClearableService::$counter = 0;
|
||||
}
|
||||
|
||||
public function testResetServices()
|
||||
{
|
||||
$resetter = new ServicesResetter(new \ArrayIterator(array(
|
||||
'id1' => new ResettableService(),
|
||||
'id2' => new ClearableService(),
|
||||
)), array(
|
||||
'id1' => 'reset',
|
||||
'id2' => 'clear',
|
||||
));
|
||||
|
||||
$resetter->reset();
|
||||
|
||||
$this->assertEquals(1, ResettableService::$counter);
|
||||
$this->assertEquals(1, ClearableService::$counter);
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\HttpKernel\Tests\EventListener;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpKernel\EventListener\ServiceResetListener;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
|
||||
|
||||
class ServiceResetListenerTest extends TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
ResettableService::$counter = 0;
|
||||
ClearableService::$counter = 0;
|
||||
}
|
||||
|
||||
public function testResetServicesNoOp()
|
||||
{
|
||||
$container = $this->buildContainer();
|
||||
$container->get('reset_subscriber')->onKernelTerminate();
|
||||
|
||||
$this->assertEquals(0, ResettableService::$counter);
|
||||
$this->assertEquals(0, ClearableService::$counter);
|
||||
}
|
||||
|
||||
public function testResetServicesPartially()
|
||||
{
|
||||
$container = $this->buildContainer();
|
||||
$container->get('one');
|
||||
$container->get('reset_subscriber')->onKernelTerminate();
|
||||
|
||||
$this->assertEquals(1, ResettableService::$counter);
|
||||
$this->assertEquals(0, ClearableService::$counter);
|
||||
}
|
||||
|
||||
public function testResetServicesTwice()
|
||||
{
|
||||
$container = $this->buildContainer();
|
||||
$container->get('one');
|
||||
$container->get('reset_subscriber')->onKernelTerminate();
|
||||
$container->get('two');
|
||||
$container->get('reset_subscriber')->onKernelTerminate();
|
||||
|
||||
$this->assertEquals(2, ResettableService::$counter);
|
||||
$this->assertEquals(1, ClearableService::$counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ContainerBuilder
|
||||
*/
|
||||
private function buildContainer()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container->register('one', ResettableService::class)->setPublic(true);
|
||||
$container->register('two', ClearableService::class)->setPublic(true);
|
||||
|
||||
$container->register('reset_subscriber', ServiceResetListener::class)
|
||||
->setPublic(true)
|
||||
->addArgument(new IteratorArgument(array(
|
||||
'one' => new Reference('one', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
|
||||
'two' => new Reference('two', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
|
||||
)))
|
||||
->addArgument(array(
|
||||
'one' => 'reset',
|
||||
'two' => 'clear',
|
||||
));
|
||||
|
||||
$container->compile();
|
||||
|
||||
return $container;
|
||||
}
|
||||
}
|
@ -18,6 +18,8 @@ use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\Filesystem\Filesystem;
|
||||
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
|
||||
use Symfony\Component\HttpKernel\Config\EnvParametersResource;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
|
||||
use Symfony\Component\HttpKernel\Kernel;
|
||||
use Symfony\Component\HttpKernel\HttpKernelInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
@ -25,6 +27,7 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\KernelForOverrideName;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\KernelWithoutBundles;
|
||||
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
|
||||
|
||||
class KernelTest extends TestCase
|
||||
{
|
||||
@ -840,6 +843,38 @@ EOF;
|
||||
$this->assertTrue($kernel->getContainer()->getParameter('test.processed'));
|
||||
}
|
||||
|
||||
public function testServicesResetter()
|
||||
{
|
||||
$httpKernelMock = $this->getMockBuilder(HttpKernelInterface::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$httpKernelMock
|
||||
->expects($this->exactly(2))
|
||||
->method('handle');
|
||||
|
||||
$kernel = new CustomProjectDirKernel(function ($container) {
|
||||
$container->addCompilerPass(new ResettableServicePass());
|
||||
$container->register('one', ResettableService::class)
|
||||
->setPublic(true)
|
||||
->addTag('kernel.reset', array('method' => 'reset'));
|
||||
$container->register('services_resetter', ServicesResetter::class)->setPublic(true);
|
||||
}, $httpKernelMock, 'resetting');
|
||||
|
||||
ResettableService::$counter = 0;
|
||||
|
||||
$request = new Request();
|
||||
|
||||
$kernel->handle($request);
|
||||
$kernel->getContainer()->get('one');
|
||||
|
||||
$this->assertEquals(0, ResettableService::$counter);
|
||||
$this->assertFalse($kernel->getContainer()->initialized('services_resetter'));
|
||||
|
||||
$kernel->handle($request);
|
||||
|
||||
$this->assertEquals(1, ResettableService::$counter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a mock for the BundleInterface.
|
||||
*
|
||||
@ -941,13 +976,15 @@ class CustomProjectDirKernel extends Kernel
|
||||
{
|
||||
private $baseDir;
|
||||
private $buildContainer;
|
||||
private $httpKernel;
|
||||
|
||||
public function __construct(\Closure $buildContainer = null)
|
||||
public function __construct(\Closure $buildContainer = null, HttpKernelInterface $httpKernel = null, $name = 'custom')
|
||||
{
|
||||
parent::__construct('custom', true);
|
||||
parent::__construct($name, true);
|
||||
|
||||
$this->baseDir = 'foo';
|
||||
$this->buildContainer = $buildContainer;
|
||||
$this->httpKernel = $httpKernel;
|
||||
}
|
||||
|
||||
public function registerBundles()
|
||||
@ -975,6 +1012,11 @@ class CustomProjectDirKernel extends Kernel
|
||||
$build($container);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getHttpKernel()
|
||||
{
|
||||
return $this->httpKernel;
|
||||
}
|
||||
}
|
||||
|
||||
class PassKernel extends CustomProjectDirKernel implements CompilerPassInterface
|
||||
|
Reference in New Issue
Block a user