[HttpFoundation] Refactor for DRY code.

Rename ArraySessionStorage to make it clear the session is a mock for testing purposes only.
Has BC class for ArraySessionStorage
Added sanity check when starting the session.
Fixed typos and incorrect php extension test method
session_module_name() also sets session.save_handler, so must use extension_loaded() to check if module exist
or not.
Respect autostart settings.
This commit is contained in:
Drak 2012-01-02 21:17:41 +05:45
parent 9dd4dbed6d
commit f98f9ae8ff
19 changed files with 232 additions and 177 deletions

View File

@ -301,7 +301,7 @@ UPGRADE FROM 2.0 to 2.1
.. note::
You can access optionally use constants in Twig templates using `constant()` e.g.
You can optionally use constants in Twig templates using `constant()` e.g.
`constant('Symfony\Component\HttpFoundation\FlashBag::NOTICE')`.
* Session object
@ -317,7 +317,7 @@ UPGRADE FROM 2.0 to 2.1
and no longer should implement `read()`, `write()`, `remove()` which were removed from the
`SessionStorageInterface`.
Any session storage drive that wants to use custom save handlers should
Any session storage driver that wants to use custom save handlers should
implement `Symfony\Component\HttpFoundation\SessionStorage\SessionSaveHandlerInterface`
### [FrameworkBundle]

View File

@ -13,7 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Templating\Helper;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
use Symfony\Component\HttpFoundation\SessionStorage\MockArraySessionStorage;
use Symfony\Bundle\FrameworkBundle\Templating\Helper\SessionHelper;
use Symfony\Component\HttpFoundation\FlashBag;
use Symfony\Component\HttpFoundation\AttributeBag;
@ -26,7 +26,7 @@ class SessionHelperTest extends \PHPUnit_Framework_TestCase
{
$this->request = new Request();
$session = new Session(new ArraySessionStorage(new AttributeBag(), new FlashBag()));
$session = new Session(new MockArraySessionStorage(new AttributeBag(), new FlashBag()));
$session->set('foobar', 'bar');
$session->addFlash('bar', FlashBag::NOTICE);

View File

@ -15,7 +15,7 @@ use Symfony\Bundle\FrameworkBundle\Templating\PhpEngine;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
use Symfony\Component\HttpFoundation\SessionStorage\MockArraySessionStorage;
use Symfony\Component\Templating\TemplateNameParser;
use Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
@ -66,7 +66,7 @@ class PhpEngineTest extends TestCase
{
$container = new Container();
$request = new Request();
$session = new Session(new ArraySessionStorage(new AttributeBag(), new FlashBag()));
$session = new Session(new MockArraySessionStorage(new AttributeBag(), new FlashBag()));
$request->setSession($session);
$container->set('request', $request);

View File

@ -15,7 +15,7 @@ use Symfony\Bundle\TwigBundle\TwigEngine;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
use Symfony\Component\HttpFoundation\SessionStorage\MockArraySessionStorage;
use Symfony\Component\Templating\TemplateNameParser;
use Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables;
@ -71,7 +71,7 @@ class TwigEngineTest extends TestCase
{
$container = new Container();
$request = new Request();
$session = new Session(new ArraySessionStorage());
$session = new Session(new MockArraySessionStorage());
$request->setSession($session);
$container->set('request', $request);

View File

@ -19,19 +19,6 @@ use Symfony\Component\HttpFoundation\SessionStorage\AttributeInterface;
*
* @author Drak <drak@zikula.org>
*/
interface AttributeBagInterface extends AttributeInterface
interface AttributeBagInterface extends SessionBagInterface, AttributeInterface
{
/**
* Initializes the AttributeBag
*
* @param array $attributes
*/
function initialize(array &$attributes);
/**
* Gets the storage key for this bag.
*
* @return string
*/
function getStorageKey();
}

View File

@ -16,20 +16,13 @@ namespace Symfony\Component\HttpFoundation;
*
* @author Drak <drak@zikula.org>
*/
interface FlashBagInterface
interface FlashBagInterface extends SessionBagInterface
{
const INFO = 'info';
const NOTICE = 'notice';
const WARNING = 'warning';
const ERROR = 'error';
/**
* Initializes the FlashBag.
*
* @param array &$flashes
*/
function initialize(array &$flashes);
/**
* Adds a flash to the stack for a given type.
*
@ -57,7 +50,7 @@ interface FlashBagInterface
function pop($type);
/**
* Pops all flashes from the stacl and clears flashes.
* Pops all flashes from the stack and clears flashes.
*
* @param string $type
*
@ -111,11 +104,4 @@ interface FlashBagInterface
* @return array Empty array or indexed arrays or array if none.
*/
function clearAll();
/**
* Gets the storage key for this bag.
*
* @return string
*/
function getStorageKey();
}

View File

@ -0,0 +1,34 @@
<?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 Bag store.
*
* @author Drak <drak@zikula.org>
*/
interface SessionBagInterface
{
/**
* Initializes the Bag
*
* @param array $array
*/
function initialize(array &$array);
/**
* Gets the storage key for this bag.
*
* @return string
*/
function getStorageKey();
}

View File

@ -15,6 +15,7 @@ use Symfony\Component\HttpFoundation\FlashBag;
use Symfony\Component\HttpFoundation\FlashBagInterface;
use Symfony\Component\HttpFoundation\AttributeBag;
use Symfony\Component\HttpFoundation\AttributeBagInterface;
use Symfony\Component\HttpFoundation\SessionBagInterface;
/**
* This provides a base class for session attribute storage.
@ -36,7 +37,7 @@ abstract class AbstractSessionStorage implements SessionStorageInterface
/**
* @var array
*/
protected $options;
protected $options = array();
/**
* @var boolean
@ -104,7 +105,7 @@ abstract class AbstractSessionStorage implements SessionStorageInterface
*/
public function getFlashes()
{
if (!$this->started) {
if ($this->options['auto_start'] && !$this->started) {
$this->start();
}
@ -116,7 +117,7 @@ abstract class AbstractSessionStorage implements SessionStorageInterface
*/
public function getAttributes()
{
if (!$this->started) {
if ($this->options['auto_start'] && !$this->started) {
$this->start();
}
@ -132,6 +133,10 @@ abstract class AbstractSessionStorage implements SessionStorageInterface
return true;
}
if ($this->options['use_cookies'] && headers_sent()) {
throw new \RuntimeException('Failed to start the session because header have already been sent.');
}
// start the session
if (!session_start()) {
throw new \RuntimeException('Failed to start the session');
@ -228,6 +233,14 @@ abstract class AbstractSessionStorage implements SessionStorageInterface
$this->options['cache_limiter'] = 0;
}
if (!isset($this->options['auto_start'])) {
$this->options['auto_start'] = 0;
}
if (!isset($this->options['use_cookies'])) {
$this->options['use_cookies'] = 1;
}
foreach ($this->options as $key => $value) {
if (in_array($key, array(
'auto_start', 'cookie_domain', 'cookie_httponly',
@ -315,12 +328,20 @@ abstract class AbstractSessionStorage implements SessionStorageInterface
*/
protected function loadSession()
{
$key = $this->attributeBag->getStorageKey();
$_SESSION[$key] = isset($_SESSION[$key]) ? $_SESSION[$key] : array();
$this->attributeBag->initialize($_SESSION[$key]);
$this->link($this->attributeBag, $_SESSION);
$this->link($this->flashBag, $_SESSION);
}
$key = $this->flashBag->getStorageKey();
$_SESSION[$key] = isset($_SESSION[$key]) ? $_SESSION[$key] : array();
$this->flashBag->initialize($_SESSION[$key]);
/**
* Link a bag to the session.
*
* @param SessionBagInterface $bag
* @param array &$array
*/
protected function link(SessionBagInterface $bag, array &$array)
{
$key = $bag->getStorageKey();
$array[$key] = isset($array[$key]) ? $array[$key] : array();
$bag->initialize($array[$key]);
}
}

View File

@ -11,12 +11,14 @@
namespace Symfony\Component\HttpFoundation\SessionStorage;
use Symfony\Component\HttpFoundation\AttributeBagInterface;
use Symfony\Component\HttpFoundation\FlashBagInterface;
/**
* ArraySessionStorage mocks the session for unit tests.
*
* BC Class for MockArraySessionStorage
*
* @deprecated since 2.1.0
* @see MockArraySessionStorage
*
* No PHP session is actually started since a session can be initialized
* and shutdown only once per PHP execution cycle.
*
@ -24,106 +26,7 @@ use Symfony\Component\HttpFoundation\FlashBagInterface;
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
* @author Drak <drak@zikula.org>
*/
class ArraySessionStorage extends AbstractSessionStorage
class ArraySessionStorage extends MockArraySessionStorage
{
/**
* @var string
*/
protected $sessionId;
/**
* @var array
*/
private $attributes = array();
/**
* @var array
*/
private $flashes = array();
/**
* Injects array of attributes to simulate retrieval of existing session.
*
* @param array $array
*/
public function setAttributes(array $array)
{
$this->attributes = $array;
}
/**
* Injects array of flashes to simulate retrieval of existing session.
*
* @param array $array
*/
public function setFlashes(array $array)
{
$this->flashes = $array;
}
/**
* {@inheritdoc}
*/
public function start()
{
if ($this->started && !$this->closed) {
return true;
}
$this->started = true;
$this->attributeBag->initialize($this->attributes);
$this->flashBag->initialize($this->flashes);
$this->sessionId = $this->generateSessionId();
session_id($this->sessionId);
return true;
}
/**
* {@inheritdoc}
*/
public function regenerate($destroy = false)
{
if (!$this->started) {
$this->start();
}
$this->sessionId = $this->generateSessionId();
session_id($this->sessionId);
return true;
}
/**
* {@inheritdoc}
*/
public function getId()
{
if (!$this->started) {
return '';
}
return $this->sessionId;
}
/**
* {@inheritdoc}
*/
public function save()
{
// nothing to do since we don't persist the session data
$this->closed = false;
}
/**
* Generates a session ID.
*
* @return string
*/
protected function generateSessionId()
{
return sha1(uniqid(mt_rand(), true));
}
}

View File

@ -0,0 +1,129 @@
<?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\SessionStorage;
use Symfony\Component\HttpFoundation\AttributeBagInterface;
use Symfony\Component\HttpFoundation\FlashBagInterface;
/**
* MockArraySessionStorage mocks the session for unit tests.
*
* No PHP session is actually started since a session can be initialized
* and shutdown only once per PHP execution cycle.
*
* When doing functional testing, you should use MockFileSessionStorage instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
* @author Drak <drak@zikula.org>
*/
class MockArraySessionStorage extends AbstractSessionStorage
{
/**
* @var string
*/
protected $sessionId;
/**
* @var array
*/
private $attributes = array();
/**
* @var array
*/
private $flashes = array();
/**
* Injects array of attributes to simulate retrieval of existing session.
*
* @param array $array
*/
public function setAttributes(array $array)
{
$this->attributes = $array;
}
/**
* Injects array of flashes to simulate retrieval of existing session.
*
* @param array $array
*/
public function setFlashes(array $array)
{
$this->flashes = $array;
}
/**
* {@inheritdoc}
*/
public function start()
{
if ($this->started && !$this->closed) {
return true;
}
$this->started = true;
$this->attributeBag->initialize($this->attributes);
$this->flashBag->initialize($this->flashes);
$this->sessionId = $this->generateSessionId();
session_id($this->sessionId);
return true;
}
/**
* {@inheritdoc}
*/
public function regenerate($destroy = false)
{
if ($this->options['auto_start'] && !$this->started) {
$this->start();
}
$this->sessionId = $this->generateSessionId();
session_id($this->sessionId);
return true;
}
/**
* {@inheritdoc}
*/
public function getId()
{
if (!$this->started) {
return '';
}
return $this->sessionId;
}
/**
* {@inheritdoc}
*/
public function save()
{
// nothing to do since we don't persist the session data
$this->closed = false;
}
/**
* Generates a session ID.
*
* @return string
*/
protected function generateSessionId()
{
return sha1(uniqid(mt_rand(), true));
}
}

View File

@ -23,7 +23,7 @@ use Symfony\Component\HttpFoundation\FlashBagInterface;
*
* @author Drak <drak@zikula.org>
*/
class MockFileSessionStorage extends ArraySessionStorage
class MockFileSessionStorage extends MockArraySessionStorage
{
/**
* @var array
@ -141,13 +141,8 @@ class MockFileSessionStorage extends ArraySessionStorage
$filePath = $this->getFilePath();
$this->sessionData = is_readable($filePath) && is_file($filePath) ? unserialize(file_get_contents($filePath)) : array();
$key = $this->attributeBag->getStorageKey();
$this->sessionData[$key] = isset($this->sessionData[$key]) ? $this->sessionData[$key] : array();
$this->attributeBag->initialize($this->sessionData[$key]);
$key = $this->flashBag->getStorageKey();
$this->sessionData[$key] = isset($this->sessionData[$key]) ? $this->sessionData[$key] : array();
$this->flashBag->initialize($this->sessionData[$key]);
$this->link($this->attributeBag, $this->sessionData);
$this->link($this->flashBag, $this->sessionData);
}
}

View File

@ -58,7 +58,7 @@ class NativeFileSessionStorage extends AbstractSessionStorage
*/
protected function registerSaveHandlers()
{
ini_set('session.save_handlers', 'files');
ini_set('session.save_handler', 'files');
ini_set('session.save_path', $this->savePath);
}
}

View File

@ -40,7 +40,7 @@ class NativeMemcacheSessionStorage extends AbstractSessionStorage
*/
public function __construct($savePath = 'tcp://127.0.0.1:11211?persistent=0', array $options = array(), AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null)
{
if (!session_module_name('memcache')) {
if (!extension_loaded('memcache')) {
throw new \RuntimeException('PHP does not have "memcache" session module registered');
}
@ -53,7 +53,7 @@ class NativeMemcacheSessionStorage extends AbstractSessionStorage
*/
protected function registerSaveHandlers()
{
ini_set('session.save_handlers', 'memcache');
ini_set('session.save_handler', 'memcache');
ini_set('session.save_path', $this->savePath);
}

View File

@ -40,7 +40,7 @@ class NativeMemcachedSessionStorage extends AbstractSessionStorage
*/
public function __construct($savePath = '127.0.0.1:11211', array $options = array(), AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null)
{
if (!session_module_name('memcached')) {
if (!extension_loaded('memcached')) {
throw new \RuntimeException('PHP does not have "memcached" session module registered');
}
@ -53,7 +53,7 @@ class NativeMemcachedSessionStorage extends AbstractSessionStorage
*/
protected function registerSaveHandlers()
{
ini_set('session.save_handlers', 'memcached');
ini_set('session.save_handler', 'memcached');
ini_set('session.save_path', $this->savePath);
}

View File

@ -40,7 +40,7 @@ class NativeSqliteSessionStorage extends AbstractSessionStorage
*/
public function __construct($dbPath, array $options = array(), AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null)
{
if (!session_module_name('sqlite')) {
if (!extension_loaded('sqlite')) {
throw new \RuntimeException('PHP does not have "sqlite" session module registered');
}
@ -53,7 +53,7 @@ class NativeSqliteSessionStorage extends AbstractSessionStorage
*/
protected function registerSaveHandlers()
{
ini_set('session.save_handlers', 'sqlite');
ini_set('session.save_handler', 'sqlite');
ini_set('session.save_path', $this->dbPath);
}
}

View File

@ -12,7 +12,7 @@
namespace Symfony\Tests\Component\HttpFoundation;
use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
use Symfony\Component\HttpFoundation\SessionStorage\MockArraySessionStorage;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\FlashBag;
@ -848,7 +848,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$request = new Request;
$this->assertFalse($request->hasSession());
$request->setSession(new Session(new ArraySessionStorage(new AttributeBag(), new FlashBag())));
$request->setSession(new Session(new MockArraySessionStorage(new AttributeBag(), new FlashBag())));
$this->assertTrue($request->hasSession());
}
@ -859,7 +859,7 @@ class RequestTest extends \PHPUnit_Framework_TestCase
$this->assertFalse($request->hasPreviousSession());
$request->cookies->set(session_name(), 'foo');
$this->assertFalse($request->hasPreviousSession());
$request->setSession(new Session(new ArraySessionStorage(new AttributeBag(), new FlashBag())));
$request->setSession(new Session(new MockArraySessionStorage(new AttributeBag(), new FlashBag())));
$this->assertTrue($request->hasPreviousSession());
}

View File

@ -2,20 +2,20 @@
namespace Symfony\Tests\Component\HttpFoundation\SessionStorage;
use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
use Symfony\Component\HttpFoundation\SessionStorage\MockArraySessionStorage;
use Symfony\Component\HttpFoundation\AttributeBag;
use Symfony\Component\HttpFoundation\FlashBag;
/**
* Test class for ArraySessionStorage.
* Test class for MockArraySessionStorage.
*
* @author Drak <drak@zikula.org>
*/
class ArraySessionStorageTest extends \PHPUnit_Framework_TestCase
class MockArraySessionStorageTest extends \PHPUnit_Framework_TestCase
{
/**
* @var ArraySessionStorage
* @var MockArraySessionStorage
*/
private $storage;
@ -33,7 +33,7 @@ class ArraySessionStorageTest extends \PHPUnit_Framework_TestCase
{
$this->attributes = array('foo' => 'bar');
$this->flashes = array('notice' => 'hello');
$this->storage = new ArraySessionStorage(new AttributeBag(), new FlashBag());
$this->storage = new MockArraySessionStorage(new AttributeBag(), new FlashBag());
$this->storage->setFlashes($this->flashes);
$this->storage->setAttributes($this->attributes);
}

View File

@ -16,7 +16,7 @@ use Symfony\Component\HttpFoundation\FlashBag;
use Symfony\Component\HttpFoundation\FlashBagInterface;
use Symfony\Component\HttpFoundation\AttributeBag;
use Symfony\Component\HttpFoundation\AttributeBagInterface;
use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
use Symfony\Component\HttpFoundation\SessionStorage\MockArraySessionStorage;
/**
* SessionTest
@ -39,7 +39,7 @@ class SessionTest extends \PHPUnit_Framework_TestCase
public function setUp()
{
$this->storage = new ArraySessionStorage(new AttributeBag(), new FlashBag());
$this->storage = new MockArraySessionStorage(new AttributeBag(), new FlashBag());
$this->session = new Session($this->storage);
}

View File

@ -5,7 +5,7 @@ namespace Symfony\Test\Component\Security\Http\Firewall;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session;
use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
use Symfony\Component\HttpFoundation\SessionStorage\MockArraySessionStorage;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
@ -63,7 +63,7 @@ class ContextListenerTest extends \PHPUnit_Framework_TestCase
protected function runSessionOnKernelResponse($newToken, $original = null)
{
$session = new Session(new ArraySessionStorage());
$session = new Session(new MockArraySessionStorage());
if ($original !== null) {
$session->set('_security_session', $original);