[HttpFoundation] Give control over how session start on demand.

This allows control over how the session start on demand works

0: no start on demand when bags are accessed
1: start session if bags are accessed
2: no start on demand when bags are accessed but still return bag contents
This commit is contained in:
Drak 2013-04-06 10:32:48 +01:00
parent a7c9863b3a
commit 8fc2397760
8 changed files with 140 additions and 20 deletions

View File

@ -4,6 +4,7 @@ CHANGELOG
2.3.0 2.3.0
* `UploadedFile::isValid` now returns false if the file was not uploaded via HTTP (in a non-test mode) * `UploadedFile::isValid` now returns false if the file was not uploaded via HTTP (in a non-test mode)
* addded control for session start on demand.
2.2.0 2.2.0
----- -----

View File

@ -63,16 +63,23 @@ class MockArraySessionStorage implements SessionStorageInterface
*/ */
protected $bags; protected $bags;
/**
* @var Boolean
*/
protected $mode;
/** /**
* Constructor. * Constructor.
* *
* @param string $name Session name * @param string $name Session name.
* @param MetadataBag $metaBag MetadataBag instance. * @param MetadataBag $metaBag MetadataBag instance.
* @param integer $mode Session on demand mode.
*/ */
public function __construct($name = 'MOCKSESSID', MetadataBag $metaBag = null) public function __construct($name = 'MOCKSESSID', MetadataBag $metaBag = null, $mode = self::START_ON_DEMAND)
{ {
$this->name = $name; $this->name = $name;
$this->setMetadataBag($metaBag); $this->setMetadataBag($metaBag);
$this->mode = $mode;
} }
/** /**
@ -197,11 +204,13 @@ class MockArraySessionStorage implements SessionStorageInterface
public function getBag($name) public function getBag($name)
{ {
if (!isset($this->bags[$name])) { if (!isset($this->bags[$name])) {
throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name)); throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered', $name));
} }
if (!$this->started) { if (!$this->started && self::START_ON_DEMAND === $this->mode) {
$this->start(); $this->start();
} elseif (!$this->started && self::NO_START_ON_DEMAND_STRICT === $this->mode) {
throw new \RuntimeException('Cannot access session bags because the session has been started');
} }
return $this->bags[$name]; return $this->bags[$name];

View File

@ -29,19 +29,15 @@ class MockFileSessionStorage extends MockArraySessionStorage
*/ */
private $savePath; private $savePath;
/**
* @var array
*/
private $sessionData;
/** /**
* Constructor. * Constructor.
* *
* @param string $savePath Path of directory to save session files. * @param string $savePath Path of directory to save session files.
* @param string $name Session name. * @param string $name Session name.
* @param MetadataBag $metaBag MetadataBag instance. * @param MetadataBag $metaBag MetadataBag instance.
* @param integer $mode Start on demand mode.
*/ */
public function __construct($savePath = null, $name = 'MOCKSESSID', MetadataBag $metaBag = null) public function __construct($savePath = null, $name = 'MOCKSESSID', MetadataBag $metaBag = null, $mode = self::START_ON_DEMAND)
{ {
if (null === $savePath) { if (null === $savePath) {
$savePath = sys_get_temp_dir(); $savePath = sys_get_temp_dir();
@ -53,7 +49,7 @@ class MockFileSessionStorage extends MockArraySessionStorage
$this->savePath = $savePath; $this->savePath = $savePath;
parent::__construct($name, $metaBag); parent::__construct($name, $metaBag, $mode);
} }
/** /**

View File

@ -51,6 +51,16 @@ class NativeSessionStorage implements SessionStorageInterface
*/ */
protected $metadataBag; protected $metadataBag;
/**
* @var Boolean
*/
protected $mode;
/**
* @var Boolean
*/
protected $emulatePhp;
/** /**
* Constructor. * Constructor.
* *
@ -58,8 +68,9 @@ class NativeSessionStorage implements SessionStorageInterface
* want to override this constructor entirely. * want to override this constructor entirely.
* *
* List of options for $options array with their defaults. * List of options for $options array with their defaults.
*
* @see http://php.net/session.configuration for options * @see http://php.net/session.configuration for options
* but we omit 'session.' from the beginning of the keys for convenience. * but we omit 'session.' from the beginning of the keys for convenience.
* *
* ("auto_start", is not supported as it tells PHP to start a session before * ("auto_start", is not supported as it tells PHP to start a session before
* PHP starts to execute user-land code. Setting during runtime has no effect). * PHP starts to execute user-land code. Setting during runtime has no effect).
@ -94,8 +105,9 @@ class NativeSessionStorage implements SessionStorageInterface
* @param array $options Session configuration options. * @param array $options Session configuration options.
* @param object $handler SessionHandlerInterface. * @param object $handler SessionHandlerInterface.
* @param MetadataBag $metaBag MetadataBag. * @param MetadataBag $metaBag MetadataBag.
* @param integer $mode Start on demand mode.
*/ */
public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null) public function __construct(array $options = array(), $handler = null, MetadataBag $metaBag = null, $mode = self::START_ON_DEMAND)
{ {
ini_set('session.cache_limiter', ''); // disable by default because it's managed by HeaderBag (if used) ini_set('session.cache_limiter', ''); // disable by default because it's managed by HeaderBag (if used)
ini_set('session.use_cookies', 1); ini_set('session.use_cookies', 1);
@ -109,6 +121,7 @@ class NativeSessionStorage implements SessionStorageInterface
$this->setMetadataBag($metaBag); $this->setMetadataBag($metaBag);
$this->setOptions($options); $this->setOptions($options);
$this->setSaveHandler($handler); $this->setSaveHandler($handler);
$this->mode = $mode;
} }
/** /**
@ -253,13 +266,13 @@ class NativeSessionStorage implements SessionStorageInterface
public function getBag($name) public function getBag($name)
{ {
if (!isset($this->bags[$name])) { if (!isset($this->bags[$name])) {
throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name)); throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered', $name));
} }
if ($this->saveHandler->isActive() && !$this->started) { if (!$this->started && self::START_ON_DEMAND === $this->mode) {
$this->loadSession();
} elseif (!$this->started) {
$this->start(); $this->start();
} elseif (!$this->started && self::NO_START_ON_DEMAND_STRICT === $this->mode) {
throw new \RuntimeException('Cannot access session bags because the session has been started');
} }
return $this->bags[$name]; return $this->bags[$name];

View File

@ -24,6 +24,22 @@ use Symfony\Component\HttpFoundation\Session\Storage\MetadataBag;
*/ */
interface SessionStorageInterface interface SessionStorageInterface
{ {
/**
* Do not start session on demand and throw exception if attempt
* is make to read or write bag data.
*/
const NO_START_ON_DEMAND_STRICT = 0;
/**
* Start the session on demand when accessing bag data.
*/
const START_ON_DEMAND = 1;
/**
* Do not start session on demand but allow access to session bags.
*/
const NO_START_ON_DEMAND_LAX = 2;
/** /**
* Starts the session. * Starts the session.
* *

View File

@ -97,10 +97,38 @@ class MockArraySessionStorageTest extends \PHPUnit_Framework_TestCase
} }
/** /**
* @expectedException RuntimeException * @expectedException \RuntimeException
*/ */
public function testUnstartedSave() public function testUnstartedSave()
{ {
$this->storage->save(); $this->storage->save();
} }
/**
* @expectedException \RuntimeException
*/
public function testtStartOnDemandException()
{
$storage = new MockArraySessionStorage('MOCKSESSID', null, MockArraySessionStorage::NO_START_ON_DEMAND_STRICT);
$storage->registerBag(new AttributeBag);
$this->assertFalse($storage->isStarted());
$storage->getBag('attributes');
}
public function testStartOnDemandDefaults()
{
$storage = new MockArraySessionStorage('MOCKSESSID');
$storage->registerBag(new AttributeBag);
$storage->getBag('attributes');
$this->assertTrue($storage->isStarted());
}
public function testNoStartOnDemandLax()
{
$storage = new MockArraySessionStorage('MOCKSESSID', null, MockArraySessionStorage::NO_START_ON_DEMAND_LAX);
$storage->registerBag($bag = new AttributeBag);
$bag->set('foo', 'bar');
$storage->getBag('attributes');
$this->assertEquals(array('foo' => 'bar'), $storage->getBag('attributes')->all());
}
} }

View File

@ -28,7 +28,7 @@ class MockFileSessionStorageTest extends \PHPUnit_Framework_TestCase
private $sessionDir; private $sessionDir;
/** /**
* @var FileMockSessionStorage * @var MockFileSessionStorage
*/ */
protected $storage; protected $storage;
@ -107,7 +107,7 @@ class MockFileSessionStorageTest extends \PHPUnit_Framework_TestCase
} }
/** /**
* @expectedException RuntimeException * @expectedException \RuntimeException
*/ */
public function testSaveWithoutStart() public function testSaveWithoutStart()
{ {
@ -123,4 +123,32 @@ class MockFileSessionStorageTest extends \PHPUnit_Framework_TestCase
return $storage; return $storage;
} }
/**
* @expectedException \RuntimeException
*/
public function testtStartOnDemandException()
{
$storage = new MockFileSessionStorage($this->sessionDir, 'MOCKSESSID', null, MockFileSessionStorage::NO_START_ON_DEMAND_STRICT);
$storage->registerBag(new AttributeBag);
$this->assertFalse($storage->isStarted());
$storage->getBag('attributes');
}
public function testStartOnDemandDefaults()
{
$storage = new MockFileSessionStorage($this->sessionDir, 'MOCKSESSID');
$storage->registerBag(new AttributeBag);
$storage->getBag('attributes');
$this->assertTrue($storage->isStarted());
}
public function testNoStartOnDemandLax()
{
$storage = new MockFileSessionStorage($this->sessionDir, 'MOCKSESSID', null, MockFileSessionStorage::NO_START_ON_DEMAND_LAX);
$storage->registerBag($bag = new AttributeBag);
$bag->set('foo', 'bar');
$storage->getBag('attributes');
$this->assertEquals(array('foo' => 'bar'), $storage->getBag('attributes')->all());
}
} }

View File

@ -16,6 +16,7 @@ use Symfony\Component\HttpFoundation\Session\Storage\Handler\NativeFileSessionHa
use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler; use Symfony\Component\HttpFoundation\Session\Storage\Handler\NullSessionHandler;
use Symfony\Component\HttpFoundation\Session\Flash\FlashBag; use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag; use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
use Symfony\Component\HttpFoundation\Tests\Session\Storage\Handler\NativeSessionHandlerTest;
/** /**
* Test class for NativeSessionStorage. * Test class for NativeSessionStorage.
@ -154,4 +155,32 @@ class NativeSessionStorageTest extends \PHPUnit_Framework_TestCase
$storage->setSaveHandler(new NullSessionHandler()); $storage->setSaveHandler(new NullSessionHandler());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler()); $this->assertInstanceOf('Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', $storage->getSaveHandler());
} }
/**
* @expectedException \RuntimeException
*/
public function testtStartOnDemandException()
{
$storage = new NativeSessionStorage(array(), null, null, NativeSessionStorage::NO_START_ON_DEMAND_STRICT);
$storage->registerBag(new AttributeBag);
$this->assertFalse($storage->isStarted());
$storage->getBag('attributes');
}
public function testStartOnDemandDefaults()
{
$storage = new NativeSessionStorage();
$storage->registerBag(new AttributeBag);
$storage->getBag('attributes');
$this->assertTrue($storage->isStarted());
}
public function testNoStartOnDemandLax()
{
$storage = new NativeSessionStorage(array(), null, null, NativeSessionStorage::NO_START_ON_DEMAND_LAX);
$storage->registerBag($bag = new AttributeBag);
$bag->set('foo', 'bar');
$storage->getBag('attributes');
$this->assertEquals(array('foo' => 'bar'), $storage->getBag('attributes')->all());
}
} }