[HttpFoundation][Cache] Added MarshallingSessionHandler
This commit is contained in:
parent
cde44fcad1
commit
155d980aea
|
@ -0,0 +1,43 @@
|
||||||
|
<?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\Bundle\FrameworkBundle\DependencyInjection\Compiler;
|
||||||
|
|
||||||
|
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||||
|
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
|
||||||
|
*/
|
||||||
|
class RemoveUnusedSessionMarshallingHandlerPass implements CompilerPassInterface
|
||||||
|
{
|
||||||
|
public function process(ContainerBuilder $container)
|
||||||
|
{
|
||||||
|
if (!$container->hasDefinition('session.marshalling_handler')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$isMarshallerDecorated = false;
|
||||||
|
|
||||||
|
foreach ($container->getDefinitions() as $definition) {
|
||||||
|
$decorated = $definition->getDecoratedService();
|
||||||
|
if (null !== $decorated && 'session.marshaller' === $decorated[0]) {
|
||||||
|
$isMarshallerDecorated = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$isMarshallerDecorated) {
|
||||||
|
$container->removeDefinition('session.marshalling_handler');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilder
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RemoveUnusedSessionMarshallingHandlerPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerRealRefPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerRealRefPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerWeakRefPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerWeakRefPass;
|
||||||
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
|
use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass;
|
||||||
|
@ -130,6 +131,7 @@ class FrameworkBundle extends Bundle
|
||||||
$this->addCompilerPassIfExists($container, AddAutoMappingConfigurationPass::class);
|
$this->addCompilerPassIfExists($container, AddAutoMappingConfigurationPass::class);
|
||||||
$container->addCompilerPass(new RegisterReverseContainerPass(true));
|
$container->addCompilerPass(new RegisterReverseContainerPass(true));
|
||||||
$container->addCompilerPass(new RegisterReverseContainerPass(false), PassConfig::TYPE_AFTER_REMOVING);
|
$container->addCompilerPass(new RegisterReverseContainerPass(false), PassConfig::TYPE_AFTER_REMOVING);
|
||||||
|
$container->addCompilerPass(new RemoveUnusedSessionMarshallingHandlerPass());
|
||||||
|
|
||||||
if ($container->getParameter('kernel.debug')) {
|
if ($container->getParameter('kernel.debug')) {
|
||||||
$container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2);
|
$container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2);
|
||||||
|
|
|
@ -71,5 +71,12 @@
|
||||||
|
|
||||||
<!-- for BC -->
|
<!-- for BC -->
|
||||||
<service id="session.storage.filesystem" alias="session.storage.mock_file" />
|
<service id="session.storage.filesystem" alias="session.storage.mock_file" />
|
||||||
|
|
||||||
|
<service id="session.marshaller" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\IdentityMarshaller" />
|
||||||
|
|
||||||
|
<service id="session.marshalling_handler" decorates="session.handler" class="Symfony\Component\HttpFoundation\Session\Storage\Handler\MarshallingSessionHandler">
|
||||||
|
<argument type="service" id="session.marshalling_handler.inner" />
|
||||||
|
<argument type="service" id="session.marshaller" />
|
||||||
|
</service>
|
||||||
</services>
|
</services>
|
||||||
</container>
|
</container>
|
||||||
|
|
|
@ -13,6 +13,7 @@ CHANGELOG
|
||||||
* added `Request::preferSafeContent()` and `Response::setContentSafe()` to handle "safe" HTTP preference
|
* added `Request::preferSafeContent()` and `Response::setContentSafe()` to handle "safe" HTTP preference
|
||||||
according to [RFC 8674](https://tools.ietf.org/html/rfc8674)
|
according to [RFC 8674](https://tools.ietf.org/html/rfc8674)
|
||||||
* made the Mime component an optional dependency
|
* made the Mime component an optional dependency
|
||||||
|
* added `MarshallingSessionHandler`, `IdentityMarshaller`
|
||||||
|
|
||||||
5.0.0
|
5.0.0
|
||||||
-----
|
-----
|
||||||
|
|
|
@ -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\HttpFoundation\Session\Storage\Handler;
|
||||||
|
|
||||||
|
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
|
||||||
|
*/
|
||||||
|
class IdentityMarshaller implements MarshallerInterface
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function marshall(array $values, ?array &$failed): array
|
||||||
|
{
|
||||||
|
foreach ($values as $key => $value) {
|
||||||
|
if (!\is_string($value)) {
|
||||||
|
throw new \LogicException(sprintf('%s accepts only string as data.', __METHOD__));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $values;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function unmarshall(string $value): string
|
||||||
|
{
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
<?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\HttpFoundation\Session\Storage\Handler;
|
||||||
|
|
||||||
|
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
|
||||||
|
*/
|
||||||
|
class MarshallingSessionHandler implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
|
||||||
|
{
|
||||||
|
private $handler;
|
||||||
|
private $marshaller;
|
||||||
|
|
||||||
|
public function __construct(AbstractSessionHandler $handler, MarshallerInterface $marshaller)
|
||||||
|
{
|
||||||
|
$this->handler = $handler;
|
||||||
|
$this->marshaller = $marshaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function open($savePath, $name)
|
||||||
|
{
|
||||||
|
return $this->handler->open($savePath, $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function close()
|
||||||
|
{
|
||||||
|
return $this->handler->close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function destroy($sessionId)
|
||||||
|
{
|
||||||
|
return $this->handler->destroy($sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function gc($maxlifetime)
|
||||||
|
{
|
||||||
|
return $this->handler->gc($maxlifetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function read($sessionId)
|
||||||
|
{
|
||||||
|
return $this->marshaller->unmarshall($this->handler->read($sessionId));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function write($sessionId, $data)
|
||||||
|
{
|
||||||
|
$failed = [];
|
||||||
|
$marshalledData = $this->marshaller->marshall(['data' => $data], $failed);
|
||||||
|
|
||||||
|
if (isset($failed['data'])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->handler->write($sessionId, $marshalledData['data']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function validateId($sessionId)
|
||||||
|
{
|
||||||
|
return $this->handler->validateId($sessionId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function updateTimestamp($sessionId, $data)
|
||||||
|
{
|
||||||
|
return $this->handler->updateTimestamp($sessionId, $data);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
<?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\HttpFoundation\Tests\Session\Storage\Handler;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\Handler\IdentityMarshaller;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
|
||||||
|
*/
|
||||||
|
class IdentityMarshallerTest extends Testcase
|
||||||
|
{
|
||||||
|
public function testMarshall()
|
||||||
|
{
|
||||||
|
$marshaller = new IdentityMarshaller();
|
||||||
|
$values = ['data' => 'string_data'];
|
||||||
|
$failed = [];
|
||||||
|
|
||||||
|
$this->assertSame($values, $marshaller->marshall($values, $failed));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider invalidMarshallDataProvider
|
||||||
|
*/
|
||||||
|
public function testMarshallInvalidData($values)
|
||||||
|
{
|
||||||
|
$marshaller = new IdentityMarshaller();
|
||||||
|
$failed = [];
|
||||||
|
|
||||||
|
$this->expectException(\LogicException::class);
|
||||||
|
$this->expectExceptionMessage('Symfony\Component\HttpFoundation\Session\Storage\Handler\IdentityMarshaller::marshall accepts only string as data');
|
||||||
|
|
||||||
|
$marshaller->marshall($values, $failed);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUnmarshall()
|
||||||
|
{
|
||||||
|
$marshaller = new IdentityMarshaller();
|
||||||
|
|
||||||
|
$this->assertEquals('data', $marshaller->unmarshall('data'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function invalidMarshallDataProvider(): iterable
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
[['object' => new \stdClass()]],
|
||||||
|
[['foo' => ['bar']]],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,128 @@
|
||||||
|
<?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\HttpFoundation\Tests\Session\Storage\Handler;
|
||||||
|
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler;
|
||||||
|
use Symfony\Component\HttpFoundation\Session\Storage\Handler\MarshallingSessionHandler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Ahmed TAILOULOUTE <ahmed.tailouloute@gmail.com>
|
||||||
|
*/
|
||||||
|
class MarshallingSessionHandlerTest extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var MockObject|\SessionHandlerInterface
|
||||||
|
*/
|
||||||
|
protected $handler;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var MockObject|MarshallerInterface
|
||||||
|
*/
|
||||||
|
protected $marshaller;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
$this->marshaller = $this->getMockBuilder(MarshallerInterface::class)->getMock();
|
||||||
|
$this->handler = $this->getMockBuilder(AbstractSessionHandler::class)->getMock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOpen()
|
||||||
|
{
|
||||||
|
$marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller);
|
||||||
|
|
||||||
|
$this->handler->expects($this->once())->method('open')
|
||||||
|
->with('path', 'name')->willReturn(true);
|
||||||
|
|
||||||
|
$marshallingSessionHandler->open('path', 'name');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testClose()
|
||||||
|
{
|
||||||
|
$marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller);
|
||||||
|
|
||||||
|
$this->handler->expects($this->once())->method('close')->willReturn(true);
|
||||||
|
|
||||||
|
$this->assertTrue($marshallingSessionHandler->close());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDestroy()
|
||||||
|
{
|
||||||
|
$marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller);
|
||||||
|
|
||||||
|
$this->handler->expects($this->once())->method('destroy')
|
||||||
|
->with('session_id')->willReturn(true);
|
||||||
|
|
||||||
|
$marshallingSessionHandler->destroy('session_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testGc()
|
||||||
|
{
|
||||||
|
$marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller);
|
||||||
|
|
||||||
|
$this->handler->expects($this->once())->method('gc')
|
||||||
|
->with('maxlifetime')->willReturn(true);
|
||||||
|
|
||||||
|
$marshallingSessionHandler->gc('maxlifetime');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testRead()
|
||||||
|
{
|
||||||
|
$marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller);
|
||||||
|
|
||||||
|
$this->handler->expects($this->once())->method('read')->with('session_id')
|
||||||
|
->willReturn('data');
|
||||||
|
$this->marshaller->expects($this->once())->method('unmarshall')->with('data')
|
||||||
|
->willReturn('unmarshalled_data')
|
||||||
|
;
|
||||||
|
|
||||||
|
$result = $marshallingSessionHandler->read('session_id');
|
||||||
|
$this->assertEquals('unmarshalled_data', $result);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testWrite()
|
||||||
|
{
|
||||||
|
$marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller);
|
||||||
|
|
||||||
|
$this->marshaller->expects($this->once())->method('marshall')
|
||||||
|
->with(['data' => 'data'], [])
|
||||||
|
->willReturn(['data' => 'marshalled_data']);
|
||||||
|
|
||||||
|
$this->handler->expects($this->once())->method('write')
|
||||||
|
->with('session_id', 'marshalled_data')
|
||||||
|
;
|
||||||
|
|
||||||
|
$marshallingSessionHandler->write('session_id', 'data');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testValidateId()
|
||||||
|
{
|
||||||
|
$marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller);
|
||||||
|
|
||||||
|
$this->handler->expects($this->once())->method('validateId')
|
||||||
|
->with('session_id')->willReturn(true);
|
||||||
|
|
||||||
|
$marshallingSessionHandler->validateId('session_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdateTimestamp()
|
||||||
|
{
|
||||||
|
$marshallingSessionHandler = new MarshallingSessionHandler($this->handler, $this->marshaller);
|
||||||
|
|
||||||
|
$this->handler->expects($this->once())->method('updateTimestamp')
|
||||||
|
->with('session_id', 'data')->willReturn(true);
|
||||||
|
|
||||||
|
$marshallingSessionHandler->updateTimestamp('session_id', 'data');
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,7 @@
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"predis/predis": "~1.0",
|
"predis/predis": "~1.0",
|
||||||
|
"symfony/cache": "^4.4|^5.0",
|
||||||
"symfony/mime": "^4.4|^5.0",
|
"symfony/mime": "^4.4|^5.0",
|
||||||
"symfony/expression-language": "^4.4|^5.0"
|
"symfony/expression-language": "^4.4|^5.0"
|
||||||
},
|
},
|
||||||
|
|
Reference in New Issue