diff --git a/lib/Alchemy/Phrasea/Core/Provider/SessionHandlerServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/SessionHandlerServiceProvider.php index 54d03b0c65..06dd62b910 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/SessionHandlerServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/SessionHandlerServiceProvider.php @@ -14,6 +14,9 @@ namespace Alchemy\Phrasea\Core\Provider; use Alchemy\Phrasea\Core\Configuration\SessionHandlerFactory; use Silex\Application; use Silex\ServiceProviderInterface; +use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelEvents; class SessionHandlerServiceProvider implements ServiceProviderInterface { @@ -27,10 +30,24 @@ class SessionHandlerServiceProvider implements ServiceProviderInterface }); } + public function onKernelResponse(FilterResponseEvent $event) + { + if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { + return; + } + + $session = $event->getRequest()->getSession(); + if ($session && $session->isStarted()) { + $session->save(); + } + } + /** * {@inheritdoc} */ public function boot(Application $app) { + // Priority should be lower than test session mock listener + $app['dispatcher']->addListener(KernelEvents::RESPONSE, array($this, 'onKernelResponse'), -129); } } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7c9878e721..90a9513d90 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -22,11 +22,13 @@ - - lib/vendor - tests - vendor - + + tests + vendor + + + lib + diff --git a/tests/Alchemy/Tests/Phrasea/Core/Provider/SessionHandlerServiceProviderTest.php b/tests/Alchemy/Tests/Phrasea/Core/Provider/SessionHandlerServiceProviderTest.php index 61050e96fd..cbfd74b24d 100644 --- a/tests/Alchemy/Tests/Phrasea/Core/Provider/SessionHandlerServiceProviderTest.php +++ b/tests/Alchemy/Tests/Phrasea/Core/Provider/SessionHandlerServiceProviderTest.php @@ -5,17 +5,31 @@ namespace Alchemy\Tests\Phrasea\Core\Provider; use Alchemy\Phrasea\Core\Configuration\PropertyAccess; use Alchemy\Phrasea\Core\Provider\SessionHandlerServiceProvider; use Alchemy\Tests\Phrasea\MockArrayConf; -use Silex\Application as SilexApp; +use Silex\Application; use Silex\Provider\SessionServiceProvider; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\HttpKernel\Event\FilterResponseEvent; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\KernelEvents; -class SessionHandlerServiceProviderTest extends \PhraseanetTestCase +class SessionHandlerServiceProviderTest extends \PHPUnit_Framework_TestCase { - /** - * @dataProvider provideVariousConfs - */ - public function testWithVariousConf($sessionConf, $expectedInstance, $method = null, $options = null, $mock = null) + /** @var SessionHandlerServiceProvider */ + private $sut; + + protected function setUp() { - $app = new SilexApp(); + $this->sut = new SessionHandlerServiceProvider(); + } + + /** + * @dataProvider provideVariousConfigurations + */ + public function testWithVariousConfigurations($sessionConf, $expectedInstance, $method = null, $options = null, $mock = null) + { + $app = new Application(); $app['root.path'] = __DIR__ . '/../../../../../..'; $app->register(new SessionServiceProvider()); $app->register(new SessionHandlerServiceProvider()); @@ -35,60 +49,9 @@ class SessionHandlerServiceProviderTest extends \PhraseanetTestCase $this->assertInstanceOf($expectedInstance, $handler); } - public function provideVariousConfs() + public function provideVariousConfigurations() { - $memcache = $this->getMockBuilder('Memcache') - ->disableOriginalConstructor() - ->getMock(); - - @$memcached = $this->getMockBuilder('Memcached') - ->disableOriginalConstructor() - ->getMock(); - - $redis = $this->getMockBuilder('Redis') - ->disableOriginalConstructor() - ->getMock(); - - return [ - [ - [ - 'type' => 'memcache', - 'options' => [ - 'host' => 'localhost', - 'port' => '11211', - ] - ], - 'Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler', - 'getMemcacheConnection', - ['host' => 'localhost', 'port' => 11211], - $memcache - ], - [ - [ - 'type' => 'memcached', - 'options' => [ - 'host' => 'localhost', - 'port' => '11211', - ] - ], - 'Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler', - 'getMemcachedConnection', - ['host' => 'localhost', 'port' => 11211], - $memcached - ], - [ - [ - 'type' => 'redis', - 'options' => [ - 'host' => '127.0.0.1', - 'port' => '6379', - ] - ], - 'Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler', - 'getRedisConnection', - ['host' => '127.0.0.1', 'port' => 6379], - $redis - ], + $configurations = [ [ [ 'main' => [ @@ -100,5 +63,129 @@ class SessionHandlerServiceProviderTest extends \PhraseanetTestCase 'Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHandler' ] ]; + + if (class_exists('Memcache')) { + $memcache = $this->getMockBuilder('Memcache') + ->disableOriginalConstructor() + ->getMock(); + + $configurations[] = [ + [ + 'type' => 'memcache', + 'options' => [ + 'host' => 'localhost', + 'port' => '11211', + ] + ], + 'Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler', + 'getMemcacheConnection', + ['host' => 'localhost', 'port' => 11211], + $memcache + ]; + } + + if (class_exists('Memcached')) { + // Error suppressor due to Memcached having now obsolete by reference declarations + @$memcached = $this->getMockBuilder('Memcached') + ->disableOriginalConstructor() + ->getMock(); + + $configurations[] = [ + [ + 'type' => 'memcached', + 'options' => [ + 'host' => 'localhost', + 'port' => '11211', + ] + ], + 'Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler', + 'getMemcachedConnection', + ['host' => 'localhost', 'port' => 11211], + $memcached + ]; + } + + if (class_exists('Redis')) { + $redis = $this->getMockBuilder('Redis') + ->disableOriginalConstructor() + ->getMock(); + + $configurations[] = [ + [ + 'type' => 'redis', + 'options' => [ + 'host' => '127.0.0.1', + 'port' => '6379', + ] + ], + 'Symfony\Component\HttpFoundation\Session\Storage\Handler\WriteCheckSessionHandler', + 'getRedisConnection', + ['host' => '127.0.0.1', 'port' => 6379], + $redis + ]; + } + + return $configurations; + } + + public function testItIgnoresSubRequests() + { + $event = $this->getMockBuilder(FilterResponseEvent::class) + ->disableOriginalConstructor() + ->getMock(); + + $event->expects($this->once()) + ->method('getRequestType') + ->willReturn(HttpKernelInterface::SUB_REQUEST) + ; + + $this->sut->onKernelResponse($event); + } + + public function testItSavesSessionAtKernelResponseEvent() + { + $session = $this->getMock(SessionInterface::class); + $session + ->expects($this->once()) + ->method('isStarted') + ->willReturn(true) + ; + $session + ->expects($this->once()) + ->method('save') + ; + + $request = new Request(); + $request->setSession($session); + + $event = $this->getMockBuilder(FilterResponseEvent::class) + ->disableOriginalConstructor() + ->getMock(); + + $event->expects($this->once()) + ->method('getRequestType') + ->willReturn(HttpKernelInterface::MASTER_REQUEST) + ; + $event + ->expects($this->once()) + ->method('getRequest') + ->willReturn($request) + ; + + $this->sut->onKernelResponse($event); + } + + public function testItAddsFilterResponseAtBoot() + { + $dispatcher = $this->getMock(EventDispatcherInterface::class); + $dispatcher + ->expects($this->once()) + ->method('addListener') + ->with(KernelEvents::RESPONSE, [$this->sut, 'onKernelResponse'], -129); + + $app = new Application(); + $app['dispatcher'] = $dispatcher; + + $this->sut->boot($app); } }