Commit c03a3ff8 by Qiang Xue

Finishes flash feature.

parent cd1b3d32
...@@ -148,7 +148,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -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 * Defaults to false, meaning all items in the dictionary will be cleared directly
* without calling [[remove]]. * without calling [[remove]].
*/ */
public function clear($safeClear = false) public function removeAll($safeClear = false)
{ {
if ($safeClear) { if ($safeClear) {
foreach (array_keys($this->_d) as $key) { foreach (array_keys($this->_d) as $key) {
...@@ -164,7 +164,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -164,7 +164,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
* @param mixed $key the key * @param mixed $key the key
* @return boolean whether the dictionary contains an item with the specified 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); return isset($this->_d[$key]) || array_key_exists($key, $this->_d);
} }
...@@ -188,7 +188,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -188,7 +188,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
{ {
if (is_array($data) || $data instanceof \Traversable) { if (is_array($data) || $data instanceof \Traversable) {
if ($this->_d !== array()) { if ($this->_d !== array()) {
$this->clear(); $this->removeAll();
} }
if ($data instanceof self) { if ($data instanceof self) {
$data = $data->_d; $data = $data->_d;
...@@ -252,7 +252,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -252,7 +252,7 @@ class Dictionary extends Object implements \IteratorAggregate, \ArrayAccess, \Co
*/ */
public function offsetExists($offset) public function offsetExists($offset)
{ {
return $this->contains($offset); return $this->has($offset);
} }
/** /**
......
...@@ -191,7 +191,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta ...@@ -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 * Defaults to false, meaning all items in the vector will be cleared directly
* without calling [[removeAt]]. * without calling [[removeAt]].
*/ */
public function clear($safeClear = false) public function removeAll($safeClear = false)
{ {
if ($safeClear) { if ($safeClear) {
for ($i = $this->_c - 1; $i >= 0; --$i) { for ($i = $this->_c - 1; $i >= 0; --$i) {
...@@ -209,7 +209,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta ...@@ -209,7 +209,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
* @param mixed $item the item * @param mixed $item the item
* @return boolean whether the vector contains the item * @return boolean whether the vector contains the item
*/ */
public function contains($item) public function has($item)
{ {
return $this->indexOf($item) >= 0; return $this->indexOf($item) >= 0;
} }
...@@ -246,7 +246,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta ...@@ -246,7 +246,7 @@ class Vector extends Object implements \IteratorAggregate, \ArrayAccess, \Counta
{ {
if (is_array($data) || $data instanceof \Traversable) { if (is_array($data) || $data instanceof \Traversable) {
if ($this->_c > 0) { if ($this->_c > 0) {
$this->clear(); $this->removeAll();
} }
if ($data instanceof self) { if ($data instanceof self) {
$data = $data->_d; $data = $data->_d;
......
...@@ -12,13 +12,15 @@ use yii\base\Component; ...@@ -12,13 +12,15 @@ use yii\base\Component;
use yii\base\InvalidParamException; 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 start the session, call [[open()]]; To complete and send out session data, call [[close()]];
* To destroy the session, call [[destroy()]]. * To destroy the session, call [[destroy()]].
* *
* If [[autoStart]] is set true, the session will be started automatically * By default, [[autoStart]] is true which means the session will be started automatically
* when the application component is initialized by the application. * when the session component is accessed the first time.
* *
* Session can be used like an array to set and get session data. For example, * Session can be used like an array to set and get session data. For example,
* *
...@@ -37,22 +39,11 @@ use yii\base\InvalidParamException; ...@@ -37,22 +39,11 @@ use yii\base\InvalidParamException;
* [[openSession()]], [[closeSession()]], [[readSession()]], [[writeSession()]], * [[openSession()]], [[closeSession()]], [[readSession()]], [[writeSession()]],
* [[destroySession()]] and [[gcSession()]]. * [[destroySession()]] and [[gcSession()]].
* *
* Session is a Web application component that can be accessed via * Session also supports a special type of session data, called *flash messages*.
* `Yii::$app->session`. * 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
* @property boolean $useCustomStorage read-only. Whether to use custom storage. * useful for displaying confirmation messages. To use flash messages, simply
* @property boolean $isActive Whether the session has started. * call methods such as [[setFlash()]], [[getFlash()]].
* @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.
* *
* @author Qiang Xue <qiang.xue@gmail.com> * @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0 * @since 2.0
...@@ -63,6 +54,10 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -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. * @var boolean whether the session should be automatically started when the session component is initialized.
*/ */
public $autoStart = true; public $autoStart = true;
/**
* @var string the name of the session variable that stores the flash message data.
*/
public $flashVar = '__flash';
/** /**
* Initializes the application component. * Initializes the application component.
...@@ -117,7 +112,9 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -117,7 +112,9 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
if (session_id() == '') { if (session_id() == '') {
$error = error_get_last(); $error = error_get_last();
$message = isset($error['message']) ? $error['message'] : 'Failed to start session.'; $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 ...@@ -462,18 +459,18 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
/** /**
* Adds a session variable. * Adds a session variable.
* Note, if the specified name already exists, the old value will be removed first. * If the specified name already exists, the old value will be overwritten.
* @param mixed $key session variable name * @param string $key session variable name
* @param mixed $value session variable value * @param mixed $value session variable value
*/ */
public function add($key, $value) public function set($key, $value)
{ {
$_SESSION[$key] = $value; $_SESSION[$key] = $value;
} }
/** /**
* Removes a session variable. * 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. * @return mixed the removed value, null if no such session variable.
*/ */
public function remove($key) public function remove($key)
...@@ -490,7 +487,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -490,7 +487,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
/** /**
* Removes all session variables * Removes all session variables
*/ */
public function clear() public function removeAll()
{ {
foreach (array_keys($_SESSION) as $key) { foreach (array_keys($_SESSION) as $key) {
unset($_SESSION[$key]); unset($_SESSION[$key]);
...@@ -501,7 +498,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -501,7 +498,7 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co
* @param mixed $key session variable name * @param mixed $key session variable name
* @return boolean whether there is the named session variable * @return boolean whether there is the named session variable
*/ */
public function contains($key) public function has($key)
{ {
return isset($_SESSION[$key]); return isset($_SESSION[$key]);
} }
...@@ -515,6 +512,114 @@ class Session extends Component implements \IteratorAggregate, \ArrayAccess, \Co ...@@ -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. * This method is required by the interface ArrayAccess.
* @param mixed $offset the offset to check on * @param mixed $offset the offset to check on
* @return boolean * @return boolean
......
...@@ -61,7 +61,7 @@ class DictionaryTest extends \yiiunit\TestCase ...@@ -61,7 +61,7 @@ class DictionaryTest extends \yiiunit\TestCase
{ {
$this->dictionary->add('key3',$this->item3); $this->dictionary->add('key3',$this->item3);
$this->assertEquals(3,$this->dictionary->getCount()); $this->assertEquals(3,$this->dictionary->getCount());
$this->assertTrue($this->dictionary->contains('key3')); $this->assertTrue($this->dictionary->has('key3'));
$this->dictionary[] = 'test'; $this->dictionary[] = 'test';
} }
...@@ -70,28 +70,28 @@ class DictionaryTest extends \yiiunit\TestCase ...@@ -70,28 +70,28 @@ class DictionaryTest extends \yiiunit\TestCase
{ {
$this->dictionary->remove('key1'); $this->dictionary->remove('key1');
$this->assertEquals(1,$this->dictionary->getCount()); $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); $this->assertTrue($this->dictionary->remove('unknown key')===null);
} }
public function testClear() public function testRemoveAll()
{ {
$this->dictionary->add('key3',$this->item3); $this->dictionary->add('key3',$this->item3);
$this->dictionary->clear(); $this->dictionary->removeAll();
$this->assertEquals(0,$this->dictionary->getCount()); $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->add('key3',$this->item3);
$this->dictionary->clear(true); $this->dictionary->removeAll(true);
$this->assertEquals(0,$this->dictionary->getCount()); $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->has('key1'));
$this->assertTrue($this->dictionary->contains('key2')); $this->assertTrue($this->dictionary->has('key2'));
$this->assertFalse($this->dictionary->contains('key3')); $this->assertFalse($this->dictionary->has('key3'));
} }
public function testFromArray() public function testFromArray()
...@@ -162,7 +162,7 @@ class DictionaryTest extends \yiiunit\TestCase ...@@ -162,7 +162,7 @@ class DictionaryTest extends \yiiunit\TestCase
unset($this->dictionary['key2']); unset($this->dictionary['key2']);
$this->assertEquals(2,$this->dictionary->getCount()); $this->assertEquals(2,$this->dictionary->getCount());
$this->assertTrue(!$this->dictionary->contains('key2')); $this->assertTrue(!$this->dictionary->has('key2'));
unset($this->dictionary['unknown key']); unset($this->dictionary['unknown key']);
} }
......
...@@ -101,26 +101,26 @@ class VectorTest extends \yiiunit\TestCase ...@@ -101,26 +101,26 @@ class VectorTest extends \yiiunit\TestCase
$this->vector->removeAt(2); $this->vector->removeAt(2);
} }
public function testClear() public function testRemoveAll()
{ {
$this->vector->add($this->item3); $this->vector->add($this->item3);
$this->vector->clear(); $this->vector->removeAll();
$this->assertEquals(0,$this->vector->getCount()); $this->assertEquals(0,$this->vector->getCount());
$this->assertEquals(-1,$this->vector->indexOf($this->item1)); $this->assertEquals(-1,$this->vector->indexOf($this->item1));
$this->assertEquals(-1,$this->vector->indexOf($this->item2)); $this->assertEquals(-1,$this->vector->indexOf($this->item2));
$this->vector->add($this->item3); $this->vector->add($this->item3);
$this->vector->clear(true); $this->vector->removeAll(true);
$this->assertEquals(0,$this->vector->getCount()); $this->assertEquals(0,$this->vector->getCount());
$this->assertEquals(-1,$this->vector->indexOf($this->item1)); $this->assertEquals(-1,$this->vector->indexOf($this->item1));
$this->assertEquals(-1,$this->vector->indexOf($this->item2)); $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->has($this->item1));
$this->assertTrue($this->vector->contains($this->item2)); $this->assertTrue($this->vector->has($this->item2));
$this->assertFalse($this->vector->contains($this->item3)); $this->assertFalse($this->vector->has($this->item3));
} }
public function testIndexOf() 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