Skip to content

Loading…

[2.1][HttpFoundation] Refactor session handling and flash messages #2853

Merged
merged 31 commits into from
Commits on Feb 11, 2012
  1. [HttpFoundation] Added AttributesInterface and AttributesBagInterface…

    Drak committed
    … and concrete implementations.
    
    This commit outsources session attribute storage to it's own class.
    There are two concrete implementations, one with structured namespace storage and the other
    without.
  2. [HttpFoundation] Added FlashBagInterface and concrete implementation.

    Drak committed
    This commit outsources the flash message processing to it's own interface.
    
    Overall flash messages now can have multiple flash types and each type can
    store multiple messages.  For convenience there are now four flash types
    by default, INFO, NOTICE, WARNING and ERROR.
    
    There are two concrete implementations: one preserving the old behaviour of
    flash messages expiring exactly after one page load, regardless of being
    displayed or not; and the other where flash messages persist until explicitly
    popped.
  3. [HttpFoundation] Introduced session storage base class and interfaces.

    Drak committed
    Session object now implements SessionInterface to make it more portable.
    
    AbstractSessionStorage and SessionSaveHandlerInterface now makes implementation
    of session storage drivers simple and easy to write for both custom save handlers
    and native php save handlers and respect the PHP session workflow.
  4. [HttpFoundation] Added drivers for PHP native session save handlers, …

    Drak committed
    …files, sqlite, memcache and memcached.
  5. [FrameworkBundle] Refactored code for changes to HttpFoundation compo…

    Drak committed
    …nent.
    
    Native PHP sessions stored to file are done with session.storage.native_file
    Functional testing is done with session.storage.mock_file
    
    Default flash message implementation done with FlashBag (session.flash_bag)
    Default attribute storage implementation with AttributeBag (session.attribute_bag)
    
    Services added: session.storage.native_file, session.storage.native_memcache, session.storage.native_memcache,
    session.storage.native_sqlite, session.storage.memcache, session.storage.memcached, session.storage.null,
    session.storage.mock_file, session.flash_bag, session.attribute_bag
    
    Services removed: session.storage.native, session.storage.filesystem
  6. [DoctribeBridge][SecurityBundle][WebProfiler] Refactor code for HttpF…

    Drak committed
    …oundation changes.
  7. [HttpFoundation] Refactor for DRY code.

    Drak committed
    Rename ArraySessionStorage to make it clear the session is a mock for testing purposes only.
    Has BC class for ArraySessionStorage
    Added sanity check when starting the session.
    Fixed typos and incorrect php extension test method
    session_module_name() also sets session.save_handler, so must use extension_loaded() to check if module exist
    or not.
    Respect autostart settings.
  8. Fixed formatting.

    Drak committed
  9. [HttpFoundation] Free bags from session storage and move classes to t…

    Drak committed
    …heir own namespaces.
  10. [HttpFoundation] Simplify session storage class names now we have a s…

    Drak committed
    …eparate namespace for sessions.
  11. [HttpFoundation] Add back get defaults and small clean-up.

    Drak committed
    Changed read-only method names from get*() to peek*()
    
    Typo
  12. [HttpFoundation] Remove constants from FlashBagInterface

    Drak committed
    As requested by fabpot.
    Corrected a few mistakes in the documentation.
  13. @fabpot
  14. @fabpot

    removed unused use statements

    fabpot committed
  15. @fabpot
  16. @fabpot

    reverted 5b7ef116507fa05e1042065f61a50733c19116cb (Simplify session

    fabpot committed
    storage class names now we have a separate namespace for sessions)
  17. @fabpot

    [HttpFoundation] removed configuration for session storages in sessio…

    fabpot committed
    …n.xml as we cannot provide a way to configure them (like before this PR anyway)
  18. @fabpot
  19. @fabpot
  20. @fabpot

    updated CHANGELOG for 2.1

    fabpot committed
  21. @fabpot
  22. Correct instanceof condition.

    Drak committed
  23. Docblocks.

    Drak committed
  24. @fabpot
Showing with 4,191 additions and 1,421 deletions.
  1. +28 −0 CHANGELOG-2.1.md
  2. +72 −5 UPGRADE-2.1.md
  3. +25 −33 src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionStorage.php
  4. +1 −1 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
  5. +1 −1 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
  6. +0 −1 src/Symfony/Bundle/FrameworkBundle/EventListener/TestSessionListener.php
  7. +18 −5 src/Symfony/Bundle/FrameworkBundle/Resources/config/session.xml
  8. +1 −1 src/Symfony/Bundle/FrameworkBundle/Templating/GlobalVariables.php
  9. +3 −3 src/Symfony/Bundle/FrameworkBundle/Templating/Helper/SessionHelper.php
  10. +1 −1 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/full.php
  11. +1 −1 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml
  12. +1 −1 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/full.yml
  13. +1 −1 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
  14. +1 −1 src/Symfony/Bundle/FrameworkBundle/Tests/EventListener/TestSessionListenerTest.php
  15. +3 −3 ...ymfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php
  16. +1 −1 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/config/framework.yml
  17. +11 −10 src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/SessionHelperTest.php
  18. +3 −3 src/Symfony/Bundle/FrameworkBundle/Tests/Templating/PhpEngineTest.php
  19. +1 −1 src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/config/framework.yml
  20. +3 −3 src/Symfony/Bundle/TwigBundle/Tests/TwigEngineTest.php
  21. +4 −3 src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php
  22. +5 −3 src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php
  23. +1 −1 src/Symfony/Bundle/WebProfilerBundle/Tests/EventListener/WebDebugToolbarListenerTest.php
  24. +1 −1 src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProvider.php
  25. +6 −4 src/Symfony/Component/HttpFoundation/Request.php
  26. +0 −358 src/Symfony/Component/HttpFoundation/Session.php
  27. +137 −0 src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php
  28. +70 −0 src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBagInterface.php
  29. +184 −0 src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php
  30. +174 −0 src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php
  31. +158 −0 src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php
  32. +85 −0 src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php
  33. +318 −0 src/Symfony/Component/HttpFoundation/Session/Session.php
  34. +48 −0 src/Symfony/Component/HttpFoundation/Session/SessionBagInterface.php
  35. +108 −0 src/Symfony/Component/HttpFoundation/Session/SessionInterface.php
  36. +339 −0 src/Symfony/Component/HttpFoundation/Session/Storage/AbstractSessionStorage.php
  37. +136 −0 src/Symfony/Component/HttpFoundation/Session/Storage/MemcacheSessionStorage.php
  38. +137 −0 src/Symfony/Component/HttpFoundation/Session/Storage/MemcachedSessionStorage.php
  39. +124 −0 src/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php
  40. +136 −0 src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php
  41. +59 −0 src/Symfony/Component/HttpFoundation/Session/Storage/NativeFileSessionStorage.php
  42. +77 −0 src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorage.php
  43. +76 −0 src/Symfony/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorage.php
  44. +54 −0 src/Symfony/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorage.php
  45. +74 −0 src/Symfony/Component/HttpFoundation/Session/Storage/NullSessionStorage.php
  46. +31 −76 src/Symfony/Component/HttpFoundation/{SessionStorage → Session/Storage}/PdoSessionStorage.php
  47. +157 −0 src/Symfony/Component/HttpFoundation/Session/Storage/SessionSaveHandlerInterface.php
  48. +92 −0 src/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php
  49. +0 −81 src/Symfony/Component/HttpFoundation/SessionStorage/ArraySessionStorage.php
  50. +0 −192 src/Symfony/Component/HttpFoundation/SessionStorage/FilesystemSessionStorage.php
  51. +0 −180 src/Symfony/Component/HttpFoundation/SessionStorage/NativeSessionStorage.php
  52. +0 −97 src/Symfony/Component/HttpFoundation/SessionStorage/SessionStorageInterface.php
  53. +1 −1 tests/Symfony/Tests/Component/Form/Extension/Csrf/CsrfProvider/SessionCsrfProviderTest.php
  54. +4 −6 tests/Symfony/Tests/Component/HttpFoundation/RequestTest.php
  55. +155 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Attribute/AttributeBagTest.php
  56. +162 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBagTest.php
  57. +130 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Flash/AutoExpireFlashBagTest.php
  58. +121 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Flash/FlashBagTest.php
  59. +171 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/SessionTest.php
  60. +127 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/AbstractSessionStorageTest.php
  61. +90 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockArraySessionStorageTest.php
  62. +105 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/MockFileSessionStorageTest.php
  63. +23 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeFileSessionStorageTest.php
  64. +27 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcacheSessionStorageTest.php
  65. +32 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeMemcachedSessionStorageTest.php
  66. +28 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NativeSqliteSessionStorageTest.php
  67. +42 −0 tests/Symfony/Tests/Component/HttpFoundation/Session/Storage/NullSessionStorageTest.php
  68. +0 −104 tests/Symfony/Tests/Component/HttpFoundation/SessionStorage/FilesystemSessionStorageTest.php
  69. +0 −232 tests/Symfony/Tests/Component/HttpFoundation/SessionTest.php
  70. +2 −2 tests/Symfony/Tests/Component/HttpKernel/EventListener/LocaleListenerTest.php
  71. +3 −3 tests/Symfony/Tests/Component/Security/Http/Firewall/ContextListenerTest.php
  72. +1 −1 tests/Symfony/Tests/Component/Security/Http/Logout/SessionLogoutHandlerTest.php
View
28 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
View
77 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):
+
+ <?php if ($view['session']->hasFlash('notice')): ?>
+ <div class="flash-notice">
+ <?php echo $view['session']->getFlash('notice') ?>
+ </div>
+ <?php endif; ?>
+
+ After (PHP):
+
+ <?php if ($view['session']->getFlashBag()->has('notice')): ?>
+ <div class="flash-notice">
+ <?php echo $view['session']->getFlashBag()->get('notice') ?>
+ </div>
+ <?php endif; ?>
@stof Symfony member
stof added a note

this is wrong. $view['session'] is not the Session object in the PHP templates but the SessionHelper which is BC.

The Session object is available through $app->getSession() (equivalent to the Twig way to access it)

@fabpot Symfony member
fabpot added a note

fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+
+ If you wanted to process all flash types you could also make use of the `getFlashBag()->all()` API:
+
+ <?php foreach ($view['session']->getFlashBag()->all() as $type => $flash): ?>
+ <div class="flash-$type">
+ <?php echo $flash; ?>
+ </div>
+ <?php endforeach; ?>
+
+ Before (Twig):
+
+ {% if app.session.hasFlash('notice') %}
+ <div class="flash-notice">
+ {{ app.session.flash('notice') }}
+ </div>
+ {% endif %}
+
+ After (Twig):
+
+ {% if app.session.flashes.has('notice') %}
@stof Symfony member
stof added a note

@fabpot shouldn't it be flashBag instead of flashes as you renamed it ?

@fabpot Symfony member
fabpot added a note

fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
+ <div class="flash-notice">
+ {{ app.session.flashes.get('notice') }}
+ </div>
+ {% endif %}
+
+ Again you can process all flash messages in one go with
+
+ {% for type, flashMessage in app.session.flashes.all() %}
+ <div class="flash-{{ type }}">
+ {{ flashMessage }}
+ </div>
+ {% 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`
View
58 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 <fabien@symfony.com>
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
-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;
View
2 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()
View
2 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',
@stof Symfony member
stof added a note

shouldn't you add the abstract storage too ?

@fabpot Symfony member
fabpot added a note

added. thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
$container->getDefinition('session')->getClass(),
));
View
1 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();
View
23 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">
<parameters>
- <parameter key="session.class">Symfony\Component\HttpFoundation\Session</parameter>
- <parameter key="session.storage.native.class">Symfony\Component\HttpFoundation\SessionStorage\NativeSessionStorage</parameter>
- <parameter key="session.storage.filesystem.class">Symfony\Component\HttpFoundation\SessionStorage\FilesystemSessionStorage</parameter>
+ <parameter key="session.class">Symfony\Component\HttpFoundation\Session\Session</parameter>
+ <parameter key="session.flashbag.class">Symfony\Component\HttpFoundation\Session\Flash\AutoExpireFlashBag</parameter>
+ <parameter key="session.attribute_bag.class">Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag</parameter>
+ <parameter key="session.storage.native_file.class">Symfony\Component\HttpFoundation\Session\Storage\NativeFileSessionStorage</parameter>
+ <parameter key="session.storage.mock_file.class">Symfony\Component\HttpFoundation\Session\Storage\MockFileSessionStorage</parameter>
<parameter key="session_listener.class">Symfony\Bundle\FrameworkBundle\EventListener\SessionListener</parameter>
</parameters>
<services>
<service id="session" class="%session.class%">
<argument type="service" id="session.storage" />
+ <argument type="service" id="session.attribute_bag" />
+ <argument type="service" id="session.flash_bag" />
</service>
- <service id="session.storage.native" class="%session.storage.native.class%" public="false">
+ <service id="session.flash_bag" class="%session.flashbag.class%" public="false" />
+
+ <service id="session.attribute_bag" class="%session.attribute_bag.class%" public="false" />
+
+ <service id="session.storage.mock_file" class="%session.storage.mock_file.class%" public="false">
+ <argument>%kernel.cache_dir%/sessions</argument>
<argument>%session.storage.options%</argument>
</service>
- <service id="session.storage.filesystem" class="%session.storage.filesystem.class%" public="false">
+ <service id="session.storage.native_file" class="%session.storage.native_file.class%" public="false">
<argument>%kernel.cache_dir%/sessions</argument>
<argument>%session.storage.options%</argument>
</service>
@@ -29,5 +38,9 @@
<tag name="kernel.event_subscriber" />
<argument type="service" id="service_container" />
</service>
+
+ <!-- for BC -->
+ <service id="session.storage.native" alias="session.storage.native_file" />
+ <service id="session.storage.filesystem" alias="session.storage.mock_file" />
</services>
</container>
View
2 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()
{
View
6 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);
}
/**
View
2 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' => '/',
View
2 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/full.xml
@@ -12,7 +12,7 @@
<framework:esi enabled="true" />
<framework:profiler only-exceptions="true" />
<framework:router resource="%kernel.root_dir%/config/routing.xml" type="xml" />
- <framework:session auto-start="true" storage-id="session.storage.native" name="_SYMFONY" lifetime="86400" path="/" domain="example.com" secure="true" httponly="true" />
+ <framework:session auto-start="true" storage-id="session.storage.native_file" name="_SYMFONY" lifetime="86400" path="/" domain="example.com" secure="true" httponly="true" />
<framework:templating assets-version="SomeVersionScheme" cache="/path/to/cache" >
<framework:loader>loader.foo</framework:loader>
<framework:loader>loader.bar</framework:loader>
View
2 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: /
View
2 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']);
View
2 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();
}
View
6 ...undle/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.';
}
View
2 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 }
View
21 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()
View
6 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);
View
2 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 }
View
6 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);
View
7 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) {
View
8 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'))));
View
2 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'),
View
2 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
View
10 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;
}
View
358 src/Symfony/Component/HttpFoundation/Session.php
@@ -1,358 +0,0 @@
-<?php
-
-/*
- * This file is part of the Symfony package.
- *
- * (c) Fabien Potencier <fabien@symfony.com>
- *
- * For the full copyright and license information, please view the LICENSE
- * file that was distributed with this source code.
- */
-
-namespace Symfony\Component\HttpFoundation;
-
-use Symfony\Component\HttpFoundation\SessionStorage\SessionStorageInterface;
-
-/**
- * Session.
- *
- * @author Fabien Potencier <fabien@symfony.com>
- *
- * @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;
- }
-}
View
137 src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php
@@ -0,0 +1,137 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\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;
+ }
+}
View
70 src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBagInterface.php
@@ -0,0 +1,70 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Attribute;
+
+use Symfony\Component\HttpFoundation\Session\SessionBagInterface;
+
+/**
+ * Attributes store.
+ *
+ * @author Drak <drak@zikula.org>
+ */
+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);
+}
View
184 src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php
@@ -0,0 +1,184 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Attribute;
+
+/**
+ * This class provides structured storage of session attributes using
+ * a name spacing character in the key.
+ *
+ * @author Drak <drak@zikula.org>
+ */
+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;
+ }
+}
View
174 src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php
@@ -0,0 +1,174 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\HttpFoundation\Session\Flash;
+
+/**
+ * AutoExpireFlashBag flash message container.
+ *
+ * @author Drak <drak@zikula.org>
+ */
+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()