Bored with setFlash? Use addFlash and multiFlash!

I’ve extended CWebUser class adding functionality that enables easy adding and showing multiple flashes.

You don’t have to worry about keys, just add flashes and then show them all in the current or next request!




class WebUser extends CWebUser {

	

	const MF_KEY_PREFIX = 'mf';

	const MF_MAX = 100;

	

	/**

	 * Add flash to the stack.

	 * @param string $msg

	 * @param string $class 

	 */

	public function addFlash($msg='', $class='info') {

		$key = $this->getNexMultiFlashKey();

		if ($key===false) 

			Yii::trace("Stack overflow in addFlash", 'application.webuser.addFlash()');

		else

			$this->setFlash($key, array($msg, $class));

	}

	

	/**

	 * Returns next flash key for addFlash function.

	 * @return mixed string if ok or bool false if there was stack overflow.

	 */

	protected function getNexMultiFlashKey() {

		$counters=$this->getState(self::FLASH_COUNTERS,array());

		if (empty($counters)) return self::MF_KEY_PREFIX."1";

		for ($i=1;$i<=self::MF_MAX; $i++) {

			$key = self::MF_KEY_PREFIX . (string)$i;

			if (array_key_exists($key, $counters)) continue;

			return $key;

		}

		return false;

	}

	

	/**

	 * Gets all flashes and shows them to the user.

	 * Every flash is div with css class 'flash' and another 'flash_xxx' where xxx is the $class

	 * parameter set in addFlash function.

	 * Examples:

	 * Yii::app()->user->addFlash('My text, something important!', 'warning');

	 * Yii::app()->multiFlash();

	 * Output is <div class="flash flash_warning">My text, something important!<div>

	 */

	public function multiFlash() {

		for ($i=1;$i<=self::MF_MAX; $i++) {

			$key = self::MF_KEY_PREFIX . (string)$i;

			if (!$this->hasFlash($key)) continue;

			list($msg, $class) = $this->getFlash($key);

			Yii::trace("Echoing multiFlash: $key", 'application.webuser.multiFlash()');

			echo "<div class=\"flash flash_$class\">$msg</div>\n";

		}

	}


	

}



Usage:

Adding:

Yii::app()->user->addFlash(‘My text, something important!’, ‘warning’);

Yii::app()->user->addFlash(‘Another one!’, ‘info’);

Yii::app()->user->addFlash(‘Another one!’, ‘error’);

Showing them all:

Yii::app()->user->multiFlash();

Installation:

  1. paste the code to WebUser.php

  2. save it somewhere

  3. change your config file in /protected/config




return array(

  'components'=>array(

    'user'=>array(

       'class'=>'application.somewhere_dir.WebUser

    ),

  )

);



I really missed the functionality of handling multiple flashes in CWebUser.

Just a note, CWebUser::getFlashes() was added in trunk already.

Yes, it returns all flash messages + Array ‘counters’ compare to $counters=->getState(self::FLASH_COUNTERS); which returns only flash messages.

This is desired functionality or a bug?

I have the same question as @skippy: Why does getFlashes() return an array element [counters] in addition to all the flashes themselves? Seems like a bug.

EDIT: logged as issue #2060

http://code.google.com/p/yii/issues/detail?id=2060

I know it’s old topic but i think my solution could be also good:

Add to WebUser class this method:




/**

 * Add flash to the stack.

 * @param string $key key identifying the flash message

 * @param mixed $value flash message

*/

public function addFlash($key,$value) {

	if($this->hasFlash($key)) {

		$actualVal = $this->getFlash($key);

		$array = is_array($actualVal) ? $actualVal : array($actualVal);

		$array[] = $value;

		$this->setFlash($key, $array);

	} else $this->setFlash($key, $value);

}



and then use it as normal "setFlash" method.

If you want to display messages, use (in your view) something like this:




foreach(Yii::app()->user->getFlashes() as $key => $value) {

	if(is_array($value))

		foreach($value as $message)

			echo '<div class="message message-' . $key . '">' . $message . "</div>";

	else echo '<div class="message message-' . $key . '">' . $value . "</div>";

}