Commit c03a3ff8 by Qiang Xue

Finishes flash feature.

parent cd1b3d32
......@@ -148,7 +148,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
* Defaults to false, meaning all items in the dictionary will be cleared directly
* without calling [[remove]].
*/
public function clear($safeClear = false)
public function removeAll($safeClear = false)
{
if ($safeClear) {
foreach (array_keys($this->_d) as $key) {
......@@ -164,7 +164,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
* @param mixed $key the key
* @return boolean whether the dictionary contains an item with the specified key
*/
public function contains($key)
public function has($key)
{
return isset($this->_d[$key]) || array_key_exists($key, $this->_d);
}
......@@ -188,7 +188,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
{
if (is_array($data) || $data instanceof \Traversable) {
if ($this->_d !== array()) {
$this->clear();
$this->removeAll();
}
if ($data instanceof self) {
$data = $data->_d;
......@@ -252,7 +252,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*/
public function offsetExists($offset)
{
return $this->contains($offset);
return $this->has($offset);
}
/**
......
......@@ -191,7 +191,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* Defaults to false, meaning all items in the vector will be cleared directly
* without calling [[removeAt]].
*/
public function clear($safeClear = false)
public function removeAll($safeClear = false)
{
if ($safeClear) {
for ($i = $this->_c - 1; $i >= 0; --$i) {
......@@ -209,7 +209,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* @param mixed $item the item
* @return boolean whether the vector contains the item
*/
public function contains($item)
public function has($item)
{
return $this->indexOf($item) >= 0;
}
......@@ -246,7 +246,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
{
if (is_array($data) || $data instanceof \Traversable) {
if ($this->_c > 0) {
$this->clear();
$this->removeAll();
}
if ($data instanceof self) {
$data = $data->_d;
......
......@@ -12,13 +12,15 @@ use yii\base\Component;
use yii\base\InvalidParamException;
/**
* Session provides session-level data management and the related configurations.
* Session provides session data management and the related configurations.
*
* Session is a Web application component that can be accessed via `Yii::$app->session`.
* To start the session, call [[open()]]; To complete and send out session data, call [[close()]];
* To destroy the session, call [[destroy()]].
*
* If [[autoStart]] is set true, the session will be started automatically
* when the application component is initialized by the application.
* By default, [[autoStart]] is true which means the session will be started automatically
* when the session component is accessed the first time.
*
* Session can be used like an array to set and get session data. For example,
*
......@@ -37,22 +39,11 @@ use yii\base\InvalidParamException;
* [[openSession()]], [[closeSession()]], [[readSession()]], [[writeSession()]],
* [[destroySession()]] and [[gcSession()]].
*
* Session is a Web application component that can be accessed via
* `Yii::$app->session`.
*
* @property boolean $useCustomStorage read-only. Whether to use custom storage.
* @property boolean $isActive Whether the session has started.
* @property string $id The current session ID.
* @property string $name The current session name.
* @property string $savePath The current session save path, defaults to '/tmp'.
* @property array $cookieParams The session cookie parameters.
* @property string $cookieMode How to use cookie to store session ID. Defaults to 'Allow'.
* @property float $gcProbability The probability (percentage) that the gc (garbage collection) process is started on every session initialization.
* @property boolean $useTransparentSessionID Whether transparent sid support is enabled or not, defaults to false.
* @property integer $timeout The number of seconds after which data will be seen as 'garbage' and cleaned up, defaults to 1440 seconds.
* @property SessionIterator $iterator An iterator for traversing the session variables.
* @property integer $count The number of session variables.
* @property array $keys The list of session variable names.
* Session also supports a special type of session data, called *flash messages*.
* A flash message is available only in the current request and the next request.
* After that, it will be deleted automatically. Flash messages are particularly
* useful for displaying confirmation messages. To use flash messages, simply
* call methods such as [[setFlash()]], [[getFlash()]].
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
......@@ -63,6 +54,10 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
* @var boolean whether the session should be automatically started when the session component is initialized.
*/
public $autoStart = true;
/**
* @var string the name of the session variable that stores the flash message data.
*/
public $flashVar = '__flash';
/**
* Initializes the application component.
......@@ -117,7 +112,9 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
if (session_id() == '') {
$error = error_get_last();
$message = isset($error['message']) ? $error['message'] : 'Failed to start session.';
Yii::warning($message, __CLASS__);
Yii::error($message, __CLASS__);
} else {
$this->updateFlashCounters();
}
}
......@@ -462,18 +459,18 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
/**
* Adds a session variable.
* Note, if the specified name already exists, the old value will be removed first.
* @param mixed $key session variable name
* If the specified name already exists, the old value will be overwritten.
* @param string $key session variable name
* @param mixed $value session variable value
*/
public function add($key, $value)
public function set($key, $value)
{
$_SESSION[$key] = $value;
}
/**
* Removes a session variable.
* @param mixed $key the name of the session variable to be removed
* @param string $key the name of the session variable to be removed
* @return mixed the removed value, null if no such session variable.
*/
public function remove($key)
......@@ -490,7 +487,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
/**
* Removes all session variables
*/
public function clear()
public function removeAll()
{
foreach (array_keys($_SESSION) as $key) {
unset($_SESSION[$key]);
......@@ -501,7 +498,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
* @param mixed $key session variable name
* @return boolean whether there is the named session variable
*/
public function contains($key)
public function has($key)
{
return isset($_SESSION[$key]);
}
......@@ -515,6 +512,114 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
}
/**
* Updates the counters for flash messages and removes outdated flash messages.
* This method should only be called once in [[init()]].
*/
protected function updateFlashCounters()
{
$counters = $this->get($this->flashVar, array());
if (is_array($counters)) {
foreach ($counters as $key => $count) {
if ($count) {
unset($counters[$key], $_SESSION[$key]);
} else {
$counters[$key]++;
}
}
$_SESSION[$this->flashVar] = $counters;
} else {
// fix the unexpected problem that flashVar doesn't return an array
unset($_SESSION[$this->flashVar]);
}
}
/**
* Returns a flash message.
* A flash message is available only in the current request and the next request.
* @param string $key the key identifying the flash message
* @param mixed $defaultValue value to be returned if the flash message does not exist.
* @return mixed the flash message
*/
public function getFlash($key, $defaultValue = null)
{
$counters = $this->get($this->flashVar, array());
return isset($counters[$key]) ? $this->get($key, $defaultValue) : $defaultValue;
}
/**
* Returns all flash messages.
* @return array flash messages (key => message).
*/
public function getAllFlashes()
{
$counters = $this->get($this->flashVar, array());
$flashes = array();
foreach (array_keys($counters) as $key) {
if (isset($_SESSION[$key])) {
$flashes[$key] = $_SESSION[$key];
}
}
return $flashes;
}
/**
* Stores a flash message.
* A flash message is available only in the current request and the next request.
* @param string $key the key identifying the flash message. Note that flash messages
* and normal session variables share the same name space. If you have a normal
* session variable using the same name, its value will be overwritten by this method.
* @param mixed $value flash message
*/
public function setFlash($key, $value)
{
$counters = $this->get($this->flashVar, array());
$counters[$key] = 0;
$_SESSION[$key] = $value;
$_SESSION[$this->flashVar] = $counters;
}
/**
* Removes a flash message.
* Note that flash messages will be automatically removed after the next request.
* @param string $key the key identifying the flash message. Note that flash messages
* and normal session variables share the same name space. If you have a normal
* session variable using the same name, it will be removed by this method.
* @return mixed the removed flash message. Null if the flash message does not exist.
*/
public function removeFlash($key)
{
$counters = $this->get($this->flashVar, array());
$value = isset($_SESSION[$key], $counters[$key]) ? $_SESSION[$key] : null;
unset($counters[$key], $_SESSION[$key]);
$_SESSION[$this->flashVar] = $counters;
return $value;
}
/**
* Removes all flash messages.
* Note that flash messages and normal session variables share the same name space.
* If you have a normal session variable using the same name, it will be removed
* by this method.
*/
public function removeAllFlashes()
{
$counters = $this->get($this->flashVar, array());
foreach (array_keys($counters) as $key) {
unset($_SESSION[$key]);
}
unset($_SESSION[$this->flashVar]);
}
/**
* @param string $key key identifying the flash message
* @return boolean whether the specified flash message exists
*/
public function hasFlash($key)
{
return $this->getFlash($key) !== null;
}
/**
* This method is required by the interface ArrayAccess.
* @param mixed $offset the offset to check on
* @return boolean
......
......@@ -61,7 +61,7 @@ class DictionaryTest extends \yiiunit\TestCase
{
$this->dictionary->add('key3',$this->item3);
$this->assertEquals(3,$this->dictionary->getCount());
$this->assertTrue($this->dictionary->contains('key3'));
$this->assertTrue($this->dictionary->has('key3'));
$this->dictionary[] = 'test';
}
......@@ -70,28 +70,28 @@ class DictionaryTest extends \yiiunit\TestCase
{
$this->dictionary->remove('key1');
$this->assertEquals(1,$this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->contains('key1'));
$this->assertTrue(!$this->dictionary->has('key1'));
$this->assertTrue($this->dictionary->remove('unknown key')===null);
}
public function testClear()
public function testRemoveAll()
{
$this->dictionary->add('key3',$this->item3);
$this->dictionary->clear();
$this->dictionary->removeAll();
$this->assertEquals(0,$this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->contains('key1') && !$this->dictionary->contains('key2'));
$this->assertTrue(!$this->dictionary->has('key1') && !$this->dictionary->has('key2'));
$this->dictionary->add('key3',$this->item3);
$this->dictionary->clear(true);
$this->dictionary->removeAll(true);
$this->assertEquals(0,$this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->contains('key1') && !$this->dictionary->contains('key2'));
$this->assertTrue(!$this->dictionary->has('key1') && !$this->dictionary->has('key2'));
}
public function testContains()
public function testHas()
{
$this->assertTrue($this->dictionary->contains('key1'));
$this->assertTrue($this->dictionary->contains('key2'));
$this->assertFalse($this->dictionary->contains('key3'));
$this->assertTrue($this->dictionary->has('key1'));
$this->assertTrue($this->dictionary->has('key2'));
$this->assertFalse($this->dictionary->has('key3'));
}
public function testFromArray()
......@@ -162,7 +162,7 @@ class DictionaryTest extends \yiiunit\TestCase
unset($this->dictionary['key2']);
$this->assertEquals(2,$this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->contains('key2'));
$this->assertTrue(!$this->dictionary->has('key2'));
unset($this->dictionary['unknown key']);
}
......
......@@ -101,26 +101,26 @@ class VectorTest extends \yiiunit\TestCase
$this->vector->removeAt(2);
}
public function testClear()
public function testRemoveAll()
{
$this->vector->add($this->item3);
$this->vector->clear();
$this->vector->removeAll();
$this->assertEquals(0,$this->vector->getCount());
$this->assertEquals(-1,$this->vector->indexOf($this->item1));
$this->assertEquals(-1,$this->vector->indexOf($this->item2));
$this->vector->add($this->item3);
$this->vector->clear(true);
$this->vector->removeAll(true);
$this->assertEquals(0,$this->vector->getCount());
$this->assertEquals(-1,$this->vector->indexOf($this->item1));
$this->assertEquals(-1,$this->vector->indexOf($this->item2));
}
public function testContains()
public function testHas()
{
$this->assertTrue($this->vector->contains($this->item1));
$this->assertTrue($this->vector->contains($this->item2));
$this->assertFalse($this->vector->contains($this->item3));
$this->assertTrue($this->vector->has($this->item1));
$this->assertTrue($this->vector->has($this->item2));
$this->assertFalse($this->vector->has($this->item3));
}
public function testIndexOf()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment