Skip to content

[WIP][HttpFoundation] Improve flash messages (replaces PR #2510) #2543

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 108 additions & 20 deletions src/Symfony/Component/HttpFoundation/Session.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
*/
class Session implements \Serializable
{
const FLASH_INFO = 'info';
const FLASH_WARNING = 'warning';
const FLASH_ERROR = 'error';

protected $storage;
protected $started;
protected $attributes;
Expand All @@ -37,8 +41,8 @@ class Session implements \Serializable
public function __construct(SessionStorageInterface $storage)
{
$this->storage = $storage;
$this->flashes = array();
$this->oldFlashes = array();
$this->flashes = array(self::FLASH_INFO => array());
$this->oldFlashes = array(self::FLASH_INFO => array());
$this->attributes = array();
$this->started = false;
$this->closed = false;
Expand Down Expand Up @@ -174,7 +178,7 @@ public function clear()
}

$this->attributes = array();
$this->flashes = array();
$this->flashes = array(self::FLASH_INFO => array());
}

/**
Expand Down Expand Up @@ -215,88 +219,138 @@ public function getId()
return $this->storage->getId();
}

/**
* Gets the flash messages of a given type.
*
* @param string $type
*
* @throws \InvalidArgumentException If non-existing $type is requested.
*
* @return array
*/
public function getFlashes($type = self::FLASH_INFO)
{
if (!isset($this->flashes[$type])) {
throw new \InvalidArgumentException(sprintf('Flash message type %s does not exist', $type));
}

return $this->flashes[$type];
}

/**
* Gets the flash messages.
*
* @return array
*/
public function getFlashes()
public function getAllFlashes()
{
return $this->flashes;
}

/**
* Sets the flash messages of a specific type.
*
* @param array $values
* @param string $type
*/
public function setFlashes($values, $type = self::FLASH_INFO)
{
if (false === $this->started) {
$this->start();
}

$this->flashes[$type] = $values;
$this->oldFlashes = array(self::FLASH_INFO => array());
}

/**
* Sets the flash messages.
*
* @param array $values
*/
public function setFlashes($values)
public function setAllFlashes($values)
{
if (false === $this->started) {
$this->start();
}

$this->flashes = $values;
$this->oldFlashes = array();
$this->oldFlashes = array(self::FLASH_INFO => array());
}

/**
* Gets a flash message.
*
* @param string $name
* @param string|null $default
*
* @throws InvalidArgumentException If unknown type specified.
*
* @return string
* @return mixed
*/
public function getFlash($name, $default = null)
public function getFlash($name, $default = null, $type = self::FLASH_INFO)
{
return array_key_exists($name, $this->flashes) ? $this->flashes[$name] : $default;
if (!isset($this->flashes[$type])) {
throw new \InvalidArgumentException(sprintf('Unknown flash message type %s', $type));
}

return array_key_exists($name, $this->flashes[$type]) ? $this->flashes[$type][$name] : $default;
}

/**
* Sets a flash message.
*
* @param string $name
* @param string $value
* @param string $type
*/
public function setFlash($name, $value)
public function setFlash($name, $value, $type = self::FLASH_INFO)
{
if (false === $this->started) {
$this->start();
}

$this->flashes[$name] = $value;
unset($this->oldFlashes[$name]);
$this->flashes[$type][$name] = $value;
unset($this->oldFlashes[$type][$name]);
}

/**
* Checks whether a flash message exists.
*
* @param string $name
* @param string $type
*
* @throws InvalidArgumentException If unknown type specified.
*
* @return Boolean
*/
public function hasFlash($name)
public function hasFlash($name, $type = self::FLASH_INFO)
{
if (false === $this->started) {
$this->start();
}

if (!isset($this->flashes[$type])) {
throw new \InvalidArgumentException(sprintf('Unknown flash message type %s', $type));
}

return array_key_exists($name, $this->flashes);
return array_key_exists($name, $this->flashes[$type]);
}

/**
* Removes a flash message.
*
* @param string $name
*/
public function removeFlash($name)
public function removeFlash($name, $type = self::FLASH_INFO)
{
if (false === $this->started) {
$this->start();
}

unset($this->flashes[$name]);
if (isset($this->flashes[$type])) {
unset($this->flashes[$type][$name]);
}
}

/**
Expand All @@ -308,17 +362,33 @@ public function clearFlashes()
$this->start();
}

$this->flashes = array();
$this->oldFlashes = array();
$this->flashes = array(self::FLASH_INFO => array());
$this->oldFlashes = array(self::FLASH_INFO => array());
}

/**
* Adds a generic flash message to the session.
*
* @param string $value
* @param string $type
*/
public function addFlash($value, $type = self::FLASH_INFO)
{
$this->flashes[$type][] = $value;
}

/**
* Save session.
*/
public function save()
{
if (false === $this->started) {
$this->start();
}

$this->flashes = array_diff_key($this->flashes, $this->oldFlashes);
foreach ($this->flashes as $type => $flashes) {
$this->flashes[$type] = array_diff_key($flashes, $this->oldFlashes[$type]);
}

$this->storage->write('_symfony2', array(
'attributes' => $this->attributes,
Expand All @@ -327,6 +397,8 @@ public function save()
}

/**
* Close the session without writing saving it.
*
* 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
Expand All @@ -344,14 +416,30 @@ public function __destruct()
}
}

/**
* Serialize the session storage driver.
*
* @return string
*/
public function serialize()
{
return serialize($this->storage);
}

/**
* Unserialize the SessionStorage.
*
* @param type $serialized
*
* @throws \InvalidArgumentException If serialized string is not an instance of SessionStorageInterface
*/
public function unserialize($serialized)
{
$this->storage = unserialize($serialized);
$storage = unserialize($serialized);
if (!$storage instanceof SessionStorageInterface) {
throw new \InvalidArgumentException('Serialized string passed does not unserialze to an instance of Symfony\\Component\\HttpFoundation\\SessionStorageInterface');
}
$this->storage = $storage;
$this->attributes = array();
$this->started = false;
}
Expand Down
71 changes: 68 additions & 3 deletions tests/Symfony/Tests/Component/HttpFoundation/SessionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,14 @@
*/
class SessionTest extends \PHPUnit_Framework_TestCase
{
/**
* @var SessionStorage
*/
protected $storage;

/**
* @var Session
*/
protected $session;

public function setUp()
Expand Down Expand Up @@ -59,6 +66,55 @@ public function testFlash()
$this->session->setFlashes($flashes);

$this->assertSame($flashes, $this->session->getFlashes());

$this->session->clearFlashes();
$this->session->addFlash('foo');
$compare = $this->session->getFlashes();
$this->assertSame($compare, array(0 => 'foo'));
}

/**
* @expectedException InvalidArgumentException
*/
public function testGetFlashException()
{
$this->session->getFlash('foo', null, 'notexisting');
}

/**
* @expectedException InvalidArgumentException
*/
public function testHasFlashException()
{
$this->session->hasFlash('foo', 'notexisting');
}

public function testGetFlashes()
{
$this->assertEquals(array(), $this->session->getFlashes(Session::FLASH_INFO));
$this->session->setFlash(Session::FLASH_INFO, 'hello');
$this->assertEquals(array(Session::FLASH_INFO => 'hello'), $this->session->getFlashes(Session::FLASH_INFO));
}

/**
* @expectedException InvalidArgumentException
*/
public function testGetFlashesException()
{
$this->session->getFlashes('notexisting');
}

public function testSetFlashes()
{
$this->session->setFlashes(array('hello', 'world'));
$this->assertEquals(array('hello', 'world'), $this->session->getFlashes(Session::FLASH_INFO));
}

public function testAllFlashes()
{
$this->assertEquals(array(Session::FLASH_INFO => array()), $this->session->getAllFlashes());
$this->session->setAllFlashes(array(Session::FLASH_INFO => array('hello', 'world')));
$this->assertEquals(array(Session::FLASH_INFO => array('hello', 'world')), $this->session->getAllFlashes());
}

public function testFlashesAreFlushedWhenNeeded()
Expand Down Expand Up @@ -141,6 +197,15 @@ public function testSerialize()

$this->assertEquals($_storage->getValue($this->session), $this->storage, 'storage match');
}

/**
* @expectedException InvalidArgumentException
*/
public function testUnserializeException()
{
$serialized = serialize('not an instance of SessionStorage');
$this->session->unserialize($serialized);
}

public function testSave()
{
Expand All @@ -149,7 +214,7 @@ public function testSave()
$this->session->set('foo', 'bar');

$this->session->save();
$compare = array('_symfony2' => array('attributes' => array('foo' => 'bar'), 'flashes' => array()));
$compare = array('_symfony2' => array('attributes' => array('foo' => 'bar'), 'flashes' => array(Session::FLASH_INFO => array())));

$r = new \ReflectionObject($this->storage);
$p = $r->getProperty('data');
Expand Down Expand Up @@ -179,7 +244,7 @@ public function testSavedOnDestruct()

$expected = array(
'attributes'=>array('foo'=>'bar'),
'flashes'=>array(),
'flashes'=>array(Session::FLASH_INFO => array()),
);
$saved = $this->storage->read('_symfony2');
$this->assertSame($expected, $saved);
Expand All @@ -195,7 +260,7 @@ public function testSavedOnDestructAfterManualSave()

$expected = array(
'attributes'=>array('foo'=>'bar'),
'flashes'=>array(),
'flashes'=>array(Session::FLASH_INFO => array()),
);
$saved = $this->storage->read('_symfony2');
$this->assertSame($expected, $saved);
Expand Down