We often want to provide users feedback from their actions. Zend Framework
includes the FlashMessenger Action Helper for this purpose.
A gentle trickle of questions appear on the Zend Framework mailing lists
concerning the exact usage of the FlashMessenger, so I'm going to go over the
details here. Hopefully we'll get all those Zend Framework FlashMessenger
questions answered.
We will also introduce the Noumenal PHP Library's FlashMessenger View Helper.
This encapsulates retrieving flash messages and adds the option to send
different
levels of message (e.g. "notice", "warning", "error").
The Noumenal
PHP Library is available on
GitHub.
Overview of the FlashMessenger
Zend Framework's FlashMessenger Action Helper is meant to allow immediate
feedback on the status of a user's actions: "Your profile was updated", "Your
message was sent", "Your junk mail has been deleted".
Here's an example of the sort of thing from Google's Gmail:
Basic usage of the FlashMessenger couldn't be simpler. In your action
controller, you set messages via the
addMessage()
method:
$flashMessenger = $this->_helper->FlashMessenger;
$flashMessenger->addMessage('We did something in the last request');
or via its proxy, the FlashMessenger's
direct()
:
$this->_helper->FlashMessenger('Message stored until needed');
(
Action helpers can each define their own direct()
as a short cut to their core
functionality.)
Under normal circumstances you'd collect any messages when you want to display
them:
//Collect array of messages for display.
$aMessages = $this->_helper->FlashMessenger->getMessages();
And that is all there is to it. Your user performs some action, e.g. sending
their message; you redirect them somewhere sensible and let them know it was
successful.
Note, however, the "Under normal circumstances". There are a couple of
wiggles
that can catch you out. We'll go over these as way of introduction to the
Noumenal PHP Library's FlashMessenger View Helper, which handles these.
Messages are stored until the FlashMessenger is next instantiated
The FlashMessenger stores its messages in a Zend_Session namespace. The data in
that namespace is collected each time the FlashMessenger is instantiated (i.e.
in the constructor). The data in the namespace is also cleared (via
unset()
)
at the same time. This can cause problems for people when they wish to add an
extra action in between setting the messages and retrieving them. If on the
extra request they accidently instantiate the FlashMessenger whilst not wanting
to collect the messages then they find that they are not there when they do want
them later.
The rule here is simple. Contrary to the
bad example in the
documentation, which assigns the FlashMessenger to an instance variable in
the controller's
init()
,
do not get a reference to the FlashMessenger until
you actually need it.
There's also a getCurrentMessages() Method
Sometimes we want to send users a message not for the next request but for the
current one. The obvious example of this is a failed form validation. Here we
output the form with error messages and ask the user to resubmit. Zend_Form has
Decorators specifically for displaying form and element level errors, but beyond
this it's good on the consistency front to send a message via the normal
messaging channel to let the users know that there was a problem.
Calling the regular
getMessages()
method here won't work. This only returns
messages which were stored in the appropriate Zend
Session namespace when the
FlashMessenger was instantiated. Since any messages added this request were not
in the ZendSession namespace at that time (because the FlashMessenger was
instantiated
in order to add the messages) they won't be returned by
getMessages()
.
For just this use-case, the FlashMessenger also provides a
getCurrentMessages()
method (and a related family of
current methods) which
returns those messages set on the current request.
The Noumenal PHP Library's FlashMessenger View Helper
The FlashMessenger View Helper encapsulates the message retrieval side of our interactions with the Zend Framework's FlashMessenger Action Helper. It checks for messages from both previous requests and the current request, so it satisfies our use-case from above. It also interprets key-value pairs, rather than a simple strings, passed to the FlashMessenger as specifying a message-level.
Setting up the View Helper
The first thing to do is to add the call to echo the FlashMessenger View Helper to your layout script, say above the main content:
<html>
<head></head>
<body>
<div id="hd">
<!-- Header -->
</div>
<div id="bd">
<div>
<!-- Main Content -->
<?php echo $this->flashMessenger(); ?>
<?php echo $this->layout()->content; ?>
</div>
<div>
<!-- Sidebar -->
</div>
</div>
<div id="ft">
<!-- Footer -->
</div>
</body>
</html>
Since the layout script is rendered so late in the dispatch process, putting the call the the FlashMessenger View Helper here eliminates most of the risk that you'll accidently instantiate the FlashMessenger Action Helper when you don't
mean to. (Of course this is still possible but if you're going out of your way to instantiate it then we can assume that you'll know to handle any messages that still need to be displayed.)
Adding Messages (with levels) to the FlashMessenger
Adding messages to the FlashMessenger proceeds via the HelperBroker unchanged. Add simple string messages as you normally would:
$this->_helper->FlashMessenger('Your message was sent.');
If you want to specify a message-level pass a key-value pair instead:
$this->_helper->FlashMessenger(
array('error' => 'There was a problem with your form submission.')
);
By default, the FlashMessenger View Helper will render the message within a
p
tag with a class attribute of the message-level key.
Advanced Options to the FlashMessenger View Helper
You can specify the default message-level by passing a string value as the first parameter to
flashMessenger()
. The default message-level is
'warning'
. To change this to
'notice'
, in your layout do:
<?php echo $this->flashMessenger('notice'); ?>
This applies to simple string messages only. If key-value pairs are passed to the FlashMessenger, any message-level key will override the default value set here.
Finally, you can override the default message template by passing a format specifier string (suitable for the
printf
family of functions) as the second parameter. The default template is
<p class="%s">%s</p>
(where the message-level and message fill the respective placeholders).
As an example, if you regularly expected multiple flash messages, you could render messages as an unordered list by doing this in your layout:
<ul>
<?php echo $this->flashMessenger('notice', '<li class="%s">%s</li>');?>
</ul>
Here we have also set the default message-level to
'notice'
.
The FlashMessenger View Helper is part of the Noumenal
PHP Library and is available on
GitHub.