Custom CakePHP Flash Messages
UPDATE: I've written an updated version of the article making this one obsolete. Please click here to view the article.
For a new project I'm working on I want to display custom error messages that are enclosed in a coloured box depending on the action, for example if a post was successfully saved i want to display a message inside a green box and if it failed i want to display the message in a red box.
Usually i just use the flash messages that are built into the Session helper, these messages are displayed on the next page after the controller has redirected the user. The major limitation of using setFlash() is that only a single message can be displayed, so when this message is displayed in the view there is no way of knowing whether it is a success or failure message. In this post i'm going to go through the process of creating your own helper which will display a custom flash message.
Mysession Helper
Although this might seem a bit overkill for displaying a simple message to the screen i wanted to keep the functionality of the flash messages so that they are only displayed once and then destroyed. For this to happen my new helper will extend the SessionHelper, in object orientated programming when a class extends another class it will inherit all the methods ( another name for a function in a class file) so my new session helper will automatically be able to read, write and delete to the session.
To create my new flash message i will save an array to the session called "flash" this array will contain 2 things. The message to display and whether the message is a "success" or a "failure". When viewing the message it will either be wrapped in a green or red box depending on the message. This will make it incredibly easy for a user to determine if their action on the site was successful or not.
// this code goes in the controller
// using this
$this->Session->write('flash', array('Success: You have successfully logged in.','success'));
// instead of this
//$this->Session->setFlash('You have successfully logged in.');
Now that we have a custom flash message in the session my new helper will read the array and display the message and finally remove it from the session so that it does not display more than once. My new helper looks like this:
// file: /app/views/helpers/mysession.php
/*
* Mysession Helper
* extends the CakePHP session helper
*
*/
class MysessionHelper extends SessionHelper {
// init
var $__active = true;
// constructor
function __construct($base = null) {
// copied from the parent SessionHelper
if (!defined('AUTO_SESSION') || AUTO_SESSION === true) {
parent::__construct($base, false);
} else {
$this->__active = false;
}
}
/*
* flash()
* flashes a message on the screen with a coloured box indicating success, failure or normal
*/
function flash() {
// init
$output = '';
// get the flash msg array from the session
$data = parent::read('flash');
// data looks like this
// $data = array('flash message', 'success');
// delete the session variable
parent::del('flash');
// if the flash message is not empty
if(!empty($data[0])) {
// switch depending on flash type
switch($data[1]) {
case 'success':
// print out a div with a success class
$output .= '<div class="flash_success">';
break;
case 'failure':
// print out a div with a failure class
$output .= '<div class="flash_failure">';
break;
default:
// print out a default flash class
$output .= '<div class="flash">';
break;
}
// save the flash message with the closing div
$output .= $data[0].'</div>';
}
return $output;
}
}
Before we can use our new helper in the view it must be loaded at the top of the controller using:
// load helpers
var $helpers = array('Html', 'Form', 'Mysession');
Finally to print the flash message to the screen we use this piece of code in our view:
// flash customer error msg on screen
echo $mysession->flash();
// cleaner than this
if ($session->check('Message.flash')) {
$session->flash();
}
And for reference here are my styles for the flash boxes:
.flash { border:3px solid #ff9b00; background:#ffcc80; padding:10px; font-weight:bold; margin:15px 0;}
.flash_success { border:3px solid #bedf5d; background:#e2f1a8; padding:10px; font-weight:bold; margin:15px 0;}
.flash_failure { border:3px solid #990000; background:#f97d88; padding:10px; font-weight:bold; margin:15px 0;}
Wrapping Up
With a little bit of extra effort and code our custom flash messages are complete and have some added benefits:
- Views are cleaner with no checking involved.
- Message logic all in one place.
- Can easily change the functionality of the flash message.
Comments
deizel. (07/05/2008 - 03:46)
Good to see another UK cake baker on the scene. I'll be subscribing to your feed.
What version of CakePHP are you using the code in this article on? You might not be aware of this, but in v1.2 you can pass a $layout to the SessionComponent::setFlash() function.
http://api.cakephp.org/1.2/class_session_component.html#0f46011d40587807377decf37088ac12
James (07/05/2008 - 10:51)
Hi Deizel,
I was using 1.1 in this article but have recently been experimenting with 1.2 so thanks for heads up about passing a layout to setFlash().
PandoO (24/05/2008 - 17:09)
Even more, from 22th may, you can add a class too.
http://api.cakephp.org/view_2helpers_2session_8php-source.html
ega (06/10/2008 - 22:18)
hello... it seems to me that the flash message does not show. I don't know why... do i need to set something in the configurations to display the flash message? thanks again!
James (07/10/2008 - 02:31)
@ega: Hi, not sure why its not working, you shouldn't have to set anything in the config files. Are you using this to display the message?
echo $mysession->flash();
Also if your using the CakePHP 1.2 you can pass a layout string that the flash message will use which is easier than creating your own class, look it up in the API or I may do an update to this post later.
Henrik Gemal (02/12/2008 - 01:19)
I'm using CakePHP 1.2 and doing this when having to display a flash message:
$this->Session->setFlash("You have successfully logged in.", "flash_success");
$this->Session->setFlash("Something went wrong.", "flash_error");
then I have a view file called flash_success and one called view_error and it that using content_for_layout. That works really well!
empe (08/05/2009 - 07:00)
hi james,
thanks for great code that you made
but i find something wrong with the code
i'm using cakephp ver 1.2
and i got this notification
"Fatal error: Class 'SessionHelper' not found in E:\xampp\htdocs\freeman\incruitment\app\views\helpers\mysession.php on line 9"
but, i know that sessionhelper is placed in folder cake/libs/view/helpers/session.php, and after i check, the file is exists.
so.. can you help me, what's the problem
great thanks for you :)
James (18/05/2009 - 23:48)
@empe: I'm not sure why you're experiencing problems. It was originally created for CakePHP 1.1 but I'll try and put some time aside to do an updated version.
kwokwai (20/06/2010 - 12:00)
You code is like this:
$this->Session->write('flash', array('Success: You have successfully logged in.','success'));
so why were you trying to check "Message.flash" instead of "flash"?
James (24/06/2010 - 04:52)
@kwokwai: Cake stores the Flash message with a prefix so that's why I'm checking for it instead of just 'flash'
empe (05/08/2010 - 07:23)
hai james, long time no see this post
now, i'm using cakephp 1.3 and i did modify about your code
in first line, add this
if (!class_exists('SessionHelper')) {
require LIBS . 'view' . DS .'helpers' . DS . 'session.php';
}
then remove
parent::del('flash');
with
parent::delete('flash');
perhaps it will work
arigatou :)