diff --git a/CHANGELOG-2.1.md b/CHANGELOG-2.1.md
index 35cbb4f96e606..02ff0a5301c1b 100644
--- a/CHANGELOG-2.1.md
+++ b/CHANGELOG-2.1.md
@@ -224,6 +224,34 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
* removed the ContentTypeMimeTypeGuesser class as it is deprecated and never used on PHP 5.3
* added ResponseHeaderBag::makeDisposition() (implements RFC 6266)
* made mimetype to extension conversion configurable
+ * [BC BREAK] Moved all session related classes and interfaces into own namespace, as
+ `Symfony\Component\HttpFoudation\Session` and renamed classes accordingly.
+ * Added `FlashBag`. Flashes expire when retrieved by `get()` or `all()`.
+ This makes the implementation ESI compatible.
+ * Added `AutoExpireFlashBag` (default) to replicate Symfony 2.0.x auto expire behaviour of messages auto expiring
+ after one page page load. Messages must be retrived by `get()` or `all()`.
+ * [BC BREAK] Removed the `close()` method from the Session class
+ * Deprecated the following methods from the Session class: `setFlash()`, `setFlashes()`
+ `getFlash()`, `hasFlash()`, and `removeFlash()`. Use `getFlashBag() instead which returns a `FlashBagInterface`.
+ * `Session->clear()` now only clears session attributes as before it cleared flash messages and
+ attributes. `Session->getFlashBag()->all()` clears flashes now.
+ * Added `Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage` base class for
+ session storage drivers.
+ * Added `Symfony\Component\HttpFoundation\Session\Storage\SessionSaveHandlerInterface` interface
+ which storage drivers should implement after inheriting from
+ `Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage` when writing custom session save handlers.
+ * [BC BREAK] `SessionStorageInterface` methods removed: `write()`, `read()` and `remove()`. Added
+ `getBag()`, `registerBag()`.
+ * Moved attribute storage to `Symfony\Component\HttpFoundation\Attribute\AttributeBagInterface`.
+ * Added `Symfony\Component\HttpFoundation\Attribute\AttributeBag` to replicate attributes storage
+ behaviour from 2.0.x (default).
+ * Added `Symfony\Component\HttpFoundation\Attribute\NamespacedAttributeBag` for namespace session attributes.
+ * Session now implements `Symfony\Component\HttpFoundation\Session\SessionInterface` making
+ implementation customizable and portable.
+ * [BC BREAK] Removed `NativeSessionStorage` and replaced with `NativeFileSessionStorage`.
+ * Added session storage drivers for PHP native Memcache, Memcached and SQLite session save handlers.
+ * Added session storage drivers for custom Memcache, Memcached and Null session save handlers.
+ * Removed `FilesystemSessionStorage`, use `MockFileSessionStorage` for functional testing instead.
### HttpKernel
diff --git a/UPGRADE-2.1.md b/UPGRADE-2.1.md
index b94b511d79814..862806138b261 100644
--- a/UPGRADE-2.1.md
+++ b/UPGRADE-2.1.md
@@ -1,6 +1,8 @@
UPGRADE FROM 2.0 to 2.1
=======================
+### General
+
* assets_base_urls and base_urls merging strategy has changed
Unlike most configuration blocks, successive values for
@@ -11,6 +13,8 @@ UPGRADE FROM 2.0 to 2.1
and/or share a common base configuration (i.e. ``config.yml``), merging
could yield a set of base URL's for multiple environments.
+### [HttpFoundation]
+
* moved management of the locale from the Session class to the Request class
Configuring the default locale:
@@ -28,17 +32,20 @@ UPGRADE FROM 2.0 to 2.1
Retrieving the locale from a Twig template:
- Before: `{{ app.request.session.locale }}` or `{{ app.session.locale }}`
+ Before: `{{ app.request.session.locale }}` or `{{ app.session.locale }}`
+
After: `{{ app.request.locale }}`
Retrieving the locale from a PHP template:
- Before: `$view['session']->getLocale()`
+ Before: `$view['session']->getLocale()`
+
After: `$view['request']->getLocale()`
Retrieving the locale from PHP code:
- Before: `$session->getLocale()`
+ Before: `$session->getLocale()`
+
After: `$request->getLocale()`
* Method `equals` of `Symfony\Component\Security\Core\User\UserInterface` has
@@ -134,7 +141,7 @@ UPGRADE FROM 2.0 to 2.1
* The strategy for generating the HTML attributes "id" and "name"
of choices in a choice field has changed
-
+
Instead of appending the choice value, a generated integer is now appended
by default. Take care if your Javascript relies on that. If you can
guarantee that your choice values only contain ASCII letters, digits,
@@ -144,7 +151,7 @@ UPGRADE FROM 2.0 to 2.1
* The strategy for generating the HTML attributes "value" of choices in a
choice field has changed
-
+
Instead of using the choice value, a generated integer is now stored.
Again, take care if your Javascript reads this value. If your choice field
is a non-expanded single-choice field, or if the choices are guaranteed not
@@ -248,3 +255,63 @@ UPGRADE FROM 2.0 to 2.1
{
return isset($options['widget']) && 'single_text' === $options['widget'] ? 'text' : 'choice';
}
+
+* Flash Messages now returns and array based on type (the old method are still available but deprecated)
+
+ Before (PHP):
+
+ hasFlash('notice')): ?>
+
+ getFlash('notice') ?>
+
+
+
+ After (PHP):
+
+ getFlashBag()->has('notice')): ?>
+
+ getFlashBag()->get('notice') ?>
+
+
+
+ If you wanted to process all flash types you could also make use of the `getFlashBag()->all()` API:
+
+ getFlashBag()->all() as $type => $flash): ?>
+
+
+
+
+
+ Before (Twig):
+
+ {% if app.session.hasFlash('notice') %}
+
+ {{ app.session.flash('notice') }}
+
+ {% endif %}
+
+ After (Twig):
+
+ {% if app.session.flashes.has('notice') %}
+
+ {{ app.session.flashes.get('notice') }}
+
+ {% endif %}
+
+ Again you can process all flash messages in one go with
+
+ {% for type, flashMessage in app.session.flashes.all() %}
+
+ {{ flashMessage }}
+
+ {% endforeach %}
+
+* Session storage drivers
+
+ Session storage drivers should inherit from
+ `Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage`
+ and no longer should implement `read()`, `write()`, `remove()` which were removed from the
+ `SessionStorageInterface`.
+
+ Any session storage driver that wants to use custom save handlers should
+ implement `Symfony\Component\HttpFoundation\Session\Storage\SaveHandlerInterface`
diff --git a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorage.php b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorage.php
index 6fa324f85e5ec..cda9dd2a0ad5f 100644
--- a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorage.php
+++ b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorage.php
@@ -3,7 +3,8 @@
namespace Symfony\Bridge\Doctrine\HttpFoundation;
use Doctrine\DBAL\Platforms\MySqlPlatform;
-use Symfony\Component\HttpFoundation\SessionStorage\NativeSessionStorage;
+use Symfony\Component\HttpFoundation\Session\Storage\AbstractSessionStorage;
+use Symfony\Component\HttpFoundation\Session\Storage\SessionSaveHandlerInterface;
use Doctrine\DBAL\Driver\Connection;
/**
@@ -12,39 +13,30 @@
* @author Fabien Potencier
* @author Johannes M. Schmitt
*/
-class DbalSessionStorage extends NativeSessionStorage
+class DbalSessionStorage extends AbstractSessionStorage implements SessionSaveHandlerInterface
{
+ /**
+ * @var Connection
+ */
private $con;
+
+ /**
+ * @var string
+ */
private $tableName;
+ /**
+ *
+ * @param Connection $con An instance of Connection.
+ * @param string $tableName Table name.
+ * @param array $options Session configuration options
+ */
public function __construct(Connection $con, $tableName = 'sessions', array $options = array())
{
- parent::__construct($options);
-
$this->con = $con;
$this->tableName = $tableName;
- }
- /**
- * Starts the session.
- */
- public function start()
- {
- if (self::$sessionStarted) {
- return;
- }
-
- // use this object as the session handler
- session_set_save_handler(
- array($this, 'sessionOpen'),
- array($this, 'sessionClose'),
- array($this, 'sessionRead'),
- array($this, 'sessionWrite'),
- array($this, 'sessionDestroy'),
- array($this, 'sessionGC')
- );
-
- parent::start();
+ parent::__construct($options);
}
/**
@@ -55,7 +47,7 @@ public function start()
*
* @return Boolean true, if the session was opened, otherwise an exception is thrown
*/
- public function sessionOpen($path = null, $name = null)
+ public function openSession($path = null, $name = null)
{
return true;
}
@@ -65,7 +57,7 @@ public function sessionOpen($path = null, $name = null)
*
* @return Boolean true, if the session was closed, otherwise false
*/
- public function sessionClose()
+ public function closeSession()
{
// do nothing
return true;
@@ -80,7 +72,7 @@ public function sessionClose()
*
* @throws \RuntimeException If the session cannot be destroyed
*/
- public function sessionDestroy($id)
+ public function destroySession($id)
{
try {
$this->con->executeQuery("DELETE FROM {$this->tableName} WHERE sess_id = :id", array(
@@ -102,7 +94,7 @@ public function sessionDestroy($id)
*
* @throws \RuntimeException If any old sessions cannot be cleaned
*/
- public function sessionGC($lifetime)
+ public function gcSession($lifetime)
{
try {
$this->con->executeQuery("DELETE FROM {$this->tableName} WHERE sess_time < :time", array(
@@ -124,7 +116,7 @@ public function sessionGC($lifetime)
*
* @throws \RuntimeException If the session cannot be read
*/
- public function sessionRead($id)
+ public function readSession($id)
{
try {
$data = $this->con->executeQuery("SELECT sess_data FROM {$this->tableName} WHERE sess_id = :id", array(
@@ -140,7 +132,7 @@ public function sessionRead($id)
return '';
} catch (\PDOException $e) {
- throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
+ throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e);
}
}
@@ -154,7 +146,7 @@ public function sessionRead($id)
*
* @throws \RuntimeException If the session data cannot be written
*/
- public function sessionWrite($id, $data)
+ public function writeSession($id, $data)
{
$platform = $this->con->getDatabasePlatform();
@@ -181,7 +173,7 @@ public function sessionWrite($id, $data)
$this->createNewSession($id, $data);
}
} catch (\PDOException $e) {
- throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
+ throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
}
return true;
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 5195ff1c2fc8c..6738eb3e4ad05 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -167,7 +167,7 @@ private function addSessionSection(ArrayNodeDefinition $rootNode)
->canBeUnset()
->children()
->booleanNode('auto_start')->defaultFalse()->end()
- ->scalarNode('storage_id')->defaultValue('session.storage.native')->end()
+ ->scalarNode('storage_id')->defaultValue('session.storage.native_file')->end()
->scalarNode('name')->end()
->scalarNode('lifetime')->end()
->scalarNode('path')->end()
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 2e80aea918448..d635a7f59897a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -301,7 +301,7 @@ private function registerSessionConfiguration(array $config, ContainerBuilder $c
$this->addClassesToCompile(array(
'Symfony\\Bundle\\FrameworkBundle\\EventListener\\SessionListener',
- 'Symfony\\Component\\HttpFoundation\\SessionStorage\\SessionStorageInterface',
+ 'Symfony\\Component\\HttpFoundation\\Session\\Storage\\SessionStorageInterface',
$container->getDefinition('session')->getClass(),
));
diff --git a/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php b/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php
index 7d6ac49a069c2..d335758b70662 100644
--- a/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php
+++ b/src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php
@@ -69,7 +69,6 @@ public function onKernelResponse(FilterResponseEvent $event)
if ($session = $event->getRequest()->getSession()) {
$session->save();
- $session->close();
$params = session_get_cookie_params();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml
index c3c2eba0c5605..31d374aa6b22c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml
@@ -5,22 +5,31 @@
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
- Symfony\Component\HttpFoundation\Session
- Symfony\Component\HttpFoundation\SessionStorage\NativeSessionStorage
- Symfony\Component\HttpFoundation\SessionStorage\FilesystemSessionStorage
+ Symfony\Component\HttpFoundation\Session\Session
+ Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag
+ Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag
+ Symfony\Component\HttpFoundation\Session\Storage\NativeFileSessionStorage
+ Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage
Symfony\Bundle\FrameworkBundle\EventListener\SessionListener
+
+
-
+
+
+
+
+
+ %kernel.cache_dir%/sessions
%session.storage.options%
-
+
%kernel.cache_dir%/sessions
%session.storage.options%
@@ -29,5 +38,9 @@
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/GlobalVariables.php b/src/Symfony/Bundle/FrameworkBundle/Templating/GlobalVariables.php
index 08d32c86cfc7c..f77ca1243616f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Templating/GlobalVariables.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Templating/GlobalVariables.php
@@ -79,7 +79,7 @@ public function getRequest()
/**
* Returns the current session.
*
- * @return Symfony\Component\HttpFoundation\Session|void The session
+ * @return Symfony\Component\HttpFoundation\Session\Session|void The session
*/
public function getSession()
{
diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/SessionHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/SessionHelper.php
index 041d9ddff9918..c6628172f2eb0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/SessionHelper.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/SessionHelper.php
@@ -48,17 +48,17 @@ public function get($name, $default = null)
public function getFlash($name, $default = null)
{
- return $this->session->getFlash($name, $default);
+ return $this->session->getFlashBag()->get($name);
}
public function getFlashes()
{
- return $this->session->getFlashes();
+ return $this->session->getFlashBag()->all();
}
public function hasFlash($name)
{
- return $this->session->hasFlash($name);
+ return $this->session->getFlashBag()->has($name);
}
/**
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php
index 01361f2280e97..3ab6488493024 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php
@@ -20,7 +20,7 @@
),
'session' => array(
'auto_start' => true,
- 'storage_id' => 'session.storage.native',
+ 'storage_id' => 'session.storage.native_file',
'name' => '_SYMFONY',
'lifetime' => 86400,
'path' => '/',
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml
index 2d6a06047e68d..e46a476a96910 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml
@@ -12,7 +12,7 @@
-
+
loader.foo
loader.bar
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml
index 3c7db0ee49dc6..126baf2d4e90b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml
@@ -14,7 +14,7 @@ framework:
type: xml
session:
auto_start: true
- storage_id: session.storage.native
+ storage_id: session.storage.native_file
name: _SYMFONY
lifetime: 86400
path: /
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 3da5483944193..6aa952e3a6962 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -78,7 +78,7 @@ public function testSession()
$this->assertTrue($container->hasDefinition('session'), '->registerSessionConfiguration() loads session.xml');
$this->assertEquals('fr', $container->getParameter('kernel.default_locale'));
$this->assertTrue($container->getDefinition('session_listener')->getArgument(1));
- $this->assertEquals('session.storage.native', (string) $container->getAlias('session.storage'));
+ $this->assertEquals('session.storage.native_file', (string) $container->getAlias('session.storage'));
$options = $container->getParameter('session.storage.options');
$this->assertEquals('_SYMFONY', $options['name']);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php
index 7c656ba7e0bc9..fe551ba360aa7 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php
@@ -94,7 +94,7 @@ private function sessionMustBeSaved()
private function getSession()
{
- return $this->getMockBuilder('Symfony\Component\HttpFoundation\Session')
+ return $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session')
->disableOriginalConstructor()
->getMock();
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php
index e77f1f126657e..b1c4334cdee4b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php
@@ -51,7 +51,7 @@ public function setFlashAction($message)
{
$request = $this->container->get('request');
$session = $request->getSession();
- $session->setFlash('notice', $message);
+ $session->getFlashBag()->set('notice', $message);
return new RedirectResponse($this->container->get('router')->generate('session_showflash'));
}
@@ -61,8 +61,8 @@ public function showFlashAction()
$request = $this->container->get('request');
$session = $request->getSession();
- if ($session->hasFlash('notice')) {
- $output = $session->getFlash('notice');
+ if ($session->getFlashBag()->has('notice')) {
+ $output = $session->getFlashBag()->get('notice');
} else {
$output = 'No flash was set.';
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/config/framework.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/config/framework.yml
index 18ed6f4d87199..0cc6b74d30cac 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/config/framework.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/config/framework.yml
@@ -10,7 +10,7 @@ framework:
default_locale: en
session:
auto_start: true
- storage_id: session.storage.filesystem
+ storage_id: session.storage.mock_file
services:
logger: { class: Symfony\Component\HttpKernel\Log\NullLogger }
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/SessionHelperTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/SessionHelperTest.php
index ee400cd7dc135..ce8c91b1735ea 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/SessionHelperTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/SessionHelperTest.php
@@ -12,8 +12,8 @@
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\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Bundle\FrameworkBundle\Templating\Helper\SessionHelper;
class SessionHelperTest extends \PHPUnit_Framework_TestCase
@@ -24,9 +24,9 @@ public function setUp()
{
$this->request = new Request();
- $session = new Session(new ArraySessionStorage());
+ $session = new Session(new MockArraySessionStorage());
$session->set('foobar', 'bar');
- $session->setFlash('foo', 'bar');
+ $session->getFlashBag()->set('notice', 'bar');
$this->request->setSession($session);
}
@@ -40,14 +40,15 @@ public function testFlash()
{
$helper = new SessionHelper($this->request);
- $this->assertTrue($helper->hasFlash('foo'));
+ $this->assertTrue($helper->hasFlash('notice'));
- $this->assertEquals('bar', $helper->getFlash('foo'));
- $this->assertEquals('foo', $helper->getFlash('bar', 'foo'));
-
- $this->assertNull($helper->getFlash('foobar'));
+ $this->assertEquals('bar', $helper->getFlash('notice'));
+ }
- $this->assertEquals(array('foo' => 'bar'), $helper->getFlashes());
+ public function testGetFlashes()
+ {
+ $helper = new SessionHelper($this->request);
+ $this->assertEquals(array('notice' => 'bar'), $helper->getFlashes());
}
public function testGet()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/PhpEngineTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/PhpEngineTest.php
index cefc38b0efa59..476b398e61b13 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/PhpEngineTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/PhpEngineTest.php
@@ -14,8 +14,8 @@
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\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\Templating\TemplateNameParser;
use Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables;
use Symfony\Bundle\FrameworkBundle\Tests\TestCase;
@@ -64,7 +64,7 @@ protected function getContainer()
{
$container = new Container();
$request = new Request();
- $session = new Session(new ArraySessionStorage());
+ $session = new Session(new MockArraySessionStorage());
$request->setSession($session);
$container->set('request', $request);
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml
index 18ed6f4d87199..0cc6b74d30cac 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml
@@ -10,7 +10,7 @@ framework:
default_locale: en
session:
auto_start: true
- storage_id: session.storage.filesystem
+ storage_id: session.storage.mock_file
services:
logger: { class: Symfony\Component\HttpKernel\Log\NullLogger }
diff --git a/src/Symfony/Bundle/TwigBundle/Tests/TwigEngineTest.php b/src/Symfony/Bundle/TwigBundle/Tests/TwigEngineTest.php
index 77b79dd545fb5..f15ef3f94564a 100644
--- a/src/Symfony/Bundle/TwigBundle/Tests/TwigEngineTest.php
+++ b/src/Symfony/Bundle/TwigBundle/Tests/TwigEngineTest.php
@@ -14,8 +14,8 @@
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\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\Templating\TemplateNameParser;
use Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables;
@@ -71,7 +71,7 @@ protected function getContainer()
{
$container = new Container();
$request = new Request();
- $session = new Session(new ArraySessionStorage());
+ $session = new Session(new MockArraySessionStorage());
$request->setSession($session);
$container->set('request', $request);
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
index d6235025d0013..491ca0b6ea5ec 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
@@ -15,6 +15,7 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag;
/**
* ProfilerController.
@@ -146,9 +147,9 @@ public function toolbarAction($token, $position = null)
{
$request = $this->container->get('request');
- if (null !== $session = $request->getSession()) {
- // keep current flashes for one more request
- $session->setFlashes($session->getFlashes());
+ if (null !== $session = $request->getSession() && $session->getFlashBag() instanceof AutoExpireFlashBag) {
+ // keep current flashes for one more request if using AutoExpireFlashBag
+ $session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
}
if (null === $token) {
diff --git a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
index a1b6d31a7c764..b9418e6b2a4db 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
@@ -15,6 +15,7 @@
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Bundle\TwigBundle\TwigEngine;
+use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag;
/**
* WebDebugToolbarListener injects the Web Debug Toolbar.
@@ -70,9 +71,10 @@ public function onKernelResponse(FilterResponseEvent $event)
}
if ($response->headers->has('X-Debug-Token') && $response->isRedirect() && $this->interceptRedirects) {
- if (null !== $session = $request->getSession()) {
- // keep current flashes for one more request
- $session->setFlashes($session->getFlashes());
+ $session = $request->getSession();
+ if ($session->getFlashBag() instanceof AutoExpireFlashBag) {
+ // keep current flashes for one more request if using AutoExpireFlashBag
+ $session->getFlashBag()->setAll($session->getFlashBag()->peekAll());
}
$response->setContent($this->templating->render('WebProfilerBundle:Profiler:toolbar_redirect.html.twig', array('location' => $response->headers->get('Location'))));
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
index b6986176e8a06..ce75b593dc6d5 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
+++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
@@ -177,7 +177,7 @@ public function testToolbarIsNotInjectedOnNonHtmlRequests()
protected function getRequestMock($isXmlHttpRequest = false, $requestFormat = 'html')
{
- $session = $this->getMock('Symfony\Component\HttpFoundation\Session', array(), array(), '', false);
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array(), array(), '', false);
$request = $this->getMock(
'Symfony\Component\HttpFoundation\Request',
array('getSession', 'isXmlHttpRequest', 'getRequestFormat'),
diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php
index d52fcac4b38a0..5174412a97f01 100644
--- a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php
+++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php
@@ -11,7 +11,7 @@
namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
-use Symfony\Component\HttpFoundation\Session;
+use Symfony\Component\HttpFoundation\Session\Session;
/**
* This provider uses a Symfony2 Session object to retrieve the user's
diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php
index fc336109067b0..beab652a423c6 100644
--- a/src/Symfony/Component/HttpFoundation/Request.php
+++ b/src/Symfony/Component/HttpFoundation/Request.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\HttpFoundation;
+use Symfony\Component\HttpFoundation\Session\SessionInterface;
+
/**
* Request represents an HTTP request.
*
@@ -122,7 +124,7 @@ class Request
protected $format;
/**
- * @var \Symfony\Component\HttpFoundation\Session
+ * @var \Symfony\Component\HttpFoundation\Session\SessionInterface
*/
protected $session;
@@ -466,7 +468,7 @@ public function get($key, $default = null, $deep = false)
/**
* Gets the Session.
*
- * @return Session|null The session
+ * @return SessionInterface|null The session
*
* @api
*/
@@ -504,11 +506,11 @@ public function hasSession()
/**
* Sets the Session.
*
- * @param Session $session The Session
+ * @param SessionInterface $session The Session
*
* @api
*/
- public function setSession(Session $session)
+ public function setSession(SessionInterface $session)
{
$this->session = $session;
}
diff --git a/src/Symfony/Component/HttpFoundation/Session.php b/src/Symfony/Component/HttpFoundation/Session.php
deleted file mode 100644
index 721a6c7240b99..0000000000000
--- a/src/Symfony/Component/HttpFoundation/Session.php
+++ /dev/null
@@ -1,358 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\HttpFoundation;
-
-use Symfony\Component\HttpFoundation\SessionStorage\SessionStorageInterface;
-
-/**
- * Session.
- *
- * @author Fabien Potencier
- *
- * @api
- */
-class Session implements \Serializable
-{
- protected $storage;
- protected $started;
- protected $attributes;
- protected $flashes;
- protected $oldFlashes;
- protected $closed;
-
- /**
- * Constructor.
- *
- * @param SessionStorageInterface $storage A SessionStorageInterface instance
- */
- public function __construct(SessionStorageInterface $storage)
- {
- $this->storage = $storage;
- $this->flashes = array();
- $this->oldFlashes = array();
- $this->attributes = array();
- $this->started = false;
- $this->closed = false;
- }
-
- /**
- * Starts the session storage.
- *
- * @api
- */
- public function start()
- {
- if (true === $this->started) {
- return;
- }
-
- $this->storage->start();
-
- $attributes = $this->storage->read('_symfony2');
-
- if (isset($attributes['attributes'])) {
- $this->attributes = $attributes['attributes'];
- $this->flashes = $attributes['flashes'];
-
- // flag current flash messages to be removed at shutdown
- $this->oldFlashes = $this->flashes;
- }
-
- $this->started = true;
- }
-
- /**
- * Checks if an attribute is defined.
- *
- * @param string $name The attribute name
- *
- * @return Boolean true if the attribute is defined, false otherwise
- *
- * @api
- */
- public function has($name)
- {
- return array_key_exists($name, $this->attributes);
- }
-
- /**
- * Returns an attribute.
- *
- * @param string $name The attribute name
- * @param mixed $default The default value
- *
- * @return mixed
- *
- * @api
- */
- public function get($name, $default = null)
- {
- return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
- }
-
- /**
- * Sets an attribute.
- *
- * @param string $name
- * @param mixed $value
- *
- * @api
- */
- public function set($name, $value)
- {
- if (false === $this->started) {
- $this->start();
- }
-
- $this->attributes[$name] = $value;
- }
-
- /**
- * Returns attributes.
- *
- * @return array Attributes
- *
- * @api
- */
- public function all()
- {
- return $this->attributes;
- }
-
- /**
- * Sets attributes.
- *
- * @param array $attributes Attributes
- *
- * @api
- */
- public function replace(array $attributes)
- {
- if (false === $this->started) {
- $this->start();
- }
-
- $this->attributes = $attributes;
- }
-
- /**
- * Removes an attribute.
- *
- * @param string $name
- *
- * @api
- */
- public function remove($name)
- {
- if (false === $this->started) {
- $this->start();
- }
-
- if (array_key_exists($name, $this->attributes)) {
- unset($this->attributes[$name]);
- }
- }
-
- /**
- * Clears all attributes.
- *
- * @api
- */
- public function clear()
- {
- if (false === $this->started) {
- $this->start();
- }
-
- $this->attributes = array();
- $this->flashes = array();
- }
-
- /**
- * Invalidates the current session.
- *
- * @api
- */
- public function invalidate()
- {
- $this->clear();
- $this->storage->regenerate(true);
- }
-
- /**
- * Migrates the current session to a new session id while maintaining all
- * session attributes.
- *
- * @api
- */
- public function migrate()
- {
- $this->storage->regenerate();
- }
-
- /**
- * Returns the session ID
- *
- * @return mixed The session ID
- *
- * @api
- */
- public function getId()
- {
- if (false === $this->started) {
- $this->start();
- }
-
- return $this->storage->getId();
- }
-
- /**
- * Gets the flash messages.
- *
- * @return array
- */
- public function getFlashes()
- {
- return $this->flashes;
- }
-
- /**
- * Sets the flash messages.
- *
- * @param array $values
- */
- public function setFlashes($values)
- {
- if (false === $this->started) {
- $this->start();
- }
-
- $this->flashes = $values;
- $this->oldFlashes = array();
- }
-
- /**
- * Gets a flash message.
- *
- * @param string $name
- * @param string|null $default
- *
- * @return string
- */
- public function getFlash($name, $default = null)
- {
- return array_key_exists($name, $this->flashes) ? $this->flashes[$name] : $default;
- }
-
- /**
- * Sets a flash message.
- *
- * @param string $name
- * @param string $value
- */
- public function setFlash($name, $value)
- {
- if (false === $this->started) {
- $this->start();
- }
-
- $this->flashes[$name] = $value;
- unset($this->oldFlashes[$name]);
- }
-
- /**
- * Checks whether a flash message exists.
- *
- * @param string $name
- *
- * @return Boolean
- */
- public function hasFlash($name)
- {
- if (false === $this->started) {
- $this->start();
- }
-
- return array_key_exists($name, $this->flashes);
- }
-
- /**
- * Removes a flash message.
- *
- * @param string $name
- */
- public function removeFlash($name)
- {
- if (false === $this->started) {
- $this->start();
- }
-
- unset($this->flashes[$name]);
- }
-
- /**
- * Removes the flash messages.
- */
- public function clearFlashes()
- {
- if (false === $this->started) {
- $this->start();
- }
-
- $this->flashes = array();
- $this->oldFlashes = array();
- }
-
- public function save()
- {
- if (false === $this->started) {
- $this->start();
- }
-
- $this->flashes = array_diff_key($this->flashes, $this->oldFlashes);
-
- $this->storage->write('_symfony2', array(
- 'attributes' => $this->attributes,
- 'flashes' => $this->flashes,
- ));
- }
-
- /**
- * This method should be called when you don't want the session to be saved
- * when the Session object is garbaged collected (useful for instance when
- * you want to simulate the interaction of several users/sessions in a single
- * PHP process).
- */
- public function close()
- {
- $this->closed = true;
- }
-
- public function __destruct()
- {
- if (true === $this->started && !$this->closed) {
- $this->save();
- }
- }
-
- public function serialize()
- {
- return serialize($this->storage);
- }
-
- public function unserialize($serialized)
- {
- $this->storage = unserialize($serialized);
- $this->attributes = array();
- $this->started = false;
- }
-}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php
new file mode 100644
index 0000000000000..2915b03297e41
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php
@@ -0,0 +1,137 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Attribute;
+
+/**
+ * This class relates to session attribute storage
+ */
+class AttributeBag implements AttributeBagInterface
+{
+ private $name = 'attributes';
+
+ /**
+ * @var string
+ */
+ private $storageKey;
+
+ /**
+ * @var array
+ */
+ protected $attributes = array();
+
+ /**
+ * Constructor.
+ *
+ * @param type $storageKey The key used to store flashes in the session.
+ */
+ public function __construct($storageKey = '_sf2_attributes')
+ {
+ $this->storageKey = $storageKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function initialize(array &$attributes)
+ {
+ $this->attributes = &$attributes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStorageKey()
+ {
+ return $this->storageKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($name)
+ {
+ return array_key_exists($name, $this->attributes);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($name, $default = null)
+ {
+ return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($name, $value)
+ {
+ $this->attributes[$name] = $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function all()
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function replace(array $attributes)
+ {
+ $this->attributes = array();
+ foreach ($attributes as $key => $value) {
+ $this->set($key, $value);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove($name)
+ {
+ $retval = null;
+ if (array_key_exists($name, $this->attributes)) {
+ $retval = $this->attributes[$name];
+ unset($this->attributes[$name]);
+ }
+
+ return $retval;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear()
+ {
+ $return = $this->attributes;
+ $this->attributes = array();
+
+ return $return;
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBagInterface.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBagInterface.php
new file mode 100644
index 0000000000000..af16d642efebb
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBagInterface.php
@@ -0,0 +1,70 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Attribute;
+
+use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
+
+/**
+ * Attributes store.
+ *
+ * @author Drak
+ */
+interface AttributeBagInterface extends SessionBagInterface
+{
+ /**
+ * Checks if an attribute is defined.
+ *
+ * @param string $name The attribute name
+ *
+ * @return Boolean true if the attribute is defined, false otherwise
+ */
+ function has($name);
+
+ /**
+ * Returns an attribute.
+ *
+ * @param string $name The attribute name
+ * @param mixed $default The default value if not found.
+ *
+ * @return mixed
+ */
+ function get($name, $default = null);
+
+ /**
+ * Sets an attribute.
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ function set($name, $value);
+
+ /**
+ * Returns attributes.
+ *
+ * @return array Attributes
+ */
+ function all();
+
+ /**
+ * Sets attributes.
+ *
+ * @param array $attributes Attributes
+ */
+ function replace(array $attributes);
+
+ /**
+ * Removes an attribute.
+ *
+ * @param string $name
+ */
+ function remove($name);
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php
new file mode 100644
index 0000000000000..7a324050968d9
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php
@@ -0,0 +1,184 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Attribute;
+
+/**
+ * This class provides structured storage of session attributes using
+ * a name spacing character in the key.
+ *
+ * @author Drak
+ */
+class NamespacedAttributeBag extends AttributeBag
+{
+ /**
+ * Namespace character.
+ *
+ * @var string
+ */
+ private $namespaceCharacter;
+
+ /**
+ * Constructor.
+ *
+ * @param type $storageKey Session storage key.
+ * @param type $namespaceCharacter Namespace character to use in keys.
+ */
+ public function __construct($storageKey = '_sf2_attributes', $namespaceCharacter = '/')
+ {
+ $this->namespaceCharacter = $namespaceCharacter;
+ parent::__construct($storageKey);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($name)
+ {
+ $attributes = $this->resolveAttributePath($name);
+ $name = $this->resolveKey($name);
+
+ return array_key_exists($name, $attributes);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($name, $default = null)
+ {
+ $attributes = $this->resolveAttributePath($name);
+ $name = $this->resolveKey($name);
+
+ return array_key_exists($name, $attributes) ? $attributes[$name] : $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($name, $value)
+ {
+ $attributes = & $this->resolveAttributePath($name, true);
+ $name = $this->resolveKey($name);
+ $attributes[$name] = $value;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function all()
+ {
+ return $this->attributes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function replace(array $attributes)
+ {
+ $this->attributes = array();
+ foreach ($attributes as $key => $value) {
+ $this->set($key, $value);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove($name)
+ {
+ $retval = null;
+ $attributes = & $this->resolveAttributePath($name);
+ $name = $this->resolveKey($name);
+ if (array_key_exists($name, $attributes)) {
+ $retval = $attributes[$name];
+ unset($attributes[$name]);
+ }
+
+ return $retval;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear()
+ {
+ $return = $this->attributes;
+ $this->attributes = array();
+
+ return $return;
+ }
+
+ /**
+ * Resolves a path in attributes property and returns it as a reference.
+ *
+ * This method allows structured namespacing of session attributes.
+ *
+ * @param string $name Key name
+ * @param boolean $writeContext Write context, default false
+ *
+ * @return array
+ */
+ protected function &resolveAttributePath($name, $writeContext = false)
+ {
+ $array = & $this->attributes;
+ $name = (strpos($name, $this->namespaceCharacter) === 0) ? substr($name, 1) : $name;
+
+ // Check if there is anything to do, else return
+ if (!$name) {
+ return $array;
+ }
+
+ $parts = explode($this->namespaceCharacter, $name);
+ if (count($parts) < 2) {
+ if (!$writeContext) {
+ return $array;
+ }
+
+ $array[$parts[0]] = array();
+
+ return $array;
+ }
+
+ unset($parts[count($parts)-1]);
+
+ foreach ($parts as $part) {
+ if (!array_key_exists($part, $array)) {
+ if (!$writeContext) {
+ return $array;
+ }
+
+ $array[$part] = array();
+ }
+
+ $array = & $array[$part];
+ }
+
+ return $array;
+ }
+
+ /**
+ * Resolves the key from the name.
+ *
+ * This is the last part in a dot separated string.
+ *
+ * @param string $name
+ *
+ * @return string
+ */
+ protected function resolveKey($name)
+ {
+ if (strpos($name, $this->namespaceCharacter) !== false) {
+ $name = substr($name, strrpos($name, $this->namespaceCharacter)+1, strlen($name));
+ }
+
+ return $name;
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php
new file mode 100644
index 0000000000000..1c7b9e9d0795c
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php
@@ -0,0 +1,174 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Flash;
+
+/**
+ * AutoExpireFlashBag flash message container.
+ *
+ * @author Drak
+ */
+class AutoExpireFlashBag implements FlashBagInterface
+{
+ private $name = 'flashes';
+
+ /**
+ * Flash messages.
+ *
+ * @var array
+ */
+ private $flashes = array();
+
+ /**
+ * The storage key for flashes in the session
+ *
+ * @var string
+ */
+ private $storageKey;
+
+ /**
+ * Constructor.
+ *
+ * @param type $storageKey The key used to store flashes in the session.
+ */
+ public function __construct($storageKey = '_sf2_flashes')
+ {
+ $this->storageKey = $storageKey;
+ $this->flashes = array('display' => array(), 'new' => array());
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function initialize(array &$flashes)
+ {
+ $this->flashes = &$flashes;
+
+ // The logic: messages from the last request will be stored in new, so we move them to previous
+ // This request we will show what is in 'display'. What is placed into 'new' this time round will
+ // be moved to display next time round.
+ $this->flashes['display'] = array_key_exists('new', $this->flashes) ? $this->flashes['new'] : array();
+ $this->flashes['new'] = array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function peek($type, $default = null)
+ {
+ return $this->has($type) ? $this->flashes['display'][$type] : $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function peekAll()
+ {
+ return array_key_exists('display', $this->flashes) ? (array)$this->flashes['display'] : array();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($type, $default = null)
+ {
+ if (!$this->has($type)) {
+ return $default;
+ }
+
+ $return = null;
+ if (isset($this->flashes['new'][$type])) {
+ unset($this->flashes['new'][$type]);
+ }
+
+ if (isset($this->flashes['display'][$type])) {
+ $return = $this->flashes['display'][$type];
+ unset($this->flashes['display'][$type]);
+ }
+
+ return $return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function all()
+ {
+ $return = $this->flashes['display'];
+ $this->flashes = array('new' => array(), 'display' => array());
+
+ return $return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setAll(array $messages)
+ {
+ $this->flashes['new'] = $messages;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($type, $message)
+ {
+ $this->flashes['new'][$type] = $message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($type)
+ {
+ return array_key_exists($type, $this->flashes['display']);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function keys()
+ {
+ return array_keys($this->flashes['display']);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStorageKey()
+ {
+ return $this->storageKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear()
+ {
+ $return = $this->all();
+ $this->flashes = array('display' => array(), 'new' => array());
+
+ return $return;
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php
new file mode 100644
index 0000000000000..cbb77af03d37f
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php
@@ -0,0 +1,158 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Flash;
+
+/**
+ * FlashBag flash message container.
+ *
+ * @author Drak
+ */
+class FlashBag implements FlashBagInterface
+{
+ private $name = 'flashes';
+
+ /**
+ * Flash messages.
+ *
+ * @var array
+ */
+ private $flashes = array();
+
+ /**
+ * The storage key for flashes in the session
+ *
+ * @var string
+ */
+ private $storageKey;
+
+ /**
+ * Constructor.
+ *
+ * @param type $storageKey The key used to store flashes in the session.
+ */
+ public function __construct($storageKey = '_sf2_flashes')
+ {
+ $this->storageKey = $storageKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function initialize(array &$flashes)
+ {
+ $this->flashes = &$flashes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function peek($type, $default = null)
+ {
+ return $this->has($type) ? $this->flashes[$type] : $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function peekAll()
+ {
+ return $this->flashes;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($type, $default = null)
+ {
+ if (!$this->has($type)) {
+ return $default;
+ }
+
+ $return = $this->flashes[$type];
+
+ unset($this->flashes[$type]);
+
+ return $return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function all()
+ {
+ $return = $this->peekAll();
+ $this->flashes = array();
+
+ return $return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function set($type, $message)
+ {
+ $this->flashes[$type] = $message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function setAll(array $messages)
+ {
+ $this->flashes = $messages;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($type)
+ {
+ return array_key_exists($type, $this->flashes);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function keys()
+ {
+ return array_keys($this->flashes);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStorageKey()
+ {
+ return $this->storageKey;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear()
+ {
+ return $this->all();
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php
new file mode 100644
index 0000000000000..0c45d74bb7fff
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php
@@ -0,0 +1,85 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Flash;
+
+use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
+
+/**
+ * FlashBagInterface.
+ *
+ * @author Drak
+ */
+interface FlashBagInterface extends SessionBagInterface
+{
+ /**
+ * Registers a message for a given type.
+ *
+ * @param string $type
+ * @param string $message
+ */
+ function set($type, $message);
+
+ /**
+ * Gets flash message for a given type.
+ *
+ * @param string $type Message category type.
+ * @param string $default Default value if $type doee not exist.
+ *
+ * @return string
+ */
+ function peek($type, $default = null);
+
+ /**
+ * Gets all flash messages.
+ *
+ * @return array
+ */
+ function peekAll();
+
+ /**
+ * Gets and clears flash from the stack.
+ *
+ * @param string $type
+ * @param string $default Default value if $type doee not exist.
+ *
+ * @return string
+ */
+ function get($type, $default = null);
+
+ /**
+ * Gets and clears flashes from the stack.
+ *
+ * @return array
+ */
+ function all();
+
+ /**
+ * Sets all flash messages.
+ */
+ function setAll(array $messages);
+
+ /**
+ * Has flash messages for a given type?
+ *
+ * @param string $type
+ *
+ * @return boolean
+ */
+ function has($type);
+
+ /**
+ * Returns a list of all defined types.
+ *
+ * @return array
+ */
+ function keys();
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php
new file mode 100644
index 0000000000000..468040e3aa532
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Session.php
@@ -0,0 +1,318 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session;
+
+use Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface;
+use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
+use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBagInterface;
+use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
+use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
+use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
+
+/**
+ * Session.
+ *
+ * @author Fabien Potencier
+ * @author Drak
+ *
+ * @api
+ */
+class Session implements SessionInterface
+{
+ /**
+ * Storage driver.
+ *
+ * @var SessionStorageInterface
+ */
+ protected $storage;
+
+ /**
+ * Constructor.
+ *
+ * @param SessionStorageInterface $storage A SessionStorageInterface instance.
+ * @param AttributeBagInterface $attributes An AttributeBagInterface instance, (defaults null for default AttributeBag)
+ * @param FlashBagInterface $flashes A FlashBagInterface instance (defaults null for default FlashBag)
+ */
+ public function __construct(SessionStorageInterface $storage, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null)
+ {
+ $this->storage = $storage;
+ $this->registerBag($attributes ?: new AttributeBag());
+ $this->registerBag($flashes ?: new FlashBag());
+ }
+
+ /**
+ * Starts the session storage.
+ *
+ * @return boolean True if session started.
+ *
+ * @api
+ */
+ public function start()
+ {
+ return $this->storage->start();
+ }
+
+ /**
+ * Checks if an attribute is defined.
+ *
+ * @param string $name The attribute name
+ *
+ * @return Boolean true if the attribute is defined, false otherwise
+ *
+ * @api
+ */
+ public function has($name)
+ {
+ return $this->storage->getBag('attributes')->has($name);
+ }
+
+ /**
+ * Returns an attribute.
+ *
+ * @param string $name The attribute name
+ * @param mixed $default The default value
+ *
+ * @return mixed
+ *
+ * @api
+ */
+ public function get($name, $default = null)
+ {
+ return $this->storage->getBag('attributes')->get($name, $default);
+ }
+
+ /**
+ * Sets an attribute.
+ *
+ * @param string $name
+ * @param mixed $value
+ *
+ * @api
+ */
+ public function set($name, $value)
+ {
+ $this->storage->getBag('attributes')->set($name, $value);
+ }
+
+ /**
+ * Returns attributes.
+ *
+ * @return array Attributes
+ *
+ * @api
+ */
+ public function all()
+ {
+ return $this->storage->getBag('attributes')->all();
+ }
+
+ /**
+ * Sets attributes.
+ *
+ * @param array $attributes Attributes
+ *
+ * @api
+ */
+ public function replace(array $attributes)
+ {
+ $this->storage->getBag('attributes')->replace($attributes);
+ }
+
+ /**
+ * Removes an attribute.
+ *
+ * @param string $name
+ *
+ * @api
+ */
+ public function remove($name)
+ {
+ return $this->storage->getBag('attributes')->remove($name);
+ }
+
+ /**
+ * Clears all attributes.
+ *
+ * @api
+ */
+ public function clear()
+ {
+ $this->storage->getBag('attributes')->clear();
+ }
+
+ /**
+ * Invalidates the current session.
+ *
+ * Clears all session attributes and flashes and regenerates the
+ * session and deletes the old session from persistence.
+ *
+ * @return boolean True if session invalidated, false if error.
+ *
+ * @api
+ */
+ public function invalidate()
+ {
+ $this->storage->clear();
+
+ return $this->storage->regenerate(true);
+ }
+
+ /**
+ * Migrates the current session to a new session id while maintaining all
+ * session attributes.
+ *
+ * @param boolean $destroy Whether to delete the old session or leave it to garbage collection.
+ *
+ * @return boolean True if session migrated, false if error
+ *
+ * @api
+ */
+ public function migrate($destroy = false)
+ {
+ return $this->storage->regenerate($destroy);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function save()
+ {
+ $this->storage->save();
+ }
+
+ /**
+ * Returns the session ID
+ *
+ * @return mixed The session ID
+ *
+ * @api
+ */
+ public function getId()
+ {
+ return $this->storage->getId();
+ }
+
+ /**
+ * Implements the \Serialize interface.
+ *
+ * @return SessionStorageInterface
+ */
+ public function serialize()
+ {
+ return serialize($this->storage);
+ }
+
+ /**
+ * Implements the \Serialize interface.
+ *
+ * @throws \InvalidArgumentException If the passed string does not unserialize to an instance of SessionStorageInterface
+ */
+ public function unserialize($serialized)
+ {
+ $storage = unserialize($serialized);
+ if (!$storage instanceof SessionStorageInterface) {
+ throw new \InvalidArgumentException('Serialized data did not return a valid instance of SessionStorageInterface');
+ }
+
+ $this->storage = $storage;
+ }
+
+ /**
+ * Registers a SessionBagInterface with the sessio.
+ *
+ * @param SessionBagInterface $bag
+ */
+ public function registerBag(SessionBagInterface $bag)
+ {
+ $this->storage->registerBag($bag);
+ }
+
+ /**
+ * Get's a bag instance.
+ *
+ * @param string $name
+ *
+ * @return SessionBagInterface
+ */
+ public function getBag($name)
+ {
+ return $this->storage->getBag($name);
+ }
+
+ /**
+ * Gets the flashbag interface.
+ *
+ * @return FlashBagInterface
+ */
+ public function getFlashBag()
+ {
+ return $this->getBag('flashes');
+ }
+
+ // the following methods are kept for compatibility with Symfony 2.0 (they will be removed for Symfony 2.3)
+
+ /**
+ * @deprecated since 2.1, will be removed from 2.3
+ */
+ public function getFlashes()
+ {
+ return $this->getBag('flashes')->all();
+ }
+
+ /**
+ * @deprecated since 2.1, will be removed from 2.3
+ */
+ public function setFlashes($values)
+ {
+ $this->getBag('flashes')->setAll($values);
+ }
+
+ /**
+ * @deprecated since 2.1, will be removed from 2.3
+ */
+ public function getFlash($name, $default = null)
+ {
+ return $this->getBag('flashes')->get($name, $default);
+ }
+
+ /**
+ * @deprecated since 2.1, will be removed from 2.3
+ */
+ public function setFlash($name, $value)
+ {
+ $this->getBag('flashes')->set($name, $value);
+ }
+
+ /**
+ * @deprecated since 2.1, will be removed from 2.3
+ */
+ public function hasFlash($name)
+ {
+ return $this->getBag('flashes')->has($name);
+ }
+
+ /**
+ * @deprecated since 2.1, will be removed from 2.3
+ */
+ public function removeFlash($name)
+ {
+ $this->getBag('flashes')->get($name);
+ }
+
+ /**
+ * @deprecated since 2.1, will be removed from 2.3
+ */
+ public function clearFlashes()
+ {
+ return $this->getBag('flashes')->clear();
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/SessionBagInterface.php b/src/Symfony/Component/HttpFoundation/Session/SessionBagInterface.php
new file mode 100644
index 0000000000000..50c2d4bd0cb51
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/SessionBagInterface.php
@@ -0,0 +1,48 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session;
+
+/**
+ * Session Bag store.
+ *
+ * @author Drak
+ */
+interface SessionBagInterface
+{
+ /**
+ * Gets this bag's name
+ *
+ * @return string
+ */
+ function getName();
+
+ /**
+ * Initializes the Bag
+ *
+ * @param array $array
+ */
+ function initialize(array &$array);
+
+ /**
+ * Gets the storage key for this bag.
+ *
+ * @return string
+ */
+ function getStorageKey();
+
+ /**
+ * Clears out data from bag.
+ *
+ * @return mixed Whatever data was contained.
+ */
+ function clear();
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php b/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php
new file mode 100644
index 0000000000000..c31da6d165889
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/SessionInterface.php
@@ -0,0 +1,108 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session;
+
+/**
+ * Interface for the session.
+ *
+ * @author Drak
+ */
+interface SessionInterface extends \Serializable
+{
+ /**
+ * Starts the session storage.
+ *
+ * @throws \RuntimeException If session fails to start.
+ */
+ function start();
+
+ /**
+ * Invalidates the current session.
+ *
+ * @return boolean True if session invalidated, false if error.
+ */
+ function invalidate();
+
+ /**
+ * Migrates the current session to a new session id while maintaining all
+ * session attributes.
+ *
+ * @param boolean $destroy Whether to delete the old session or leave it to garbage collection.
+ *
+ * @return boolean True if session migrated, false if error.
+ *
+ * @api
+ */
+ function migrate($destroy = false);
+
+ /**
+ * Force the session to be saved and closed.
+ *
+ * This method is generally not required for real sessions as
+ * the session will be automatically saved at the end of
+ * code execution.
+ */
+ function save();
+
+ /**
+ * Checks if an attribute is defined.
+ *
+ * @param string $name The attribute name
+ *
+ * @return Boolean true if the attribute is defined, false otherwise
+ */
+ function has($name);
+
+ /**
+ * Returns an attribute.
+ *
+ * @param string $name The attribute name
+ * @param mixed $default The default value if not found.
+ *
+ * @return mixed
+ */
+ function get($name, $default = null);
+
+ /**
+ * Sets an attribute.
+ *
+ * @param string $name
+ * @param mixed $value
+ */
+ function set($name, $value);
+
+ /**
+ * Returns attributes.
+ *
+ * @return array Attributes
+ */
+ function all();
+
+ /**
+ * Sets attributes.
+ *
+ * @param array $attributes Attributes
+ */
+ function replace(array $attributes);
+
+ /**
+ * Removes an attribute.
+ *
+ * @param string $name
+ */
+ function remove($name);
+
+ /**
+ * Clears all attributes.
+ */
+ function clear();
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/AbstractSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/AbstractSessionStorage.php
new file mode 100644
index 0000000000000..c703d09a00010
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/AbstractSessionStorage.php
@@ -0,0 +1,339 @@
+
+ *
+ * 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;
+
+use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
+
+/**
+ * This provides a base class for session attribute storage.
+ *
+ * @author Drak
+ */
+abstract class AbstractSessionStorage implements SessionStorageInterface
+{
+ /**
+ * Array of SessionBagInterface
+ *
+ * @var array
+ */
+ protected $bags;
+
+ /**
+ * @var array
+ */
+ protected $options = array();
+
+ /**
+ * @var boolean
+ */
+ protected $started = false;
+
+ /**
+ * @var boolean
+ */
+ protected $closed = false;
+
+ /**
+ * Constructor.
+ *
+ * Depending on how you want the storage driver to behave you probably
+ * want top override this constructor entirely.
+ *
+ * List of options for $options array with their defaults.
+ * @see http://www.php.net/manual/en/session.configuration.php for options
+ * but we omit 'session.' from the beginning of the keys.
+ *
+ * auto_start, "0"
+ * cookie_domain, ""
+ * cookie_httponly, ""
+ * cookie_lifetime, "0"
+ * cookie_path, "/"
+ * cookie_secure, ""
+ * entropy_file, ""
+ * entropy_length, "0"
+ * gc_divisor, "100"
+ * gc_maxlifetime, "1440"
+ * gc_probability, "1"
+ * hash_bits_per_character, "4"
+ * hash_function, "0"
+ * name, "PHPSESSID"
+ * referer_check, ""
+ * save_path, ""
+ * serialize_handler, "php"
+ * use_cookies, "1"
+ * use_only_cookies, "1"
+ * use_trans_sid, "0"
+ * upload_progress.enabled, "1"
+ * upload_progress.cleanup, "1"
+ * upload_progress.prefix, "upload_progress_"
+ * upload_progress.name, "PHP_SESSION_UPLOAD_PROGRESS"
+ * upload_progress.freq, "1%"
+ * upload_progress.min-freq, "1"
+ * url_rewriter.tags, "a=href,area=href,frame=src,form=,fieldset="
+ *
+ * @param array $options Session configuration options.
+ */
+ public function __construct(array $options = array())
+ {
+ $this->setOptions($options);
+ $this->registerSaveHandlers();
+ $this->registerShutdownFunction();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function start()
+ {
+ if ($this->started && !$this->closed) {
+ 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');
+ }
+
+ $this->loadSession();
+
+ $this->started = true;
+ $this->closed = false;
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ if (!$this->started) {
+ return ''; // returning empty is consistent with session_id() behaviour
+ }
+
+ return session_id();
+ }
+
+ /**
+ * Regenerates the session.
+ *
+ * This method will regenerate the session ID and optionally
+ * destroy the old ID. Session regeneration should be done
+ * periodically and for example, should be done when converting
+ * an anonymous session to a logged in user session.
+ *
+ * @param boolean $destroy
+ *
+ * @return boolean Returns true on success or false on failure.
+ */
+ public function regenerate($destroy = false)
+ {
+ return session_regenerate_id($destroy);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function save()
+ {
+ session_write_close();
+ $this->closed = true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear()
+ {
+ // clear out the bags
+ foreach ($this->bags as $bag) {
+ $bag->clear();
+ }
+
+ // clear out the session
+ $_SESSION = array();
+
+ // reconnect the bags to the session
+ $this->loadSession();
+ }
+
+ /**
+ * Register a SessionBagInterface for use.
+ *
+ * @param SessionBagInterface $bag
+ */
+ public function registerBag(SessionBagInterface $bag)
+ {
+ $this->bags[$bag->getName()] = $bag;
+ }
+
+ /**
+ * Gets a bag by name.
+ *
+ * @param string $name
+ *
+ * @return SessionBagInterface
+ *
+ * @throws \InvalidArgumentException
+ */
+ public function getBag($name)
+ {
+ if (!isset($this->bags[$name])) {
+ throw new \InvalidArgumentException(sprintf('The SessionBagInterface %s is not registered.', $name));
+ }
+
+ if ($this->options['auto_start'] && !$this->started) {
+ $this->start();
+ }
+
+ return $this->bags[$name];
+ }
+
+ /**
+ * Sets session.* ini variables.
+ *
+ * For convenience we omit 'session.' from the beginning of the keys.
+ * Explicitly ignores other ini keys.
+ *
+ * session_get_cookie_params() overrides values.
+ *
+ * @param array $options
+ *
+ * @see http://www.php.net/manual/en/session.configuration.php
+ */
+ protected function setOptions(array $options)
+ {
+ $cookieDefaults = session_get_cookie_params();
+ $this->options = array_merge(array(
+ 'cookie_lifetime' => $cookieDefaults['lifetime'],
+ 'cookie_path' => $cookieDefaults['path'],
+ 'cookie_domain' => $cookieDefaults['domain'],
+ 'cookie_secure' => $cookieDefaults['secure'],
+ 'cookie_httponly' => isset($cookieDefaults['httponly']) ? $cookieDefaults['httponly'] : false,
+ ), $options);
+
+ // Unless session.cache_limiter has been set explicitly, disable it
+ // because this is managed by HeaderBag directly (if used).
+ if (!isset($this->options['cache_limiter'])) {
+ $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',
+ 'cookie_lifetime', 'cookie_path', 'cookie_secure',
+ 'entropy_file', 'entropy_length', 'gc_divisor',
+ 'gc_maxlifetime', 'gc_probability', 'hash_bits_per_character',
+ 'hash_function', 'name', 'referer_check',
+ 'save_path', 'serialize_handler', 'use_cookies',
+ 'use_only_cookies', 'use_trans_sid', 'upload_progress.enabled',
+ 'upload_progress.cleanup', 'upload_progress.prefix', 'upload_progress.name',
+ 'upload_progress.freq', 'upload_progress.min-freq', 'url_rewriter.tags'))) {
+ ini_set('session.'.$key, $value);
+ }
+ }
+ }
+
+ /**
+ * Registers this storage device for PHP session handling.
+ *
+ * PHP requires session save handlers to be set, either it's own, or custom ones.
+ * There are some defaults set automatically when PHP starts, but these can be overriden
+ * using this command if you need anything other than PHP's default handling.
+ *
+ * When the session starts, PHP will call the sessionRead() handler which should return an array
+ * of any session attributes. PHP will then populate these into $_SESSION.
+ *
+ * When PHP shuts down, the sessionWrite() handler is called and will pass the $_SESSION contents
+ * to be stored.
+ *
+ * When a session is specifically destroyed, PHP will call the sessionDestroy() handler with the
+ * session ID. This happens when the session is regenerated for example and th handler
+ * MUST delete the session by ID from the persistent storage immediately.
+ *
+ * PHP will call sessionGc() from time to time to expire any session records according to the
+ * set max lifetime of a session. This routine should delete all records from persistent
+ * storage which were last accessed longer than the $lifetime.
+ *
+ * PHP sessionOpen() and sessionClose() are pretty much redundant and can just return true.
+ *
+ * NOTE:
+ *
+ * To use PHP native save handlers, override this method using ini_set with
+ * session.save_handlers and session.save_path e.g.
+ *
+ * ini_set('session.save_handlers', 'files');
+ * ini_set('session.save_path', /tmp');
+ *
+ * @see http://php.net/manual/en/function.session-set-save-handler.php
+ * @see SessionSaveHandlerInterface
+ */
+ protected function registerSaveHandlers()
+ {
+ // note this can be reset to PHP's control using ini_set('session.save_handler', 'files');
+ // so long as ini_set() is called before the session is started.
+ if ($this instanceof SessionSaveHandlerInterface) {
+ session_set_save_handler(
+ array($this, 'openSession'),
+ array($this, 'closeSession'),
+ array($this, 'readSession'),
+ array($this, 'writeSession'),
+ array($this, 'destroySession'),
+ array($this, 'gcSession')
+ );
+ }
+ }
+
+ /**
+ * Registers PHP shutdown function.
+ *
+ * This method is required to avoid strange issues when using PHP objects as
+ * session save handlers.
+ */
+ protected function registerShutdownFunction()
+ {
+ register_shutdown_function('session_write_close');
+ }
+
+ /**
+ * Load the session with attributes.
+ *
+ * After starting the session, PHP retrieves the session from whatever handlers
+ * are set to (either PHP's internal, custom set with session_set_save_handler()).
+ * PHP takes the return value from the sessionRead() handler, unserializes it
+ * and populates $_SESSION with the result automatically.
+ */
+ protected function loadSession(array &$session = null)
+ {
+ if (null === $session) {
+ $session = &$_SESSION;
+ }
+
+ foreach ($this->bags as $bag) {
+ $key = $bag->getStorageKey();
+ $session[$key] = isset($session[$key]) ? $session[$key] : array();
+ $bag->initialize($session[$key]);
+ }
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MemcacheSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MemcacheSessionStorage.php
new file mode 100644
index 0000000000000..f5d5910d860ef
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MemcacheSessionStorage.php
@@ -0,0 +1,136 @@
+
+ *
+ * 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;
+
+/**
+ * MemcacheSessionStorage.
+ *
+ * @author Drak
+ */
+class MemcacheSessionStorage extends AbstractSessionStorage implements SessionSaveHandlerInterface
+{
+ /**
+ * Memcache driver.
+ *
+ * @var Memcache
+ */
+ private $memcache;
+
+ /**
+ * Configuration options.
+ *
+ * @var array
+ */
+ private $memcacheOptions;
+
+ /**
+ * Key prefix for shared environments.
+ *
+ * @var string
+ */
+ private $prefix;
+
+ /**
+ * Constructor.
+ *
+ * @param \Memcache $memcache A \Memcache instance
+ * @param array $memcacheOptions An associative array of Memcachge options
+ * @param array $options Session configuration options.
+ *
+ * @see AbstractSessionStorage::__construct()
+ */
+ public function __construct(\Memcache $memcache, array $memcacheOptions = array(), array $options = array())
+ {
+ $this->memcache = $memcache;
+
+ // defaults
+ if (!isset($memcacheOptions['serverpool'])) {
+ $memcacheOptions['serverpool'] = array(
+ 'host' => '127.0.0.1',
+ 'port' => 11211,
+ 'timeout' => 1,
+ 'persistent' => false,
+ 'weight' => 1);
+ }
+
+ $memcacheOptions['expiretime'] = isset($memcacheOptions['expiretime']) ? (int)$memcacheOptions['expiretime'] : 86400;
+ $this->prefix = isset($memcachedOptions['prefix']) ? $memcachedOptions['prefix'] : 'sf2s';
+
+ $this->memcacheOptions = $memcacheOptions;
+
+ parent::__construct($options);
+ }
+
+ protected function addServer(array $server)
+ {
+ if (array_key_exists('host', $server)) {
+ throw new \InvalidArgumentException('host key must be set');
+ }
+ $server['port'] = isset($server['port']) ? (int)$server['port'] : 11211;
+ $server['timeout'] = isset($server['timeout']) ? (int)$server['timeout'] : 1;
+ $server['presistent'] = isset($server['presistent']) ? (bool)$server['presistent'] : false;
+ $server['weight'] = isset($server['weight']) ? (bool)$server['weight'] : 1;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function openSession($savePath, $sessionName)
+ {
+ foreach ($this->memcacheOptions['serverpool'] as $server) {
+ $this->addServer($server);
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function closeSession()
+ {
+ return $this->memcache->close();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readSession($sessionId)
+ {
+ return $this->memcache->get($this->prefix.$sessionId) ?: '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeSession($sessionId, $data)
+ {
+ return $this->memcache->set($this->prefix.$sessionId, $data, $this->memcacheOptions['expiretime']);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function destroySession($sessionId)
+ {
+ return $this->memcache->delete($this->prefix.$sessionId);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gcSession($lifetime)
+ {
+ // not required here because memcache will auto expire the records anyhow.
+ return true;
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php
new file mode 100644
index 0000000000000..f7041811a3139
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php
@@ -0,0 +1,137 @@
+
+ *
+ * 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;
+
+/**
+ * MemcachedSessionStorage.
+ *
+ * @author Drak
+ */
+class MemcachedSessionStorage extends AbstractSessionStorage implements SessionSaveHandlerInterface
+{
+ /**
+ * Memcached driver.
+ *
+ * @var Memcached
+ */
+ private $memcached;
+
+ /**
+ * Configuration options.
+ *
+ * @var array
+ */
+ private $memcachedOptions;
+
+ /**
+ * Constructor.
+ *
+ * @param \Memcached $memcached A \Memcached instance
+ * @param array $memcachedOptions An associative array of Memcached options
+ * @param array $options Session configuration options.
+ *
+ * @see AbstractSessionStorage::__construct()
+ */
+ public function __construct(\Memcached $memcache, array $memcachedOptions = array(), array $options = array())
+ {
+ $this->memcached = $memcached;
+
+ // defaults
+ if (!isset($memcachedOptions['serverpool'])) {
+ $memcachedOptions['serverpool'] = array(
+ 'host' => '127.0.0.1',
+ 'port' => 11211,
+ 'timeout' => 1,
+ 'persistent' => false,
+ 'weight' => 1);
+ }
+
+ $memcachedOptions['expiretime'] = isset($memcachedOptions['expiretime']) ? (int)$memcachedOptions['expiretime'] : 86400;
+
+ $this->memcached->setOption(\Memcached::OPT_PREFIX_KEY, isset($memcachedOptions['prefix']) ? $memcachedOption['prefix'] : 'sf2s');
+
+ $this->memcacheOptions = $memcachedOptions;
+
+ parent::__construct($options);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function openSession($savePath, $sessionName)
+ {
+ foreach ($this->memcachedOptions['serverpool'] as $server) {
+ $this->addServer($server);
+ }
+
+ return true;
+ }
+
+ /**
+ * Close session.
+ *
+ * @return boolean
+ */
+ public function closeSession()
+ {
+ return $this->memcached->close();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readSession($sessionId)
+ {
+ return $this->memcached->get($this->prefix.$sessionId) ?: '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeSession($sessionId, $data)
+ {
+ return $this->memcached->set($this->prefix.$sessionId, $data, false, $this->memcachedOptions['expiretime']);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function destroySession($sessionId)
+ {
+ return $this->memcached->delete($this->prefix.$sessionId);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gcSession($lifetime)
+ {
+ // not required here because memcached will auto expire the records anyhow.
+ return true;
+ }
+
+ /**
+ * Adds a server to the memcached handler.
+ *
+ * @param array $server
+ */
+ protected function addServer(array $server)
+ {
+ if (array_key_exists('host', $server)) {
+ throw new \InvalidArgumentException('host key must be set');
+ }
+ $server['port'] = isset($server['port']) ? (int)$server['port'] : 11211;
+ $server['timeout'] = isset($server['timeout']) ? (int)$server['timeout'] : 1;
+ $server['presistent'] = isset($server['presistent']) ? (bool)$server['presistent'] : false;
+ $server['weight'] = isset($server['weight']) ? (bool)$server['weight'] : 1;
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php
new file mode 100644
index 0000000000000..2fd1a94c26c60
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php
@@ -0,0 +1,124 @@
+
+ *
+ * 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;
+
+/**
+ * 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
+ * @author Bulat Shakirzyanov
+ * @author Drak
+ */
+class MockArraySessionStorage extends AbstractSessionStorage
+{
+ /**
+ * @var string
+ */
+ protected $sessionId;
+
+ /**
+ * @var array
+ */
+ private $sessionData = array();
+
+ public function setSessionData(array $array)
+ {
+ $this->sessionData = $array;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function start()
+ {
+ if ($this->started && !$this->closed) {
+ return true;
+ }
+
+ $this->started = true;
+ $this->loadSession($this->sessionData);
+
+ $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;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clear()
+ {
+ // clear out the bags
+ foreach ($this->bags as $bag) {
+ $bag->clear();
+ }
+
+ // clear out the session
+ $this->sessionData = array();
+
+ // reconnect the bags to the session
+ $this->loadSession($this->sessionData);
+ }
+
+ /**
+ * Generates a session ID.
+ *
+ * @return string
+ */
+ protected function generateSessionId()
+ {
+ return sha1(uniqid(mt_rand(), true));
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php
new file mode 100644
index 0000000000000..094c4d6005fbb
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php
@@ -0,0 +1,136 @@
+
+ *
+ * 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;
+
+/**
+ * MockFileSessionStorage is used to mock sessions for
+ * functional testing when done in a single PHP process.
+ *
+ * No PHP session is actually started since a session can be initialized
+ * and shutdown only once per PHP execution cycle.
+ *
+ * @author Drak
+ */
+class MockFileSessionStorage extends MockArraySessionStorage
+{
+ /**
+ * @var string
+ */
+ private $savePath;
+
+ /**
+ * Constructor.
+ *
+ * @param string $savePath Path of directory to save session files.
+ * @param array $options Session options.
+ *
+ * @see AbstractSessionStorage::__construct()
+ */
+ public function __construct($savePath = null, array $options = array())
+ {
+ if (null === $savePath) {
+ $savePath = sys_get_temp_dir();
+ }
+
+ if (!is_dir($savePath)) {
+ mkdir($savePath, 0777, true);
+ }
+
+ $this->savePath = $savePath;
+
+ parent::__construct($options);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function start()
+ {
+ if ($this->started) {
+ return true;
+ }
+
+ if (!session_id()) {
+ session_id($this->generateSessionId());
+ }
+
+ $this->sessionId = session_id();
+
+ $this->read();
+
+ $this->started = true;
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function regenerate($destroy = false)
+ {
+ if ($destroy) {
+ $this->destroy();
+ }
+
+ session_id($this->generateSessionId());
+ $this->sessionId = session_id();
+
+ $this->save();
+
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getId()
+ {
+ if (!$this->started) {
+ return '';
+ }
+
+ return $this->sessionId;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function save()
+ {
+ file_put_contents($this->getFilePath(), serialize($this->sessionData));
+ }
+
+ private function destroy()
+ {
+ if (is_file($this->getFilePath())) {
+ unlink($this->getFilePath());
+ }
+ }
+
+ /**
+ * Calculate path to file.
+ *
+ * @return string File path
+ */
+ public function getFilePath()
+ {
+ return $this->savePath.'/'.$this->sessionId.'.sess';
+ }
+
+ private function read()
+ {
+ $filePath = $this->getFilePath();
+ $this->sessionData = is_readable($filePath) && is_file($filePath) ? unserialize(file_get_contents($filePath)) : array();
+
+ $this->loadSession($this->sessionData);
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php
new file mode 100644
index 0000000000000..09350e8d21a89
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php
@@ -0,0 +1,59 @@
+
+ *
+ * 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;
+
+/**
+ * NativeFileSessionStorage.
+ *
+ * Native session handler using PHP's built in file storage.
+ *
+ * @author Drak
+ */
+class NativeFileSessionStorage extends AbstractSessionStorage
+{
+ /**
+ * @var string
+ */
+ private $savePath;
+
+ /**
+ * Constructor.
+ *
+ * @param string $savePath Path of directory to save session files.
+ * @param array $options Session configuration options.
+ *
+ * @see AbstractSessionStorage::__construct()
+ */
+ public function __construct($savePath = null, array $options = array())
+ {
+ if (null === $savePath) {
+ $savePath = sys_get_temp_dir();
+ }
+
+ if (!is_dir($savePath)) {
+ mkdir($savePath, 0777, true);
+ }
+
+ $this->savePath = $savePath;
+
+ parent::__construct($options);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function registerSaveHandlers()
+ {
+ ini_set('session.save_handler', 'files');
+ ini_set('session.save_path', $this->savePath);
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php
new file mode 100644
index 0000000000000..5572c478121f3
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php
@@ -0,0 +1,77 @@
+
+ *
+ * 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;
+
+/**
+ * NativeMemcacheSessionStorage.
+ *
+ * Session based on native PHP memcache database handler.
+ *
+ * @author Drak
+ */
+class NativeMemcacheSessionStorage extends AbstractSessionStorage
+{
+ /**
+ * @var string
+ */
+ private $savePath;
+
+ /**
+ * Constructor.
+ *
+ * @param string $savePath Path of memcache server.
+ * @param array $options Session configuration options.
+ *
+ * @see AbstractSessionStorage::__construct()
+ */
+ public function __construct($savePath = 'tcp://127.0.0.1:11211?persistent=0', array $options = array())
+ {
+ if (!extension_loaded('memcache')) {
+ throw new \RuntimeException('PHP does not have "memcache" session module registered');
+ }
+
+ $this->savePath = $savePath;
+ parent::__construct($options);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function registerSaveHandlers()
+ {
+ ini_set('session.save_handler', 'memcache');
+ ini_set('session.save_path', $this->savePath);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * Sets any values memcached ini values.
+ *
+ * @see http://www.php.net/manual/en/memcache.ini.php
+ */
+ protected function setOptions(array $options)
+ {
+ foreach ($options as $key => $value) {
+ if (in_array($key, array(
+ 'memcache.allow_failover', 'memcache.max_failover_attempts',
+ 'memcache.chunk_size', 'memcache.default_port', 'memcache.hash_strategy',
+ 'memcache.hash_function', 'memcache.protocol', 'memcache.redundancy',
+ 'memcache.session_redundancy', 'memcache.compress_threshold',
+ 'memcache.lock_timeout'))) {
+ ini_set($key, $value);
+ }
+ }
+
+ parent::setOptions($options);
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php
new file mode 100644
index 0000000000000..50d8d060fd059
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php
@@ -0,0 +1,76 @@
+
+ *
+ * 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;
+
+/**
+ * NativeMemcachedSessionStorage.
+ *
+ * Session based on native PHP memcached database handler.
+ *
+ * @author Drak
+ */
+class NativeMemcachedSessionStorage extends AbstractSessionStorage
+{
+ /**
+ * @var string
+ */
+ private $savePath;
+
+ /**
+ * Constructor.
+ *
+ * @param string $savePath Comma separated list of servers: e.g. memcache1.example.com:11211,memcache2.example.com:11211
+ * @param array $options Session configuration options.
+ *
+ * @see AbstractSessionStorage::__construct()
+ */
+ public function __construct($savePath = '127.0.0.1:11211', array $options = array())
+ {
+ if (!extension_loaded('memcached')) {
+ throw new \RuntimeException('PHP does not have "memcached" session module registered');
+ }
+
+ $this->savePath = $savePath;
+ parent::__construct($options);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function registerSaveHandlers()
+ {
+ ini_set('session.save_handler', 'memcached');
+ ini_set('session.save_path', $this->savePath);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * Sets any values memcached ini values.
+ *
+ * @see https://github.com/php-memcached-dev/php-memcached/blob/master/memcached.ini
+ */
+ protected function setOptions(array $options)
+ {
+ foreach ($options as $key => $value) {
+ if (in_array($key, array(
+ 'memcached.sess_locking', 'memcached.sess_lock_wait',
+ 'memcached.sess_prefix', 'memcached.compression_type',
+ 'memcached.compression_factor', 'memcached.compression_threshold',
+ 'memcached.serializer'))) {
+ ini_set($key, $value);
+ }
+ }
+
+ parent::setOptions($options);
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php
new file mode 100644
index 0000000000000..1dac36ac2ff16
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php
@@ -0,0 +1,54 @@
+
+ *
+ * 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;
+
+/**
+ * NativeSqliteSessionStorage.
+ *
+ * Session based on native PHP sqlite database handler.
+ *
+ * @author Drak
+ */
+class NativeSqliteSessionStorage extends AbstractSessionStorage
+{
+ /**
+ * @var string
+ */
+ private $dbPath;
+
+ /**
+ * Constructor.
+ *
+ * @param string $dbPath Path to SQLite database file.
+ * @param array $options Session configuration options.
+ *
+ * @see AbstractSessionStorage::__construct()
+ */
+ public function __construct($dbPath, array $options = array())
+ {
+ if (!extension_loaded('sqlite')) {
+ throw new \RuntimeException('PHP does not have "sqlite" session module registered');
+ }
+
+ $this->dbPath = $dbPath;
+ parent::__construct($options);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function registerSaveHandlers()
+ {
+ ini_set('session.save_handler', 'sqlite');
+ ini_set('session.save_path', $this->dbPath);
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php
new file mode 100644
index 0000000000000..b81fa8ae3acfe
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php
@@ -0,0 +1,74 @@
+
+ *
+ * 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;
+
+/**
+ * NullSessionStorage.
+ *
+ * Can be used in unit testing or in a sitation where persisted sessions are not desired.
+ *
+ * @author Drak
+ *
+ * @api
+ */
+class NullSessionStorage extends AbstractSessionStorage implements SessionSaveHandlerInterface
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function openSession($savePath, $sessionName)
+ {
+ return true;
+ }
+
+ /**
+ * Close session.
+ *
+ * @return boolean
+ */
+ public function closeSession()
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function readSession($sessionId)
+ {
+ return '';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function writeSession($sessionId, $data)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function destroySession($sessionId)
+ {
+ return true;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function gcSession($lifetime)
+ {
+ return true;
+ }
+}
diff --git a/src/Symfony/Component/HttpFoundation/SessionStorage/PdoSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/PdoSessionStorage.php
similarity index 68%
rename from src/Symfony/Component/HttpFoundation/SessionStorage/PdoSessionStorage.php
rename to src/Symfony/Component/HttpFoundation/Session/Storage/PdoSessionStorage.php
index 24898b7c20cb9..2015396b2fe9c 100644
--- a/src/Symfony/Component/HttpFoundation/SessionStorage/PdoSessionStorage.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/PdoSessionStorage.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\HttpFoundation\SessionStorage;
+namespace Symfony\Component\HttpFoundation\Session\Storage;
/**
* PdoSessionStorage.
@@ -17,18 +17,19 @@
* @author Fabien Potencier
* @author Michael Williams
*/
-class PdoSessionStorage extends NativeSessionStorage
+class PdoSessionStorage extends AbstractSessionStorage implements SessionSaveHandlerInterface
{
/**
* PDO instance.
*
* @var \PDO
*/
- private $db;
+ private $pdo;
/**
* Database options.
*
+ *
* @var array
*/
private $dbOptions;
@@ -36,21 +37,22 @@ class PdoSessionStorage extends NativeSessionStorage
/**
* Constructor.
*
- * @param \PDO $db A PDO instance
- * @param array $options An associative array of session options
- * @param array $dbOptions An associative array of DB options
+ *
+ * @param \PDO $pdo A \PDO instance
+ * @param array $dbOptions An associative array of DB options
+ * @param array $options Session configuration options
*
* @throws \InvalidArgumentException When "db_table" option is not provided
*
- * @see NativeSessionStorage::__construct()
+ * @see AbstractSessionStorage::__construct()
*/
- public function __construct(\PDO $db, array $options = array(), array $dbOptions = array())
+ public function __construct(\PDO $pdo, array $dbOptions = array(), array $options = array())
{
if (!array_key_exists('db_table', $dbOptions)) {
throw new \InvalidArgumentException('You must provide the "db_table" option for a PdoSessionStorage.');
}
- $this->db = $db;
+ $this->pdo = $pdo;
$this->dbOptions = array_merge(array(
'db_id_col' => 'sess_id',
'db_data_col' => 'sess_data',
@@ -61,61 +63,27 @@ public function __construct(\PDO $db, array $options = array(), array $dbOptions
}
/**
- * Starts the session.
- */
- public function start()
- {
- if (self::$sessionStarted) {
- return;
- }
-
- // use this object as the session handler
- session_set_save_handler(
- array($this, 'sessionOpen'),
- array($this, 'sessionClose'),
- array($this, 'sessionRead'),
- array($this, 'sessionWrite'),
- array($this, 'sessionDestroy'),
- array($this, 'sessionGC')
- );
-
- parent::start();
- }
-
- /**
- * Opens a session.
- *
- * @param string $path (ignored)
- * @param string $name (ignored)
- *
- * @return Boolean true, if the session was opened, otherwise an exception is thrown
+ * {@inheritdoc}
*/
- public function sessionOpen($path = null, $name = null)
+ public function openSession($path = null, $name = null)
{
return true;
}
/**
- * Closes a session.
- *
- * @return Boolean true, if the session was closed, otherwise false
+ * {@inheritdoc}
*/
- public function sessionClose()
+ public function closeSession()
{
- // do nothing
return true;
}
/**
- * Destroys a session.
- *
- * @param string $id A session ID
- *
- * @return Boolean true, if the session was destroyed, otherwise an exception is thrown
+ * {@inheritdoc}
*
* @throws \RuntimeException If the session cannot be destroyed
*/
- public function sessionDestroy($id)
+ public function destroySession($id)
{
// get table/column
$dbTable = $this->dbOptions['db_table'];
@@ -125,7 +93,7 @@ public function sessionDestroy($id)
$sql = "DELETE FROM $dbTable WHERE $dbIdCol = :id";
try {
- $stmt = $this->db->prepare($sql);
+ $stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
$stmt->execute();
} catch (\PDOException $e) {
@@ -136,15 +104,11 @@ public function sessionDestroy($id)
}
/**
- * Cleans up old sessions.
- *
- * @param int $lifetime The lifetime of a session
- *
- * @return Boolean true, if old sessions have been cleaned, otherwise an exception is thrown
+ * {@inheritdoc}
*
* @throws \RuntimeException If any old sessions cannot be cleaned
*/
- public function sessionGC($lifetime)
+ public function gcSession($lifetime)
{
// get table/column
$dbTable = $this->dbOptions['db_table'];
@@ -154,7 +118,7 @@ public function sessionGC($lifetime)
$sql = "DELETE FROM $dbTable WHERE $dbTimeCol < (:time - $lifetime)";
try {
- $stmt = $this->db->prepare($sql);
+ $stmt = $this->pdo->prepare($sql);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
$stmt->execute();
} catch (\PDOException $e) {
@@ -165,15 +129,11 @@ public function sessionGC($lifetime)
}
/**
- * Reads a session.
- *
- * @param string $id A session ID
- *
- * @return string The session data if the session was read or created, otherwise an exception is thrown
+ * {@inheritdoc}
*
* @throws \RuntimeException If the session cannot be read
*/
- public function sessionRead($id)
+ public function readSession($id)
{
// get table/columns
$dbTable = $this->dbOptions['db_table'];
@@ -183,7 +143,7 @@ public function sessionRead($id)
try {
$sql = "SELECT $dbDataCol FROM $dbTable WHERE $dbIdCol = :id";
- $stmt = $this->db->prepare($sql);
+ $stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR, 255);
$stmt->execute();
@@ -200,21 +160,16 @@ public function sessionRead($id)
return '';
} catch (\PDOException $e) {
- throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
+ throw new \RuntimeException(sprintf('PDOException was thrown when trying to read the session data: %s', $e->getMessage()), 0, $e);
}
}
/**
- * Writes session data.
- *
- * @param string $id A session ID
- * @param string $data A serialized chunk of session data
- *
- * @return Boolean true, if the session was written, otherwise an exception is thrown
+ * {@inheritdoc}
*
* @throws \RuntimeException If the session data cannot be written
*/
- public function sessionWrite($id, $data)
+ public function writeSession($id, $data)
{
// get table/column
$dbTable = $this->dbOptions['db_table'];
@@ -222,7 +177,7 @@ public function sessionWrite($id, $data)
$dbIdCol = $this->dbOptions['db_id_col'];
$dbTimeCol = $this->dbOptions['db_time_col'];
- $sql = ('mysql' === $this->db->getAttribute(\PDO::ATTR_DRIVER_NAME))
+ $sql = ('mysql' === $this->pdo->getAttribute(\PDO::ATTR_DRIVER_NAME))
? "INSERT INTO $dbTable ($dbIdCol, $dbDataCol, $dbTimeCol) VALUES (:id, :data, :time) "
."ON DUPLICATE KEY UPDATE $dbDataCol = VALUES($dbDataCol), $dbTimeCol = CASE WHEN $dbTimeCol = :time THEN (VALUES($dbTimeCol) + 1) ELSE VALUES($dbTimeCol) END"
: "UPDATE $dbTable SET $dbDataCol = :data, $dbTimeCol = :time WHERE $dbIdCol = :id";
@@ -230,7 +185,7 @@ public function sessionWrite($id, $data)
try {
//session data can contain non binary safe characters so we need to encode it
$encoded = base64_encode($data);
- $stmt = $this->db->prepare($sql);
+ $stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
$stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
@@ -242,7 +197,7 @@ public function sessionWrite($id, $data)
$this->createNewSession($id, $data);
}
} catch (\PDOException $e) {
- throw new \RuntimeException(sprintf('PDOException was thrown when trying to manipulate session data: %s', $e->getMessage()), 0, $e);
+ throw new \RuntimeException(sprintf('PDOException was thrown when trying to write the session data: %s', $e->getMessage()), 0, $e);
}
return true;
@@ -268,7 +223,7 @@ private function createNewSession($id, $data = '')
//session data can contain non binary safe characters so we need to encode it
$encoded = base64_encode($data);
- $stmt = $this->db->prepare($sql);
+ $stmt = $this->pdo->prepare($sql);
$stmt->bindParam(':id', $id, \PDO::PARAM_STR);
$stmt->bindParam(':data', $encoded, \PDO::PARAM_STR);
$stmt->bindValue(':time', time(), \PDO::PARAM_INT);
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionSaveHandlerInterface.php b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionSaveHandlerInterface.php
new file mode 100644
index 0000000000000..ec4530a15064e
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionSaveHandlerInterface.php
@@ -0,0 +1,157 @@
+
+ *
+ * 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;
+
+/**
+ * Session Savehandler Interface.
+ *
+ * This interface is for implementing methods required for the
+ * session_set_save_handler() function.
+ *
+ * @see http://php.net/session_set_save_handler
+ *
+ * These are methods called by PHP when the session is started
+ * and closed and for various house-keeping tasks required
+ * by session management.
+ *
+ * PHP requires session save handlers. There are some defaults set
+ * automatically when PHP starts, but these can be overriden using
+ * this command if you need anything other than PHP's default handling.
+ *
+ * When the session starts, PHP will call the readSession() handler
+ * which should return a string extactly as stored (which will have
+ * been encoded by PHP using a special session serializer session_decode()
+ * which is different to the serialize() function. PHP will then populate
+ * these into $_SESSION.
+ *
+ * When PHP shuts down, the sessionWrite() handler is called and will pass
+ * the $_SESSION contents already serialized (using session_encode()) to
+ * be stored.
+ *
+ * When a session is specifically destroyed, PHP will call the
+ * sessionSession() handler with the session ID. This happens when the
+ * session is regenerated for example and th handler MUST delete the
+ * session by ID from the persistent storage immediately.
+ *
+ * PHP will call sessionSession() from time to time to expire any session
+ * records according to the set max lifetime of a session. This routine
+ * should delete all records from persistent storage which were last
+ * accessed longer than the $lifetime.
+ *
+ * PHP openSession() and closeSession() are pretty much redundant and
+ * can return true.
+ *
+ * @author Drak
+ */
+interface SessionSaveHandlerInterface
+{
+ /**
+ * Open session.
+ *
+ * This method is for internal use by PHP and must not be called manually.
+ *
+ * @param string $savePath Save path.
+ * @param string $sessionName Session Name.
+ *
+ * @throws \RuntimeException If something goes wrong starting the session.
+ *
+ * @return boolean
+ */
+ function openSession($savePath, $sessionName);
+
+ /**
+ * Close session.
+ *
+ * This method is for internal use by PHP and must not be called manually.
+ *
+ * @return boolean
+ */
+ function closeSession();
+
+ /**
+ * Read session.
+ *
+ * This method is for internal use by PHP and must not be called manually.
+ *
+ * This method is called by PHP itself when the session is started.
+ * This method should retrieve the session data from storage by the
+ * ID provided by PHP. Return the string directly as is from storage.
+ * If the record was not found you must return an empty string.
+ *
+ * The returned data will be unserialized automatically by PHP using a
+ * special unserializer method session_decode() and the result will be used
+ * to populate the $_SESSION superglobal. This is done automatically and
+ * is not configurable.
+ *
+ * @param string $sessionId Session ID.
+ *
+ * @throws \RuntimeException On fatal error but not "record not found".
+ *
+ * @return string String as stored in persistent storage or empty string in all other cases.
+ */
+ function readSession($sessionId);
+
+ /**
+ * Commit session to storage.
+ *
+ * This method is for internal use by PHP and must not be called manually.
+ *
+ * PHP will call this method when the session is closed. It sends
+ * the session ID and the contents of $_SESSION to be saved in a lightweight
+ * serialized format (which PHP does automatically using session_encode()
+ * which should be stored exactly as is given in $data.
+ *
+ * Note this method is normally called by PHP after the output buffers
+ * have been closed.
+ *
+ * @param string $sessionId Session ID.
+ * @param string $data Session serialized data to save.
+ *
+ * @throws \RuntimeException On fatal error.
+ *
+ * @return boolean
+ */
+ function writeSession($sessionId, $data);
+
+ /**
+ * Destroys this session.
+ *
+ * This method is for internal use by PHP and must not be called manually.
+ *
+ * PHP will call this method when the session data associated
+ * with the session ID provided needs to be immediately
+ * deleted from the permanent storage.
+ *
+ * @param string $sessionId Session ID.
+ *
+ * @throws \RuntimeException On fatal error.
+ *
+ * @return boolean
+ */
+ function destroySession($sessionId);
+
+ /**
+ * Garbage collection for storage.
+ *
+ * This method is for internal use by PHP and must not be called manually.
+ *
+ * This method is called by PHP periodically and passes the maximum
+ * time a session can exist for before being deleted from permanent storage.
+ *
+ * @param integer $lifetime Max lifetime in seconds to keep sessions stored.
+ *
+ * @throws \RuntimeException On fatal error.
+ *
+ * @return boolean
+ */
+ function gcSession($lifetime);
+}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php
new file mode 100644
index 0000000000000..7eb720b7c62ee
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php
@@ -0,0 +1,92 @@
+
+ *
+ * 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;
+
+use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
+
+/**
+ * StorageInterface.
+ *
+ * @author Fabien Potencier
+ * @author Drak
+ *
+ * @api
+ */
+interface SessionStorageInterface
+{
+ /**
+ * Starts the session.
+ *
+ * @throws \RuntimeException If something goes wrong starting the session.
+ *
+ * @return boolean True if started.
+ *
+ * @api
+ */
+ function start();
+
+ /**
+ * Returns the session ID
+ *
+ * @return mixed The session ID or false if the session has not started.
+ *
+ * @api
+ */
+ function getId();
+
+ /**
+ * Regenerates id that represents this storage.
+ *
+ * This method must invoke session_regenerate_id($destroy) unless
+ * this interface is used for a storage object designed for unit
+ * or functional testing where a real PHP session would interfere
+ * with testing.
+ *
+ * @param Boolean $destroy Destroy session when regenerating?
+ *
+ * @return Boolean True if session regenerated, false if error
+ *
+ * @throws \RuntimeException If an error occurs while regenerating this storage
+ *
+ * @api
+ */
+ function regenerate($destroy = false);
+
+ /**
+ * Force the session to be saved and closed.
+ *
+ * This method must invoke session_write_close() unless this interface is
+ * used for a storage object design for unit or functional testing where
+ * a real PHP session would interfere with testing, in which case it
+ * it should actually persist the session data if required.
+ */
+ function save();
+
+ /**
+ * Clear all session data in memory.
+ */
+ function clear();
+
+ /**
+ * Gets a SessionBagInterface by name.
+ *
+ * @return SessionBagInterface
+ */
+ function getBag($name);
+
+ /**
+ * Registers a SessionBagInterface for use.
+ *
+ * @param SessionBagInterface $bag
+ */
+ function registerBag(SessionBagInterface $bag);
+}
diff --git a/src/Symfony/Component/HttpFoundation/SessionStorage/ArraySessionStorage.php b/src/Symfony/Component/HttpFoundation/SessionStorage/ArraySessionStorage.php
deleted file mode 100644
index 5a6558a2b387b..0000000000000
--- a/src/Symfony/Component/HttpFoundation/SessionStorage/ArraySessionStorage.php
+++ /dev/null
@@ -1,81 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\HttpFoundation\SessionStorage;
-
-/**
- * ArraySessionStorage mocks the session for unit tests.
- *
- * When doing functional testing, you should use FilesystemSessionStorage instead.
- *
- * @author Fabien Potencier
- * @author Bulat Shakirzyanov
- */
-
-class ArraySessionStorage implements SessionStorageInterface
-{
- /**
- * Storage data.
- *
- * @var array
- */
- private $data = array();
-
- /**
- * {@inheritdoc}
- */
- public function read($key, $default = null)
- {
- return array_key_exists($key, $this->data) ? $this->data[$key] : $default;
- }
-
- /**
- * {@inheritdoc}
- */
- public function regenerate($destroy = false)
- {
- if ($destroy) {
- $this->data = array();
- }
-
- return true;
- }
-
- /**
- * {@inheritdoc}
- */
- public function remove($key)
- {
- unset($this->data[$key]);
- }
-
- /**
- * {@inheritdoc}
- */
- public function start()
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function getId()
- {
- }
-
- /**
- * {@inheritdoc}
- */
- public function write($key, $data)
- {
- $this->data[$key] = $data;
- }
-}
diff --git a/src/Symfony/Component/HttpFoundation/SessionStorage/FilesystemSessionStorage.php b/src/Symfony/Component/HttpFoundation/SessionStorage/FilesystemSessionStorage.php
deleted file mode 100644
index ceb5913fe934f..0000000000000
--- a/src/Symfony/Component/HttpFoundation/SessionStorage/FilesystemSessionStorage.php
+++ /dev/null
@@ -1,192 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\HttpFoundation\SessionStorage;
-
-/**
- * FilesystemSessionStorage simulates sessions for functional tests.
- *
- * This storage does not start the session (session_start())
- * as it is not "available" when running tests on the command line.
- *
- * @author Fabien Potencier
- *
- * @api
- */
-class FilesystemSessionStorage extends NativeSessionStorage
-{
- /**
- * File path.
- *
- * @var string
- */
- private $path;
-
- /**
- * Data.
- *
- * @var array
- */
- private $data;
-
- /**
- * Session started flag.
- *
- * @var boolean
- */
- private $started;
-
- /**
- * Constructor.
- */
- public function __construct($path, array $options = array())
- {
- $this->path = $path;
- $this->started = false;
-
- parent::__construct($options);
- }
-
- /**
- * Starts the session.
- *
- * @api
- */
- public function start()
- {
- if ($this->started) {
- return;
- }
-
- session_set_cookie_params(
- $this->options['lifetime'],
- $this->options['path'],
- $this->options['domain'],
- $this->options['secure'],
- $this->options['httponly']
- );
-
- if (!ini_get('session.use_cookies') && isset($this->options['id']) && $this->options['id'] && $this->options['id'] != session_id()) {
- session_id($this->options['id']);
- }
-
- if (!session_id()) {
- session_id(hash('md5', uniqid(mt_rand(), true)));
- }
-
- $file = $this->path.'/'.session_id().'.session';
-
- $this->data = is_file($file) ? unserialize(file_get_contents($file)) : array();
- $this->started = true;
- }
-
- /**
- * Returns the session ID
- *
- * @return mixed The session ID
- *
- * @throws \RuntimeException If the session was not started yet
- *
- * @api
- */
- public function getId()
- {
- if (!$this->started) {
- throw new \RuntimeException('The session must be started before reading its ID');
- }
-
- return session_id();
- }
-
- /**
- * Reads data from this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- * @param string $default The default value
- *
- * @return mixed Data associated with the key
- *
- * @throws \RuntimeException If an error occurs while reading data from this storage
- *
- * @api
- */
- public function read($key, $default = null)
- {
- return array_key_exists($key, $this->data) ? $this->data[$key] : $default;
- }
-
- /**
- * Removes data from this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- *
- * @return mixed Data associated with the key
- *
- * @throws \RuntimeException If an error occurs while removing data from this storage
- *
- * @api
- */
- public function remove($key)
- {
- $retval = $this->data[$key];
-
- unset($this->data[$key]);
-
- return $retval;
- }
-
- /**
- * Writes data to this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- * @param mixed $data Data associated with your key
- *
- * @throws \RuntimeException If an error occurs while writing to this storage
- *
- * @api
- */
- public function write($key, $data)
- {
- $this->data[$key] = $data;
-
- if (!is_dir($this->path)) {
- mkdir($this->path, 0777, true);
- }
-
- file_put_contents($this->path.'/'.session_id().'.session', serialize($this->data));
- }
-
- /**
- * Regenerates id that represents this storage.
- *
- * @param Boolean $destroy Destroy session when regenerating?
- *
- * @return Boolean True if session regenerated, false if error
- *
- * @throws \RuntimeException If an error occurs while regenerating this storage
- *
- * @api
- */
- public function regenerate($destroy = false)
- {
- if ($destroy) {
- $this->data = array();
- }
-
- return true;
- }
-}
diff --git a/src/Symfony/Component/HttpFoundation/SessionStorage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/SessionStorage/NativeSessionStorage.php
deleted file mode 100644
index b759f7411a0a4..0000000000000
--- a/src/Symfony/Component/HttpFoundation/SessionStorage/NativeSessionStorage.php
+++ /dev/null
@@ -1,180 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\HttpFoundation\SessionStorage;
-
-/**
- * NativeSessionStorage.
- *
- * @author Fabien Potencier
- *
- * @api
- */
-class NativeSessionStorage implements SessionStorageInterface
-{
- static protected $sessionIdRegenerated = false;
- static protected $sessionStarted = false;
-
- protected $options;
-
- /**
- * Available options:
- *
- * * name: The cookie name (null [omitted] by default)
- * * id: The session id (null [omitted] by default)
- * * lifetime: Cookie lifetime
- * * path: Cookie path
- * * domain: Cookie domain
- * * secure: Cookie secure
- * * httponly: Cookie http only
- *
- * The default values for most options are those returned by the session_get_cookie_params() function
- *
- * @param array $options An associative array of session options
- */
- public function __construct(array $options = array())
- {
- $cookieDefaults = session_get_cookie_params();
-
- $this->options = array_merge(array(
- 'lifetime' => $cookieDefaults['lifetime'],
- 'path' => $cookieDefaults['path'],
- 'domain' => $cookieDefaults['domain'],
- 'secure' => $cookieDefaults['secure'],
- 'httponly' => isset($cookieDefaults['httponly']) ? $cookieDefaults['httponly'] : false,
- ), $options);
-
- // Skip setting new session name if user don't want it
- if (isset($this->options['name'])) {
- session_name($this->options['name']);
- }
- }
-
- /**
- * Starts the session.
- *
- * @api
- */
- public function start()
- {
- if (self::$sessionStarted) {
- return;
- }
-
- session_set_cookie_params(
- $this->options['lifetime'],
- $this->options['path'],
- $this->options['domain'],
- $this->options['secure'],
- $this->options['httponly']
- );
-
- // disable native cache limiter as this is managed by HeaderBag directly
- session_cache_limiter(false);
-
- if (!ini_get('session.use_cookies') && isset($this->options['id']) && $this->options['id'] && $this->options['id'] != session_id()) {
- session_id($this->options['id']);
- }
-
- session_start();
-
- self::$sessionStarted = true;
- }
-
- /**
- * {@inheritDoc}
- *
- * @api
- */
- public function getId()
- {
- if (!self::$sessionStarted) {
- throw new \RuntimeException('The session must be started before reading its ID');
- }
-
- return session_id();
- }
-
- /**
- * Reads data from this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- * @param string $default Default value
- *
- * @return mixed Data associated with the key
- *
- * @api
- */
- public function read($key, $default = null)
- {
- return array_key_exists($key, $_SESSION) ? $_SESSION[$key] : $default;
- }
-
- /**
- * Removes data from this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- *
- * @return mixed Data associated with the key
- *
- * @api
- */
- public function remove($key)
- {
- $retval = null;
-
- if (isset($_SESSION[$key])) {
- $retval = $_SESSION[$key];
- unset($_SESSION[$key]);
- }
-
- return $retval;
- }
-
- /**
- * Writes data to this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- * @param mixed $data Data associated with your key
- *
- * @api
- */
- public function write($key, $data)
- {
- $_SESSION[$key] = $data;
- }
-
- /**
- * Regenerates id that represents this storage.
- *
- * @param Boolean $destroy Destroy session when regenerating?
- *
- * @return Boolean True if session regenerated, false if error
- *
- * @api
- */
- public function regenerate($destroy = false)
- {
- if (self::$sessionIdRegenerated) {
- return;
- }
-
- session_regenerate_id($destroy);
-
- self::$sessionIdRegenerated = true;
- }
-}
diff --git a/src/Symfony/Component/HttpFoundation/SessionStorage/SessionStorageInterface.php b/src/Symfony/Component/HttpFoundation/SessionStorage/SessionStorageInterface.php
deleted file mode 100644
index b61a2557b27c7..0000000000000
--- a/src/Symfony/Component/HttpFoundation/SessionStorage/SessionStorageInterface.php
+++ /dev/null
@@ -1,97 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\HttpFoundation\SessionStorage;
-
-/**
- * SessionStorageInterface.
- *
- * @author Fabien Potencier
- *
- * @api
- */
-interface SessionStorageInterface
-{
- /**
- * Starts the session.
- *
- * @api
- */
- function start();
-
- /**
- * Returns the session ID
- *
- * @return mixed The session ID
- *
- * @throws \RuntimeException If the session was not started yet
- *
- * @api
- */
- function getId();
-
- /**
- * Reads data from this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- *
- * @return mixed Data associated with the key
- *
- * @throws \RuntimeException If an error occurs while reading data from this storage
- *
- * @api
- */
- function read($key);
-
- /**
- * Removes data from this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- *
- * @return mixed Data associated with the key
- *
- * @throws \RuntimeException If an error occurs while removing data from this storage
- *
- * @api
- */
- function remove($key);
-
- /**
- * Writes data to this storage.
- *
- * The preferred format for a key is directory style so naming conflicts can be avoided.
- *
- * @param string $key A unique key identifying your data
- * @param mixed $data Data associated with your key
- *
- * @throws \RuntimeException If an error occurs while writing to this storage
- *
- * @api
- */
- function write($key, $data);
-
- /**
- * Regenerates id that represents this storage.
- *
- * @param Boolean $destroy Destroy session when regenerating?
- *
- * @return Boolean True if session regenerated, false if error
- *
- * @throws \RuntimeException If an error occurs while regenerating this storage
- *
- * @api
- */
- function regenerate($destroy = false);
-}
diff --git a/tests/Symfony/Tests/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php b/tests/Symfony/Tests/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php
index 958a32829594e..3358ffcb21df2 100644
--- a/tests/Symfony/Tests/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php
+++ b/tests/Symfony/Tests/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php
@@ -21,7 +21,7 @@ class SessionCsrfProviderTest extends \PHPUnit_Framework_TestCase
protected function setUp()
{
$this->session = $this->getMock(
- 'Symfony\Component\HttpFoundation\Session',
+ 'Symfony\Component\HttpFoundation\Session\Session',
array(),
array(),
'',
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php b/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php
index 4b208bb3ec780..c147070fdfa2b 100644
--- a/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php
+++ b/tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php
@@ -12,10 +12,8 @@
namespace Symfony\Tests\Component\HttpFoundation;
-use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
-
-use Symfony\Component\HttpFoundation\Session;
-
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
+use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Request;
class RequestTest extends \PHPUnit_Framework_TestCase
@@ -848,7 +846,7 @@ public function testHasSession()
$request = new Request;
$this->assertFalse($request->hasSession());
- $request->setSession(new Session(new ArraySessionStorage()));
+ $request->setSession(new Session(new MockArraySessionStorage()));
$this->assertTrue($request->hasSession());
}
@@ -859,7 +857,7 @@ public function testHasPreviousSession()
$this->assertFalse($request->hasPreviousSession());
$request->cookies->set(session_name(), 'foo');
$this->assertFalse($request->hasPreviousSession());
- $request->setSession(new Session(new ArraySessionStorage()));
+ $request->setSession(new Session(new MockArraySessionStorage()));
$this->assertTrue($request->hasPreviousSession());
}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Attribute/AttributeBagTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Attribute/AttributeBagTest.php
new file mode 100644
index 0000000000000..a5c921254c7d2
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Attribute/AttributeBagTest.php
@@ -0,0 +1,155 @@
+
+ */
+class AttributeBagTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var array
+ */
+ private $array;
+
+ /**
+ * @var AttributeBag
+ */
+ private $bag;
+
+ protected function setUp()
+ {
+ $this->array = array(
+ 'hello' => 'world',
+ 'always' => 'be happy',
+ 'user.login' => 'drak',
+ 'csrf.token' => array(
+ 'a' => '1234',
+ 'b' => '4321',
+ ),
+ 'category' => array(
+ 'fishing' => array(
+ 'first' => 'cod',
+ 'second' => 'sole')
+ ),
+ );
+ $this->bag = new AttributeBag('_sf2');
+ $this->bag->initialize($this->array);
+ }
+
+ protected function tearDown()
+ {
+ $this->bag = null;
+ $this->array = array();
+ }
+
+ public function testInitialize()
+ {
+ $bag = new AttributeBag();
+ $bag->initialize($this->array);
+ $this->assertEquals($this->array, $bag->all());
+ $array = array('should' => 'change');
+ $bag->initialize($array);
+ $this->assertEquals($array, $bag->all());
+ }
+
+ public function testGetStorageKey()
+ {
+ $this->assertEquals('_sf2', $this->bag->getStorageKey());
+ $attributeBag = new AttributeBag('test');
+ $this->assertEquals('test', $attributeBag->getStorageKey());
+ }
+
+ /**
+ * @dataProvider attributesProvider
+ */
+ public function testHas($key, $value, $exists)
+ {
+ $this->assertEquals($exists, $this->bag->has($key));
+ }
+
+ /**
+ * @dataProvider attributesProvider
+ */
+ public function testGet($key, $value, $expected)
+ {
+ $this->assertEquals($value, $this->bag->get($key));
+ }
+
+ public function testGetDefaults()
+ {
+ $this->assertNull($this->bag->get('user2.login'));
+ $this->assertEquals('default', $this->bag->get('user2.login', 'default'));
+ }
+
+ /**
+ * @dataProvider attributesProvider
+ */
+ public function testSet($key, $value, $expected)
+ {
+ $this->bag->set($key, $value);
+ $this->assertEquals($value, $this->bag->get($key));
+ }
+
+ public function testAll()
+ {
+ $this->assertEquals($this->array, $this->bag->all());
+
+ $this->bag->set('hello', 'fabien');
+ $array = $this->array;
+ $array['hello'] = 'fabien';
+ $this->assertEquals($array, $this->bag->all());
+ }
+
+ public function testReplace()
+ {
+ $array = array();
+ $array['name'] = 'jack';
+ $array['foo.bar'] = 'beep';
+ $this->bag->replace($array);
+ $this->assertEquals($array, $this->bag->all());
+ $this->assertNull($this->bag->get('hello'));
+ $this->assertNull($this->bag->get('always'));
+ $this->assertNull($this->bag->get('user.login'));
+ }
+
+ public function testRemove()
+ {
+ $this->assertEquals('world', $this->bag->get('hello'));
+ $this->bag->remove('hello');
+ $this->assertNull($this->bag->get('hello'));
+
+ $this->assertEquals('be happy', $this->bag->get('always'));
+ $this->bag->remove('always');
+ $this->assertNull($this->bag->get('always'));
+
+ $this->assertEquals('drak', $this->bag->get('user.login'));
+ $this->bag->remove('user.login');
+ $this->assertNull($this->bag->get('user.login'));
+ }
+
+ public function testClear()
+ {
+ $this->bag->clear();
+ $this->assertEquals(array(), $this->bag->all());
+ }
+
+ public function attributesProvider()
+ {
+ return array(
+ array('hello', 'world', true),
+ array('always', 'be happy', true),
+ array('user.login', 'drak', true),
+ array('csrf.token', array('a' => '1234', 'b' => '4321'), true),
+ array('category', array('fishing' => array('first' => 'cod', 'second' => 'sole')), true),
+ array('user2.login', null, false),
+ array('never', null, false),
+ array('bye', null, false),
+ array('bye/for/now', null, false),
+ );
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBagTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBagTest.php
new file mode 100644
index 0000000000000..94e5d80b0770d
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBagTest.php
@@ -0,0 +1,162 @@
+
+ */
+class NamespacedAttributeBagTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var array
+ */
+ private $array;
+
+ /**
+ * @var NamespacedAttributeBag
+ */
+ private $bag;
+
+ protected function setUp()
+ {
+ $this->array = array(
+ 'hello' => 'world',
+ 'always' => 'be happy',
+ 'user.login' => 'drak',
+ 'csrf.token' => array(
+ 'a' => '1234',
+ 'b' => '4321',
+ ),
+ 'category' => array(
+ 'fishing' => array(
+ 'first' => 'cod',
+ 'second' => 'sole')
+ ),
+ );
+ $this->bag = new NamespacedAttributeBag('_sf2', '/');
+ $this->bag->initialize($this->array);
+ }
+
+ protected function tearDown()
+ {
+ $this->bag = null;
+ $this->array = array();
+ }
+
+ public function testInitialize()
+ {
+ $bag = new NamespacedAttributeBag();
+ $bag->initialize($this->array);
+ $this->assertEquals($this->array, $this->bag->all());
+ $array = array('should' => 'not stick');
+ $bag->initialize($array);
+
+ // should have remained the same
+ $this->assertEquals($this->array, $this->bag->all());
+ }
+
+ public function testGetStorageKey()
+ {
+ $this->assertEquals('_sf2', $this->bag->getStorageKey());
+ $attributeBag = new NamespacedAttributeBag('test');
+ $this->assertEquals('test', $attributeBag->getStorageKey());
+ }
+
+ /**
+ * @dataProvider attributesProvider
+ */
+ public function testHas($key, $value, $exists)
+ {
+ $this->assertEquals($exists, $this->bag->has($key));
+ }
+
+ /**
+ * @dataProvider attributesProvider
+ */
+ public function testGet($key, $value, $expected)
+ {
+ $this->assertEquals($value, $this->bag->get($key));
+ }
+
+ public function testGetDefaults()
+ {
+ $this->assertNull($this->bag->get('user2.login'));
+ $this->assertEquals('default', $this->bag->get('user2.login', 'default'));
+ }
+
+ /**
+ * @dataProvider attributesProvider
+ */
+ public function testSet($key, $value, $expected)
+ {
+ $this->bag->set($key, $value);
+ $this->assertEquals($value, $this->bag->get($key));
+ }
+
+ public function testAll()
+ {
+ $this->assertEquals($this->array, $this->bag->all());
+
+ $this->bag->set('hello', 'fabien');
+ $array = $this->array;
+ $array['hello'] = 'fabien';
+ $this->assertEquals($array, $this->bag->all());
+ }
+
+ public function testReplace()
+ {
+ $array = array();
+ $array['name'] = 'jack';
+ $array['foo.bar'] = 'beep';
+ $this->bag->replace($array);
+ $this->assertEquals($array, $this->bag->all());
+ $this->assertNull($this->bag->get('hello'));
+ $this->assertNull($this->bag->get('always'));
+ $this->assertNull($this->bag->get('user.login'));
+ }
+
+ public function testRemove()
+ {
+ $this->assertEquals('world', $this->bag->get('hello'));
+ $this->bag->remove('hello');
+ $this->assertNull($this->bag->get('hello'));
+
+ $this->assertEquals('be happy', $this->bag->get('always'));
+ $this->bag->remove('always');
+ $this->assertNull($this->bag->get('always'));
+
+ $this->assertEquals('drak', $this->bag->get('user.login'));
+ $this->bag->remove('user.login');
+ $this->assertNull($this->bag->get('user.login'));
+ }
+
+ public function testClear()
+ {
+ $this->bag->clear();
+ $this->assertEquals(array(), $this->bag->all());
+ }
+
+ public function attributesProvider()
+ {
+ return array(
+ array('hello', 'world', true),
+ array('always', 'be happy', true),
+ array('user.login', 'drak', true),
+ array('csrf.token', array('a' => '1234', 'b' => '4321'), true),
+ array('csrf.token/a', '1234', true),
+ array('csrf.token/b', '4321', true),
+ array('category', array('fishing' => array('first' => 'cod', 'second' => 'sole')), true),
+ array('category/fishing', array('first' => 'cod', 'second' => 'sole'), true),
+ array('category/fishing/first', 'cod', true),
+ array('category/fishing/second', 'sole', true),
+ array('user2.login', null, false),
+ array('never', null, false),
+ array('bye', null, false),
+ array('bye/for/now', null, false),
+ );
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Flash/AutoExpireFlashBagTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Flash/AutoExpireFlashBagTest.php
new file mode 100644
index 0000000000000..3b12c0eaea0ca
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Flash/AutoExpireFlashBagTest.php
@@ -0,0 +1,130 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\HttpFoundation\Session\Flash;
+
+use Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag as FlashBag;
+use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
+
+/**
+ * AutoExpireFlashBagTest
+ *
+ * @author Drak
+ */
+class AutoExpireFlashBagTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var \Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface
+ */
+ private $bag;
+
+ /**
+ * @var array
+ */
+ protected $array = array();
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->bag = new FlashBag();
+ $this->array = array('new' => array('notice' => 'A previous flash message'));
+ $this->bag->initialize($this->array);
+ }
+
+ public function tearDown()
+ {
+ $this->bag = null;
+ parent::tearDown();
+ }
+
+ public function testInitialize()
+ {
+ $bag = new FlashBag();
+ $array = array('new' => array('notice' => 'A previous flash message'));
+ $bag->initialize($array);
+ $this->assertEquals('A previous flash message', $bag->peek('notice'));
+ $array = array('new' => array(
+ 'notice' => 'Something else',
+ 'error' => 'a',
+ ));
+ $bag->initialize($array);
+ $this->assertEquals('Something else', $bag->peek('notice'));
+ $this->assertEquals('a', $bag->peek('error'));
+ }
+
+ public function testPeek()
+ {
+ $this->assertNull($this->bag->peek('non_existing'));
+ $this->assertEquals('default', $this->bag->peek('non_existing', 'default'));
+ $this->assertEquals('A previous flash message', $this->bag->peek('notice'));
+ $this->assertEquals('A previous flash message', $this->bag->peek('notice'));
+ }
+
+ public function testSet()
+ {
+ $this->bag->set('notice', 'Foo');
+ $this->assertNotEquals('Foo', $this->bag->peek('notice'));
+ }
+
+ public function testHas()
+ {
+ $this->assertFalse($this->bag->has('nothing'));
+ $this->assertTrue($this->bag->has('notice'));
+ }
+
+ public function testKeys()
+ {
+ $this->assertEquals(array('notice'), $this->bag->keys());
+ }
+
+ public function testPeekAll()
+ {
+ $array = array(
+ 'new' => array(
+ 'notice' => 'Foo',
+ 'error' => 'Bar',
+ ),
+ );
+
+ $this->bag->initialize($array);
+ $this->assertEquals(array(
+ 'notice' => 'Foo',
+ 'error' => 'Bar',
+ ), $this->bag->peekAll()
+ );
+
+ $this->assertEquals(array(
+ 'notice' => 'Foo',
+ 'error' => 'Bar',
+ ), $this->bag->peekAll()
+ );
+ }
+
+ public function testGet()
+ {
+ $this->assertNull($this->bag->get('non_existing'));
+ $this->assertEquals('default', $this->bag->get('non_existing', 'default'));
+ $this->assertEquals('A previous flash message', $this->bag->get('notice'));
+ $this->assertNull($this->bag->get('notice'));
+ }
+
+ public function testAll()
+ {
+ $this->bag->set('notice', 'Foo');
+ $this->bag->set('error', 'Bar');
+ $this->assertEquals(array(
+ 'notice' => 'A previous flash message',
+ ), $this->bag->all()
+ );
+
+ $this->assertEquals(array(), $this->bag->all());
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Flash/FlashBagTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Flash/FlashBagTest.php
new file mode 100644
index 0000000000000..3616ec9156a75
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Flash/FlashBagTest.php
@@ -0,0 +1,121 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\HttpFoundation\Session\Flash;
+
+use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
+use Symfony\Component\HttpFoundation\Session\Flash\FlashBagInterface;
+
+/**
+ * FlashBagTest
+ *
+ * @author Drak
+ */
+class FlashBagTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var \Symfony\Component\HttpFoundation\SessionFlash\FlashBagInterface
+ */
+ private $bag;
+
+ /**
+ * @var array
+ */
+ protected $array = array();
+
+ public function setUp()
+ {
+ parent::setUp();
+ $this->bag = new FlashBag();
+ $this->array = array('notice' => 'A previous flash message');
+ $this->bag->initialize($this->array);
+ }
+
+ public function tearDown()
+ {
+ $this->bag = null;
+ parent::tearDown();
+ }
+
+ public function testInitialize()
+ {
+ $bag = new FlashBag();
+ $bag->initialize($this->array);
+ $this->assertEquals($this->array, $bag->peekAll());
+ $array = array('should' => array('change'));
+ $bag->initialize($array);
+ $this->assertEquals($array, $bag->peekAll());
+ }
+
+ public function testPeek()
+ {
+ $this->assertNull($this->bag->peek('non_existing'));
+ $this->assertEquals('default', $this->bag->peek('not_existing', 'default'));
+ $this->assertEquals('A previous flash message', $this->bag->peek('notice'));
+ $this->assertEquals('A previous flash message', $this->bag->peek('notice'));
+ }
+
+ public function testGet()
+ {
+ $this->assertNull($this->bag->get('non_existing'));
+ $this->assertEquals('default', $this->bag->get('not_existing', 'default'));
+ $this->assertEquals('A previous flash message', $this->bag->get('notice'));
+ $this->assertNull($this->bag->get('notice'));
+ }
+
+ public function testAll()
+ {
+ $this->bag->set('notice', 'Foo');
+ $this->bag->set('error', 'Bar');
+ $this->assertEquals(array(
+ 'notice' => 'Foo',
+ 'error' => 'Bar'), $this->bag->all()
+ );
+
+ $this->assertEquals(array(), $this->bag->all());
+ }
+
+ public function testSet()
+ {
+ $this->bag->set('notice', 'Foo');
+ $this->bag->set('notice', 'Bar');
+ $this->assertEquals('Bar', $this->bag->peek('notice'));
+ }
+
+ public function testHas()
+ {
+ $this->assertFalse($this->bag->has('nothing'));
+ $this->assertTrue($this->bag->has('notice'));
+ }
+
+ public function testKeys()
+ {
+ $this->assertEquals(array('notice'), $this->bag->keys());
+ }
+
+ public function testPeekAll()
+ {
+ $this->bag->set('notice', 'Foo');
+ $this->bag->set('error', 'Bar');
+ $this->assertEquals(array(
+ 'notice' => 'Foo',
+ 'error' => 'Bar',
+ ), $this->bag->peekAll()
+ );
+ $this->assertTrue($this->bag->has('notice'));
+ $this->assertTrue($this->bag->has('error'));
+ $this->assertEquals(array(
+ 'notice' => 'Foo',
+ 'error' => 'Bar',
+ ), $this->bag->peekAll()
+ );
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/SessionTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/SessionTest.php
new file mode 100644
index 0000000000000..3f57670581f36
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/SessionTest.php
@@ -0,0 +1,171 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Tests\Component\HttpFoundation\Session;
+
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Flash\FlashBag;
+use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
+
+/**
+ * SessionTest
+ *
+ * @author Fabien Potencier
+ * @author Robert Schönthal
+ * @author Drak
+ */
+class SessionTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var \Symfony\Component\HttpFoundation\Session\Storage\SessionStorageInterface
+ */
+ protected $storage;
+
+ /**
+ * @var \Symfony\Component\HttpFoundation\Session\SessionInterface
+ */
+ protected $session;
+
+ public function setUp()
+ {
+ $this->storage = new MockArraySessionStorage();
+ $this->session = new Session($this->storage, new AttributeBag(), new FlashBag());
+ }
+
+ protected function tearDown()
+ {
+ $this->storage = null;
+ $this->session = null;
+ }
+
+ public function testStart()
+ {
+ $this->assertEquals('', $this->session->getId());
+ $this->assertTrue($this->session->start());
+ $this->assertNotEquals('', $this->session->getId());
+ }
+
+ public function testGet()
+ {
+ // tests defaults
+ $this->assertNull($this->session->get('foo'));
+ $this->assertEquals(1, $this->session->get('foo', 1));
+ }
+
+ /**
+ * @dataProvider setProvider
+ */
+ public function testSet($key, $value)
+ {
+ $this->session->set($key, $value);
+ $this->assertEquals($value, $this->session->get($key));
+ }
+
+ public function testReplace()
+ {
+ $this->session->replace(array('happiness' => 'be good', 'symfony' => 'awesome'));
+ $this->assertEquals(array('happiness' => 'be good', 'symfony' => 'awesome'), $this->session->all());
+ $this->session->replace(array());
+ $this->assertEquals(array(), $this->session->all());
+ }
+
+ /**
+ * @dataProvider setProvider
+ */
+ public function testAll($key, $value, $result)
+ {
+ $this->session->set($key, $value);
+ $this->assertEquals($result, $this->session->all());
+ }
+
+ /**
+ * @dataProvider setProvider
+ */
+ public function testClear($key, $value)
+ {
+ $this->session->set('hi', 'fabien');
+ $this->session->set($key, $value);
+ $this->session->clear();
+ $this->assertEquals(array(), $this->session->all());
+ }
+
+ public function setProvider()
+ {
+ return array(
+ array('foo', 'bar', array('foo' => 'bar')),
+ array('foo.bar', 'too much beer', array('foo.bar' => 'too much beer')),
+ array('great', 'symfony2 is great', array('great' => 'symfony2 is great')),
+ );
+ }
+
+ /**
+ * @dataProvider setProvider
+ */
+ public function testRemove($key, $value)
+ {
+ $this->session->set('hi.world', 'have a nice day');
+ $this->session->set($key, $value);
+ $this->session->remove($key);
+ $this->assertEquals(array('hi.world' => 'have a nice day'), $this->session->all());
+ }
+
+ public function testInvalidate()
+ {
+ $this->session->set('invalidate', 123);
+ $this->session->invalidate();
+ $this->assertEquals(array(), $this->session->all());
+ }
+
+ public function testMigrate()
+ {
+ $this->session->set('migrate', 321);
+ $this->session->migrate();
+ $this->assertEquals(321, $this->session->get('migrate'));
+ }
+
+ public function testMigrateDestroy()
+ {
+ $this->session->set('migrate', 333);
+ $this->session->migrate(true);
+ $this->assertEquals(333, $this->session->get('migrate'));
+ }
+
+ public function testSerialize()
+ {
+ $compare = serialize($this->storage);
+
+ $this->assertSame($compare, $this->session->serialize());
+
+ $this->session->unserialize($compare);
+
+ $_storage = new \ReflectionProperty(get_class($this->session), 'storage');
+ $_storage->setAccessible(true);
+
+ $this->assertEquals($_storage->getValue($this->session), $this->storage, 'storage match');
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testUnserializeException()
+ {
+ $serialized = serialize(new \ArrayObject());
+ $this->session->unserialize($serialized);
+ }
+
+ public function testGetId()
+ {
+ $this->assertEquals('', $this->session->getId());
+ $this->session->start();
+ $this->assertNotEquals('', $this->session->getId());
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php
new file mode 100644
index 0000000000000..05bc5fefb341b
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php
@@ -0,0 +1,127 @@
+
+ *
+ * These tests require separate processes.
+ *
+ * @runTestsInSeparateProcesses
+ */
+class AbstractSessionStorageTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @return AbstractSessionStorage
+ */
+ protected function getStorage()
+ {
+ $storage = new CustomHandlerSessionStorage();
+ $storage->registerBag(new AttributeBag);
+
+ return $storage;
+ }
+
+ public function testBag()
+ {
+ $storage = $this->getStorage();
+ $bag = new FlashBag();
+ $storage->registerBag($bag);
+ $this->assertSame($bag, $storage->getBag($bag->getName()));
+ }
+
+ /**
+ * @expectedException \InvalidArgumentException
+ */
+ public function testRegisterBagException()
+ {
+ $storage = $this->getStorage();
+ $storage->getBag('non_existing');
+ }
+
+ public function testGetId()
+ {
+ $storage = $this->getStorage();
+ $this->assertEquals('', $storage->getId());
+ $storage->start();
+ $this->assertNotEquals('', $storage->getId());
+ }
+
+ public function testRegenerate()
+ {
+ $storage = $this->getStorage();
+ $storage->start();
+ $id = $storage->getId();
+ $storage->getBag('attributes')->set('lucky', 7);
+ $storage->regenerate();
+ $this->assertNotEquals($id, $storage->getId());
+ $this->assertEquals(7, $storage->getBag('attributes')->get('lucky'));
+
+ }
+
+ public function testRegenerateDestroy()
+ {
+ $storage = $this->getStorage();
+ $storage->start();
+ $id = $storage->getId();
+ $storage->getBag('attributes')->set('legs', 11);
+ $storage->regenerate(true);
+ $this->assertNotEquals($id, $storage->getId());
+ $this->assertEquals(11, $storage->getBag('attributes')->get('legs'));
+ }
+
+ public function testCustomSaveHandlers()
+ {
+ $storage = new CustomHandlerSessionStorage();
+ $this->assertEquals('user', ini_get('session.save_handler'));
+ }
+
+ public function testNativeSaveHandlers()
+ {
+ $storage = new ConcreteSessionStorage();
+ $this->assertNotEquals('user', ini_get('session.save_handler'));
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockArraySessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockArraySessionStorageTest.php
new file mode 100644
index 0000000000000..4611457940589
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockArraySessionStorageTest.php
@@ -0,0 +1,90 @@
+
+ */
+class MockArraySessionStorageTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var MockArraySessionStorage
+ */
+ private $storage;
+
+ /**
+ * @var array
+ */
+ private $attributes;
+
+ /**
+ * @var array
+ */
+ private $flashes;
+
+ private $data;
+
+ protected function setUp()
+ {
+ $this->attributes = new AttributeBag();
+ $this->flashes = new FlashBag();
+
+ $this->data = array(
+ $this->attributes->getStorageKey() => array('foo' => 'bar'),
+ $this->flashes->getStorageKey() => array('notice' => 'hello'),
+ );
+
+ $this->storage = new MockArraySessionStorage();
+ $this->storage->registerBag($this->flashes);
+ $this->storage->registerBag($this->attributes);
+ $this->storage->setSessionData($this->data);
+ }
+
+ protected function tearDown()
+ {
+ $this->data = null;
+ $this->flashes = null;
+ $this->attributes = null;
+ $this->storage = null;
+ }
+
+ public function testStart()
+ {
+ $this->assertEquals('', $this->storage->getId());
+ $this->storage->start();
+ $id = $this->storage->getId();
+ $this->assertNotEquals('', $id);
+ $this->storage->start();
+ $this->assertEquals($id, $this->storage->getId());
+ }
+
+ public function testRegenerate()
+ {
+ $this->storage->start();
+ $id = $this->storage->getId();
+ $this->storage->regenerate();
+ $this->assertNotEquals($id, $this->storage->getId());
+ $this->assertEquals(array('foo' => 'bar'), $this->storage->getBag('attributes')->all());
+ $this->assertEquals(array('notice' => 'hello'), $this->storage->getBag('flashes')->peekAll());
+
+ $id = $this->storage->getId();
+ $this->storage->regenerate(true);
+ $this->assertNotEquals($id, $this->storage->getId());
+ $this->assertEquals(array('foo' => 'bar'), $this->storage->getBag('attributes')->all());
+ $this->assertEquals(array('notice' => 'hello'), $this->storage->getBag('flashes')->peekAll());
+ }
+
+ public function testGetId()
+ {
+ $this->assertEquals('', $this->storage->getId());
+ $this->storage->start();
+ $this->assertNotEquals('', $this->storage->getId());
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockFileSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockFileSessionStorageTest.php
new file mode 100644
index 0000000000000..770bcda8f00ec
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockFileSessionStorageTest.php
@@ -0,0 +1,105 @@
+
+ */
+class MockFileSessionStorageTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @var string
+ */
+ private $sessionDir;
+
+ /**
+ * @var FileMockSessionStorage
+ */
+ protected $storage;
+
+ protected function setUp()
+ {
+ $this->sessionDir = sys_get_temp_dir().'/sf2test';
+ $this->storage = $this->getStorage();
+ }
+
+ protected function tearDown()
+ {
+ $this->sessionDir = null;
+ $this->storage = null;
+ array_map('unlink', glob($this->sessionDir.'/*.session'));
+ if (is_dir($this->sessionDir)) {
+ rmdir($this->sessionDir);
+ }
+ }
+
+ public function testStart()
+ {
+ $this->assertEquals('', $this->storage->getId());
+ $this->assertTrue($this->storage->start());
+ $id = $this->storage->getId();
+ $this->assertNotEquals('', $this->storage->getId());
+ $this->assertTrue($this->storage->start());
+ $this->assertEquals($id, $this->storage->getId());
+ }
+
+ public function testRegenerate()
+ {
+ $this->storage->start();
+ $this->storage->getBag('attributes')->set('regenerate', 1234);
+ $this->storage->regenerate();
+ $this->assertEquals(1234, $this->storage->getBag('attributes')->get('regenerate'));
+ $this->storage->regenerate(true);
+ $this->assertEquals(1234, $this->storage->getBag('attributes')->get('regenerate'));
+ }
+
+ public function testGetId()
+ {
+ $this->assertEquals('', $this->storage->getId());
+ $this->storage->start();
+ $this->assertNotEquals('', $this->storage->getId());
+ }
+
+ public function testSave()
+ {
+ $this->storage->start();
+ $this->assertNotEquals('108', $this->storage->getBag('attributes')->get('new'));
+ $this->assertFalse($this->storage->getBag('flashes')->has('newkey'));
+ $this->storage->getBag('attributes')->set('new', '108');
+ $this->storage->getBag('flashes')->set('newkey', 'test');
+ $this->storage->save();
+
+ $storage = $this->getStorage();
+ $storage->start();
+ $this->assertEquals('108', $storage->getBag('attributes')->get('new'));
+ $this->assertTrue($storage->getBag('flashes')->has('newkey'));
+ $this->assertEquals('test', $storage->getBag('flashes')->peek('newkey'));
+ }
+
+ public function testMultipleInstances()
+ {
+ $storage1 = $this->getStorage();
+ $storage1->start();
+ $storage1->getBag('attributes')->set('foo', 'bar');
+ $storage1->save();
+
+ $storage2 = $this->getStorage();
+ $storage2->start();
+ $this->assertEquals('bar', $storage2->getBag('attributes')->get('foo'), 'values persist between instances');
+ }
+
+ private function getStorage(array $options = array())
+ {
+ $storage = new MockFileSessionStorage($this->sessionDir, $options);
+ $storage->registerBag(new FlashBag);
+ $storage->registerBag(new AttributeBag);
+
+ return $storage;
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php
new file mode 100644
index 0000000000000..df3ef95cbf799
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php
@@ -0,0 +1,23 @@
+
+ *
+ * @runTestsInSeparateProcesses
+ */
+class NativeFileSessionStorageTest extends \PHPUnit_Framework_TestCase
+{
+ public function testSaveHandlers()
+ {
+ $storage = new NativeFileSessionStorage(sys_get_temp_dir(), array('name' => 'TESTING'));
+ $this->assertEquals('files', ini_get('session.save_handler'));
+ $this->assertEquals(sys_get_temp_dir(), ini_get('session.save_path'));
+ $this->assertEquals('TESTING', ini_get('session.name'));
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php
new file mode 100644
index 0000000000000..4274ed5bd1496
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php
@@ -0,0 +1,27 @@
+
+ *
+ * @runTestsInSeparateProcesses
+ */
+class NativeMemcacheSessionStorageTest extends \PHPUnit_Framework_TestCase
+{
+ public function testSaveHandlers()
+ {
+ if (!extension_loaded('memcache')) {
+ $this->markTestSkipped('Skipped tests SQLite extension is not present');
+ }
+
+ $storage = new NativeMemcacheSessionStorage('tcp://127.0.0.1:11211?persistent=0', array('name' => 'TESTING'));
+ $this->assertEquals('memcache', ini_get('session.save_handler'));
+ $this->assertEquals('tcp://127.0.0.1:11211?persistent=0', ini_get('session.save_path'));
+ $this->assertEquals('TESTING', ini_get('session.name'));
+ }
+}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php
new file mode 100644
index 0000000000000..c0a12aa2b4d15
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php
@@ -0,0 +1,32 @@
+
+ *
+ * @runTestsInSeparateProcesses
+ */
+class NativeMemcachedSessionStorageTest extends \PHPUnit_Framework_TestCase
+{
+ public function testSaveHandlers()
+ {
+ if (!extension_loaded('memcached')) {
+ $this->markTestSkipped('Skipped tests SQLite extension is not present');
+ }
+
+ // test takes too long if memcached server is not running
+ ini_set('memcached.sess_locking', '0');
+
+ $storage = new NativeMemcachedSessionStorage('127.0.0.1:11211', array('name' => 'TESTING'));
+
+ $this->assertEquals('memcached', ini_get('session.save_handler'));
+ $this->assertEquals('127.0.0.1:11211', ini_get('session.save_path'));
+ $this->assertEquals('TESTING', ini_get('session.name'));
+ }
+}
+
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php
new file mode 100644
index 0000000000000..b1700326b1d8a
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php
@@ -0,0 +1,28 @@
+
+ *
+ * @runTestsInSeparateProcesses
+ */
+class NativeSqliteSessionStorageTest extends \PHPUnit_Framework_TestCase
+{
+ public function testSaveHandlers()
+ {
+ if (!extension_loaded('sqlite')) {
+ $this->markTestSkipped('Skipped tests SQLite extension is not present');
+ }
+
+ $storage = new NativeSqliteSessionStorage(sys_get_temp_dir().'/sqlite.db', array('name' => 'TESTING'));
+ $this->assertEquals('sqlite', ini_get('session.save_handler'));
+ $this->assertEquals(sys_get_temp_dir().'/sqlite.db', ini_get('session.save_path'));
+ $this->assertEquals('TESTING', ini_get('session.name'));
+ }
+}
+
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php
new file mode 100644
index 0000000000000..66599f68b3cef
--- /dev/null
+++ b/tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php
@@ -0,0 +1,42 @@
+
+ *
+ * @runTestsInSeparateProcesses
+ */
+class NullSessionStorageTest extends \PHPUnit_Framework_TestCase
+{
+ public function testSaveHandlers()
+ {
+ $storage = new NullSessionStorage();
+ $this->assertEquals('user', ini_get('session.save_handler'));
+ }
+
+ public function testSession()
+ {
+ session_id('nullsessionstorage');
+ $storage = new NullSessionStorage();
+ $session = new Session($storage);
+ $this->assertNull($session->get('something'));
+ $session->set('something', 'unique');
+ $this->assertEquals('unique', $session->get('something'));
+ }
+
+ public function testNothingIsPersisted()
+ {
+ session_id('nullsessionstorage');
+ $storage = new NullSessionStorage();
+ $session = new Session($storage);
+ $session->start();
+ $this->assertEquals('nullsessionstorage', $session->getId());
+ $this->assertNull($session->get('something'));
+ }
+}
+
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/SessionStorage/FilesystemSessionStorageTest.php b/tests/Symfony/Tests/Component/HttpFoundation/SessionStorage/FilesystemSessionStorageTest.php
deleted file mode 100644
index 060cb0e913e6e..0000000000000
--- a/tests/Symfony/Tests/Component/HttpFoundation/SessionStorage/FilesystemSessionStorageTest.php
+++ /dev/null
@@ -1,104 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Tests\Component\HttpFoundation\SessionStorage;
-
-use Symfony\Component\HttpFoundation\SessionStorage\FilesystemSessionStorage;
-
-class FilesystemSessionStorageTest extends \PHPUnit_Framework_TestCase
-{
- private $path;
-
- protected function setUp()
- {
- $this->path = sys_get_temp_dir().'/sf2/session_test';
- if (!file_exists($this->path)) {
- mkdir($this->path, 0777, true);
- }
- }
-
- protected function tearDown()
- {
- array_map('unlink', glob($this->path.'/*.session'));
- rmdir($this->path);
-
- $this->path = null;
- }
-
- public function testMultipleInstances()
- {
- $storage1 = new FilesystemSessionStorage($this->path);
- $storage1->start();
- $storage1->write('foo', 'bar');
-
- $storage2 = new FilesystemSessionStorage($this->path);
- $storage2->start();
- $this->assertEquals('bar', $storage2->read('foo'), 'values persist between instances');
- }
-
- public function testGetIdThrowsErrorBeforeStart()
- {
- $this->setExpectedException('RuntimeException');
-
- $storage = new FilesystemSessionStorage($this->path);
- $storage->getId();
- }
-
- public function testGetIdWorksAfterStart()
- {
- $storage = new FilesystemSessionStorage($this->path);
- $storage->start();
- $storage->getId();
- }
-
- public function testGetIdSetByOptions()
- {
- $previous = ini_get('session.use_cookies');
-
- ini_set('session.use_cookies', false);
-
- $storage = new FilesystemSessionStorage($this->path, array('id' => 'symfony2-sessionId'));
- $storage->start();
-
- $this->assertEquals('symfony2-sessionId', $storage->getId());
-
- ini_set('session.use_cookies', $previous);
- }
-
- public function testRemoveVariable()
- {
- $storage = new FilesystemSessionStorage($this->path);
- $storage->start();
-
- $storage->write('foo', 'bar');
-
- $this->assertEquals('bar', $storage->read('foo'));
-
- $storage->remove('foo', 'bar');
-
- $this->assertNull($storage->read('foo'));
- }
-
- public function testRegenerate()
- {
- $storage = new FilesystemSessionStorage($this->path);
- $storage->start();
- $storage->write('foo', 'bar');
-
- $storage->regenerate();
-
- $this->assertEquals('bar', $storage->read('foo'));
-
- $storage->regenerate(true);
-
- $this->assertNull($storage->read('foo'));
- }
-}
diff --git a/tests/Symfony/Tests/Component/HttpFoundation/SessionTest.php b/tests/Symfony/Tests/Component/HttpFoundation/SessionTest.php
deleted file mode 100644
index 8318101e665d1..0000000000000
--- a/tests/Symfony/Tests/Component/HttpFoundation/SessionTest.php
+++ /dev/null
@@ -1,232 +0,0 @@
-
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Tests\Component\HttpFoundation;
-
-use Symfony\Component\HttpFoundation\Session;
-use Symfony\Component\HttpFoundation\SessionStorage\ArraySessionStorage;
-
-/**
- * SessionTest
- *
- * @author Fabien Potencier
- * @author Robert Schönthal
- */
-class SessionTest extends \PHPUnit_Framework_TestCase
-{
- protected $storage;
- protected $session;
-
- public function setUp()
- {
- $this->storage = new ArraySessionStorage();
- $this->session = $this->getSession();
- }
-
- protected function tearDown()
- {
- $this->storage = null;
- $this->session = null;
- }
-
- public function testFlash()
- {
- $this->session->clearFlashes();
-
- $this->assertSame(array(), $this->session->getFlashes());
-
- $this->assertFalse($this->session->hasFlash('foo'));
-
- $this->session->setFlash('foo', 'bar');
-
- $this->assertTrue($this->session->hasFlash('foo'));
- $this->assertSame('bar', $this->session->getFlash('foo'));
-
- $this->session->removeFlash('foo');
-
- $this->assertFalse($this->session->hasFlash('foo'));
-
- $flashes = array('foo' => 'bar', 'bar' => 'foo');
-
- $this->session->setFlashes($flashes);
-
- $this->assertSame($flashes, $this->session->getFlashes());
- }
-
- public function testFlashesAreFlushedWhenNeeded()
- {
- $this->session->setFlash('foo', 'bar');
- $this->session->save();
-
- $this->session = $this->getSession();
- $this->assertTrue($this->session->hasFlash('foo'));
- $this->session->save();
-
- $this->session = $this->getSession();
- $this->assertFalse($this->session->hasFlash('foo'));
- }
-
- public function testAll()
- {
- $this->assertFalse($this->session->has('foo'));
- $this->assertNull($this->session->get('foo'));
-
- $this->session->set('foo', 'bar');
-
- $this->assertTrue($this->session->has('foo'));
- $this->assertSame('bar', $this->session->get('foo'));
-
- $this->session = $this->getSession();
-
- $this->session->remove('foo');
- $this->session->set('foo', 'bar');
-
- $this->session->remove('foo');
-
- $this->assertFalse($this->session->has('foo'));
-
- $attrs = array('foo' => 'bar', 'bar' => 'foo');
-
- $this->session = $this->getSession();
-
- $this->session->replace($attrs);
-
- $this->assertSame($attrs, $this->session->all());
-
- $this->session->clear();
-
- $this->assertSame(array(), $this->session->all());
- }
-
- public function testMigrateAndInvalidate()
- {
- $this->session->set('foo', 'bar');
- $this->session->setFlash('foo', 'bar');
-
- $this->assertSame('bar', $this->session->get('foo'));
- $this->assertSame('bar', $this->session->getFlash('foo'));
-
- $this->session->migrate();
-
- $this->assertSame('bar', $this->session->get('foo'));
- $this->assertSame('bar', $this->session->getFlash('foo'));
-
- $this->session = $this->getSession();
- $this->session->invalidate();
-
- $this->assertSame(array(), $this->session->all());
- $this->assertSame(array(), $this->session->getFlashes());
- }
-
- public function testSerialize()
- {
- $this->session = new Session($this->storage);
-
- $compare = serialize($this->storage);
-
- $this->assertSame($compare, $this->session->serialize());
-
- $this->session->unserialize($compare);
-
- $_storage = new \ReflectionProperty(get_class($this->session), 'storage');
- $_storage->setAccessible(true);
-
- $this->assertEquals($_storage->getValue($this->session), $this->storage, 'storage match');
- }
-
- public function testSave()
- {
- $this->storage = new ArraySessionStorage();
- $this->session = new Session($this->storage);
- $this->session->set('foo', 'bar');
-
- $this->session->save();
- $compare = array('_symfony2' => array('attributes' => array('foo' => 'bar'), 'flashes' => array()));
-
- $r = new \ReflectionObject($this->storage);
- $p = $r->getProperty('data');
- $p->setAccessible(true);
-
- $this->assertSame($p->getValue($this->storage), $compare);
- }
-
- public function testGetId()
- {
- $this->assertNull($this->session->getId());
- }
-
- public function testStart()
- {
- $this->session->start();
-
- $this->assertSame(array(), $this->session->getFlashes());
- $this->assertSame(array(), $this->session->all());
- }
-
- public function testSavedOnDestruct()
- {
- $this->session->set('foo', 'bar');
-
- $this->session->__destruct();
-
- $expected = array(
- 'attributes'=>array('foo'=>'bar'),
- 'flashes'=>array(),
- );
- $saved = $this->storage->read('_symfony2');
- $this->assertSame($expected, $saved);
- }
-
- public function testSavedOnDestructAfterManualSave()
- {
- $this->session->set('foo', 'nothing');
- $this->session->save();
- $this->session->set('foo', 'bar');
-
- $this->session->__destruct();
-
- $expected = array(
- 'attributes'=>array('foo'=>'bar'),
- 'flashes'=>array(),
- );
- $saved = $this->storage->read('_symfony2');
- $this->assertSame($expected, $saved);
- }
-
- public function testStorageRegenerate()
- {
- $this->storage->write('foo', 'bar');
-
- $this->assertTrue($this->storage->regenerate());
-
- $this->assertEquals('bar', $this->storage->read('foo'));
-
- $this->assertTrue($this->storage->regenerate(true));
-
- $this->assertNull($this->storage->read('foo'));
- }
-
- public function testStorageRemove()
- {
- $this->storage->write('foo', 'bar');
-
- $this->assertEquals('bar', $this->storage->read('foo'));
-
- $this->storage->remove('foo');
-
- $this->assertNull($this->storage->read('foo'));
- }
-
- protected function getSession()
- {
- return new Session($this->storage);
- }
-}
diff --git a/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php b/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php
index cf12ec79fc7f4..ecce76ec5eef4 100644
--- a/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php
+++ b/tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php
@@ -33,7 +33,7 @@ public function testDefaultLocaleWithSession()
session_name('foo');
$request->cookies->set('foo', 'value');
- $session = $this->getMock('Symfony\Component\HttpFoundation\Session', array('get'), array(), '', false);
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('get'), array(), '', false);
$session->expects($this->once())->method('get')->will($this->returnValue('es'));
$request->setSession($session);
@@ -55,7 +55,7 @@ public function testLocaleFromRequestAttribute()
$event = $this->getEvent($request);
// also updates the session _locale value
- $session = $this->getMock('Symfony\Component\HttpFoundation\Session', array('set', 'get'), array(), '', false);
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('set', 'get'), array(), '', false);
$session->expects($this->once())->method('set')->with('_locale', 'es');
$session->expects($this->once())->method('get')->with('_locale')->will($this->returnValue('es'));
$request->setSession($session);
diff --git a/tests/Symfony/Tests/Component/Security/Http/Firewall/ContextListenerTest.php b/tests/Symfony/Tests/Component/Security/Http/Firewall/ContextListenerTest.php
index dfbcd79e7faf9..5c810062ef84f 100644
--- a/tests/Symfony/Tests/Component/Security/Http/Firewall/ContextListenerTest.php
+++ b/tests/Symfony/Tests/Component/Security/Http/Firewall/ContextListenerTest.php
@@ -4,8 +4,8 @@
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\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
@@ -63,7 +63,7 @@ public function testOnKernelResponseWillRemoveSession()
protected function runSessionOnKernelResponse($newToken, $original = null)
{
- $session = new Session(new ArraySessionStorage());
+ $session = new Session(new MockArraySessionStorage());
if ($original !== null) {
$session->set('_security_session', $original);
diff --git a/tests/Symfony/Tests/Component/Security/Http/Logout/SessionLogoutHandlerTest.php b/tests/Symfony/Tests/Component/Security/Http/Logout/SessionLogoutHandlerTest.php
index 05df6cf8f5b96..9f38e4c9c122d 100644
--- a/tests/Symfony/Tests/Component/Security/Http/Logout/SessionLogoutHandlerTest.php
+++ b/tests/Symfony/Tests/Component/Security/Http/Logout/SessionLogoutHandlerTest.php
@@ -22,7 +22,7 @@ public function testLogout()
$request = $this->getMock('Symfony\Component\HttpFoundation\Request');
$response = new Response();
- $session = $this->getMock('Symfony\Component\HttpFoundation\Session', array(), array(), '', false);
+ $session = $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array(), array(), '', false);
$request
->expects($this->once())
pFad - Phonifier reborn
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy