Permalink
Browse files

merged branch drak/session_flashmessages (PR #3267)

Commits
-------

5ae76f1 [HttpFoundation] Update documentation.
910b5c7 [HttpFoudation] CS, more tests and some optimization.
b0466e8 [HttpFoundation] Refactored BC Session class methods.
84c2e3c [HttpFoundation] Allow flash messages to have multiple messages per type.

Discussion
----------

[2.1][HttpFoundation] Multiple session flash messages

Bug fix: no
Feature addition: yes
Backwards compatibility break: yes, but this already happened in #2583.  BC `Session` methods remain unbroken.
Symfony2 tests pass: yes
Fixes the following tickets: #1863
References the following tickets: #2714, #2753, #2510, #2543, #2853
Todo: -

This PR alters flash messages so that it is possible to store more than one message per flash type using the `add()` method or by passing an array of messages to `set()`.

__NOTES ABOUT BC__

This PR maintains BC behaviour with the `Session` class in that the old Symfony 2.0 methods will continue to work as before.

---------------------------------------------------------------------------

by drak at 2012-02-13T06:28:33Z

I think this is ready for review @fabpot @lsmith77

---------------------------------------------------------------------------

by lsmith77 at 2012-02-14T19:30:39Z

the FlashBag vs. AutoExpireFlashBag behavior and setup difference should probably also be explained in the upgrading log

---------------------------------------------------------------------------

by drak at 2012-02-15T04:43:14Z

@lsmith77 Those differences are explained already in the changelog

 * 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()`.

---------------------------------------------------------------------------

by Crell at 2012-02-19T17:35:34Z

Drak asked me to weigh in here with use cases.  Drupal currently has a similar session-stored-messaging system in place that I'd like to be able to replace with Flash messages.  We frequently have multiple messages within a single request, however, so this change is critical to our being able to do so.

For instance, when saving an article in Drupal there is, by default, a "yay, you saved an article!" type message that gets displayed.  If you also have the site configured to send email when a post is updated, you may see a "email notifications sent" message (depending on your access level).  If you have a Solr server setup for search, and you're in debug mode, there will also be a "record ID X added to Solr, it should update in 2 minutes" message.  And if there's a bug somewhere, you'll also get, as an error message rather than notice message, a "Oops, E_NOTICE on line 54" message.

Form validation is another case.  If you have multiple errors in a single form, we prefer to list all of them.  So if you screw up 4 times on a form, you may get 4 different error messages showing what you screwed up so you can fix it in one go instead of several.

Now sure, one could emulate that by building a multi-message layer on top of single-layer messages, but, really, why?  "One is a special case of many", and there are many many cases where you'll want to post multiple messages.  Like, most of Drupal. :-)

---------------------------------------------------------------------------

by lsmith77 at 2012-03-06T20:55:51Z

@fabpot is there any information you still need before merging this? do you want more discussion in which case you might want to take this to the mailing list ..

---------------------------------------------------------------------------

by drak at 2012-03-08T18:54:13Z

Another plus for this PR is that it requires no extra lines of code in templates etc to display the flashes, see https://github.com/symfony/symfony/pull/3267/files#diff-1

---------------------------------------------------------------------------

by drak at 2012-03-15T06:38:21Z

Rebased against current `master`, should be mergeable again..

---------------------------------------------------------------------------

by evillemez at 2012-03-17T03:08:41Z

+1 to this, I have an extended version of HttpFoundation just for this... would love to get rid of it.
  • Loading branch information...
2 parents a597453 + 5ae76f1 commit 09ab6430c06e0e4f9d0c40be7644956e102bb219 @fabpot fabpot committed Mar 23, 2012
View
@@ -305,6 +305,9 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c
attributes storage behaviour from 2.0.x (default).
* Added `Symfony\Component\HttpFoundation\Attribute\NamespacedAttributeBag` for
namespace session attributes.
+ * Flash API can stores messages in an array so there may be multiple messages
+ per flash type. The old `Session` class API remains without BC break as it
+ will single messages as before.
### HttpKernel
View
@@ -307,30 +307,31 @@ UPGRADE FROM 2.0 to 2.1
Before:
```
- {% if app.session.hasFlash('notice') %}
+ {% if app.session.flashbag.has('notice') %}
<div class="flash-notice">
- {{ app.session.flash('notice') }}
+ {{ app.session.flashbag.get('notice') }}
</div>
{% endif %}
```
-
After:
```
- {% if app.session.flashbag.has('notice') %}
+ {% for flashMessage in app.session.flashbag.get('notice') %}
<div class="flash-notice">
- {{ app.session.flashbag.get('notice') }}
+ {{ flashMessage }}
</div>
- {% endif %}
+ {% endfor %}
```
You can process all flash messges in a single loop with:
```
- {% for type, flashMessage in app.session.flashbag.all() %}
- <div class="flash-{{ type }}">
- {{ flashMessage }}
- </div>
+ {% for type, flashMessages in app.session.flashbag.all() %}
+ {% for flashMessage in flashMessages) %}
+ <div class="flash-{{ type }}">
+ {{ flashMessage }}
+ </div>
+ {% endfor %}
{% endfor %}
```
@@ -46,9 +46,9 @@ public function get($name, $default = null)
return $this->session->get($name, $default);
}
- public function getFlash($name, $default = null)
+ public function getFlash($name, array $default = array())
{
- return $this->session->getFlashBag()->get($name);
+ return $this->session->getFlashBag()->get($name, $default);
}
public function getFlashes()
@@ -62,7 +62,7 @@ public function showFlashAction()
$session = $request->getSession();
if ($session->getFlashBag()->has('notice')) {
- $output = $session->getFlashBag()->get('notice');
+ list($output) = $session->getFlashBag()->get('notice');
} else {
$output = 'No flash was set.';
}
@@ -42,13 +42,13 @@ public function testFlash()
$this->assertTrue($helper->hasFlash('notice'));
- $this->assertEquals('bar', $helper->getFlash('notice'));
+ $this->assertEquals(array('bar'), $helper->getFlash('notice'));
}
public function testGetFlashes()
{
$helper = new SessionHelper($this->request);
- $this->assertEquals(array('notice' => 'bar'), $helper->getFlashes());
+ $this->assertEquals(array('notice' => array('bar')), $helper->getFlashes());
}
public function testGet()
@@ -75,7 +75,15 @@ public function initialize(array &$flashes)
/**
* {@inheritdoc}
*/
- public function peek($type, $default = null)
+ public function add($type, $message)
+ {
+ $this->flashes['new'][$type][] = $message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function peek($type, array $default = array())
{
return $this->has($type) ? $this->flashes['display'][$type] : $default;
}
@@ -91,7 +99,7 @@ public function peekAll()
/**
* {@inheritdoc}
*/
- public function get($type, $default = null)
+ public function get($type, array $default = array())
{
$return = $default;
@@ -129,17 +137,17 @@ public function setAll(array $messages)
/**
* {@inheritdoc}
*/
- public function set($type, $message)
+ public function set($type, $messages)
{
- $this->flashes['new'][$type] = $message;
+ $this->flashes['new'][$type] = (array)$messages;
}
/**
* {@inheritdoc}
*/
public function has($type)
{
- return array_key_exists($type, $this->flashes['display']);
+ return array_key_exists($type, $this->flashes['display']) && $this->flashes['display'][$type];
}
/**
@@ -163,9 +171,6 @@ public function getStorageKey()
*/
public function clear()
{
- $return = $this->all();
- $this->flashes = array('display' => array(), 'new' => array());
-
- return $return;
+ return $this->all();
}
}
@@ -68,7 +68,15 @@ public function initialize(array &$flashes)
/**
* {@inheritdoc}
*/
- public function peek($type, $default = null)
+ public function add($type, $message)
+ {
+ $this->flashes[$type][] = $message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function peek($type, array $default =array())
{
return $this->has($type) ? $this->flashes[$type] : $default;
}
@@ -84,7 +92,7 @@ public function peekAll()
/**
* {@inheritdoc}
*/
- public function get($type, $default = null)
+ public function get($type, array $default = array())
{
if (!$this->has($type)) {
return $default;
@@ -111,9 +119,9 @@ public function all()
/**
* {@inheritdoc}
*/
- public function set($type, $message)
+ public function set($type, $messages)
{
- $this->flashes[$type] = $message;
+ $this->flashes[$type] = (array) $messages;
}
/**
@@ -129,7 +137,7 @@ public function setAll(array $messages)
*/
public function has($type)
{
- return array_key_exists($type, $this->flashes);
+ return array_key_exists($type, $this->flashes) && $this->flashes[$type];
}
/**
@@ -32,11 +32,11 @@ 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.
+ * @param array $default Default value if $type doee not exist.
*
* @return string
*/
- function peek($type, $default = null);
+ function peek($type, array $default = array());
/**
* Gets all flash messages.
@@ -49,11 +49,11 @@ function peekAll();
* Gets and clears flash from the stack.
*
* @param string $type
- * @param string $default Default value if $type doee not exist.
+ * @param array $default Default value if $type doee not exist.
*
* @return string
*/
- function get($type, $default = null);
+ function get($type, array $default = array());
/**
* Gets and clears flashes from the stack.
@@ -229,7 +229,16 @@ public function getFlashBag()
*/
public function getFlashes()
{
- return $this->getBag('flashes')->all();
+ $all = $this->getBag($this->flashName)->all();
+
+ $return = array();
+ if ($all) {
+ foreach ($all as $name => $array) {
+ $return[$name] = reset($array);
+ }
+ }
+
+ return $return;
}
/**
@@ -239,7 +248,9 @@ public function getFlashes()
*/
public function setFlashes($values)
{
- $this->getBag('flashes')->setAll($values);
+ foreach ($values as $name => $value) {
+ $this->getBag($this->flashName)->set($name, $value);
+ }
}
/**
@@ -252,7 +263,9 @@ public function setFlashes($values)
*/
public function getFlash($name, $default = null)
{
- return $this->getBag('flashes')->get($name, $default);
+ $return = $this->getBag($this->flashName)->get($name);
+
+ return empty($return) ? $default : reset($return);
}
/**
@@ -263,7 +276,7 @@ public function getFlash($name, $default = null)
*/
public function setFlash($name, $value)
{
- $this->getBag('flashes')->set($name, $value);
+ $this->getBag($this->flashName)->set($name, $value);
}
/**
@@ -275,7 +288,7 @@ public function setFlash($name, $value)
*/
public function hasFlash($name)
{
- return $this->getBag('flashes')->has($name);
+ return $this->getBag($this->flashName)->has($name);
}
/**
@@ -285,7 +298,7 @@ public function hasFlash($name)
*/
public function removeFlash($name)
{
- $this->getBag('flashes')->get($name);
+ $this->getBag($this->flashName)->get($name);
}
/**
@@ -295,7 +308,7 @@ public function removeFlash($name)
*/
public function clearFlashes()
{
- return $this->getBag('flashes')->clear();
+ return $this->getBag($this->flashName)->clear();
}
/**
@@ -34,7 +34,7 @@ public function setUp()
{
parent::setUp();
$this->bag = new FlashBag();
- $this->array = array('new' => array('notice' => 'A previous flash message'));
+ $this->array = array('new' => array('notice' => array('A previous flash message')));
$this->bag->initialize($this->array);
}
@@ -47,16 +47,16 @@ public function tearDown()
public function testInitialize()
{
$bag = new FlashBag();
- $array = array('new' => array('notice' => 'A previous flash message'));
+ $array = array('new' => array('notice' => array('A previous flash message')));
$bag->initialize($array);
- $this->assertEquals('A previous flash message', $bag->peek('notice'));
+ $this->assertEquals(array('A previous flash message'), $bag->peek('notice'));
$array = array('new' => array(
- 'notice' => 'Something else',
- 'error' => 'a',
+ 'notice' => array('Something else'),
+ 'error' => array('a'),
));
$bag->initialize($array);
- $this->assertEquals('Something else', $bag->peek('notice'));
- $this->assertEquals('a', $bag->peek('error'));
+ $this->assertEquals(array('Something else'), $bag->peek('notice'));
+ $this->assertEquals(array('a'), $bag->peek('error'));
}
public function testGetStorageKey()
@@ -75,16 +75,16 @@ public function testGetSetName()
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'));
+ $this->assertEquals(array(), $this->bag->peek('non_existing'));
+ $this->assertEquals(array('default'), $this->bag->peek('non_existing', array('default')));
+ $this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
+ $this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
}
public function testSet()
{
$this->bag->set('notice', 'Foo');
- $this->assertNotEquals('Foo', $this->bag->peek('notice'));
+ $this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
}
public function testHas()
@@ -123,10 +123,10 @@ public function testPeekAll()
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'));
+ $this->assertEquals(array(), $this->bag->get('non_existing'));
+ $this->assertEquals(array('default'), $this->bag->get('non_existing', array('default')));
+ $this->assertEquals(array('A previous flash message'), $this->bag->get('notice'));
+ $this->assertEquals(array(), $this->bag->get('notice'));
}
public function testSetAll()
@@ -141,7 +141,7 @@ public function testAll()
$this->bag->set('notice', 'Foo');
$this->bag->set('error', 'Bar');
$this->assertEquals(array(
- 'notice' => 'A previous flash message',
+ 'notice' => array('A previous flash message'),
), $this->bag->all()
);
@@ -150,6 +150,6 @@ public function testAll()
public function testClear()
{
- $this->assertEquals(array('notice' => 'A previous flash message'), $this->bag->clear());
+ $this->assertEquals(array('notice' => array('A previous flash message')), $this->bag->clear());
}
}
Oops, something went wrong.

0 comments on commit 09ab643

Please sign in to comment.