8000 Adding PSR6 session handler · symfony/symfony@ba865f2 · GitHub
[go: up one dir, main page]

Skip to content

Commit ba865f2

Browse files
committed
Adding PSR6 session handler
1 parent e891d55 commit ba865f2

File tree

2 files changed

+255
-0
lines changed

2 files changed

+255
-0
lines changed
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
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\Component\HttpFoundation\Session\Storage\Handler;
13+
14+
use Psr\Cache\CacheItemPoolInterface;
15+
16+
/**
17+
* Session handler that supports a PSR6 cache implementation.
18+
*
19+
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
20+
*/
21+
class Psr6SessionHandler implements \SessionHandlerInterface
22+
{
23+
/**
24+
* @type CacheItemPoolInterface
25+
*/
26+
private $cache;
27+
28+
/**
29+
* @type int Time to live in seconds
30+
*/
31+
private $ttl;
32+
33+
/**
34+
* @type string Key prefix for shared environments.
35+
*/
36+
private $prefix;
37+
38+
/**
39+
* List of available options:
40+
* * prefix: The prefix to use for the cache keys in order to avoid collision
41+
* * ttl: The time to live in seconds
42+
*
43+
* @param CacheItemPoolInterface $cache A Cache instance
44+
* @param array $options An associative array of cache options
45+
*/
46+
public function __construct(CacheItemPoolInterface $cache, array $options = [])
47+
{
48+
$this->cache = $cache;
49+
50+
$this->ttl = isset($options['ttl']) ? (int) $options['ttl'] : 86400;
51+
$this->prefix = isset($options['prefix']) ? $options['prefix'] : 'sfPsr6sess_';
52+
}
53+
54+
/**
55+
* {@inheritdoc}
56+
*/
57+
public function open($savePath, $sessionName)
58+
{
59+
return true;
60+
}
61+
62+
/**
63+
* {@inheritdoc}
64+
*/
65+
public function close()
66+
{
67+
return true;
68+
}
69+
70+
/**
71+
* {@inheritdoc}
72+
*/
73+
public function read($sessionId)
74+
{
75+
$item = $this->getCacheItem($sessionId);
76+
if ($item->isHit()) {
77+
return $item->get();
78+
}
79+
80+
return '';
81+
}
82+
83+
/**
84+
* {@inheritdoc}
85+
*/
86+
public function write($sessionId, $data)
87+
{
88+
$item = $this->getCacheItem($sessionId);
89+
$item->set($data)
90+
->expiresAfter($this->ttl);
91+
92+
return $this->cache->save($item);
93+
}
94+
95+
/**
96+
* {@inheritdoc}
97+
*/
98+
public function destroy($sessionId)
99+
{
100+
return $this->cache->deleteItem($this->prefix.$sessionId);
101+
}
102+
103+
/**
104+
* {@inheritdoc}
105+
*/
106+
public function gc($lifetime)
107+
{
108+
// not required here because cache will auto expire the records anyhow.
109+
return true;
110+
}
111+
112+
/**
113+
* @param string $sessionId
114+
*
115+
* @return \Psr\Cache\CacheItemInterface
116+
*/
117+
private function getCacheItem(string $sessionId)
118+
{
119+
return $this->cache->getItem($this->prefix.$sessionId);
120+
}
121+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
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\Component\HttpFoundation\Tests\Session\Storage\Handler;
13+
14+
use PHPUnit\Framework\TestCase;
15+
use Psr\Cache\CacheItemInterface;
16+
use Psr\Cache\CacheItemPoolInterface;
17+
use Symfony\Component\HttpFoundation\Session\Storage\Handler\Psr6SessionHandler;
18+
19+
/**
20+
* @author Aaron Scherer <aequasi@gmail.com>
21+
*/
22+
class Psr6SessionHandlerTest extends TestCase
23+
{
24+
const TTL = 100;
25+
const PREFIX = 'pre';
26+
27+
/**
28+
* @var Psr6SessionHandler
29+
*/
30+
private $handler;
31+
32+
/**
33+
* @var \PHPUnit_Framework_MockObject_MockObject|CacheItemPoolInterface
34+
*/
35+
private $psr6;
36+
37+
protected function setUp()
38+
{
39+
parent::setUp();
40+
41+
$this->psr6 = $this->getMockBuilder(CacheItemPoolInterface::class)->getMock();
42+
$this->handler = new Psr6SessionHandler($this->psr6, ['prefix' => self::PREFIX, 'ttl' => self::TTL]);
43+
}
44+
45+
public function testOpen()
46+
{
47+
$this->assertTrue($this->handler->open('foo', 'bar'));
48+
}
49+
50+
public function testClose()
51+
{
52+
$this->assertTrue($this->handler->close());
53+
}
54+
55+
public function testGc()
56+
{
57+
$this->assertTrue($this->handler->gc(4711));
58+
}
59+
60+
public function testReadMiss()
61+
{
62+
$item = $this->getItemMock();
63+
$item->expects($this->once())
64+
->method('isHit')
65+
->willReturn(false);
66+
$this->psr6->expects($this->once())
67+
->method('getItem')
68+
->willReturn($item);
69+
70+
$this->assertEquals('', $this->handler->read('foo'));
71+
}
72+
73+
public function testReadHit()
74+
{
75+
$item = $this->getItemMock();
76+
$item->expects($this->once())
77+
->method('isHit')
78+
->willReturn(true);
79+
$item->expects($this->once())
80+
->method('get')
81+
->willReturn('bar');
82+
$this->psr6->expects($this->once())
83+
->method('getItem')
84+
->willReturn($item);
85+
86+
$this->assertEquals('bar', $this->handler->read('foo'));
87+
}
88+
89+
public function testWrite()
90+
{
91+
$item = $this->getItemMock();
92+
93+
$item->expects($this->once())
94+
->method('set')
95+
->with('session value')
96+
->willReturnSelf();
97+
$item->expects($this->once())
98+
->method('expiresAfter')
99+
->with(self::TTL)
100+
->willReturnSelf();
101+
102+
$this->psr6->expects($this->once())
103+
->method('getItem')
104+
->with(self::PREFIX.'foo')
105+
->willReturn($item);
106+
107+
$this->psr6->expects($this->once())
108+
->method('save')
109+
->with($item)
110+
->willReturn(true);
111+
112+
$this->assertTrue($this->handler->write('foo', 'session value'));
113+
}
114+
115+
public function testDestroy()
116+
{
117+
$this->psr6->expects($this->once())
118+
->method('deleteItem')
119+
->with(self::PREFIX.'foo')
120+
->willReturn(true);
121+
122+
$this->assertTrue($this->handler->destroy('foo'));
123+
}
124+
125+
/**
126+
* @return \PHPUnit_Framework_MockObject_MockObject
127+
*/
128+
private function getItemMock(): \PHPUnit_Framework_MockObject_MockObject
129+
{
130+
return $this->getMockBuilder(CacheItemInterface::class)
131+
->setMethods(['isHit', 'getKey', 'get', 'set', 'expiresAt', 'expiresAfter'])
132+
->getMock();
133+
}
134+
}

0 commit comments

Comments
 (0)
0