Flash Messages in CakePHP 4

This replaces the old and outdated v2+ article about this topic.

Looking back at v3

As the old article was still from CakePHP 2 days, the CakePHP 3 version was already its own plugin.
It was moved to a standalone Flash plugin and further enhanced with for example AJAX handling by including them in the header.

You could already directly use the following 4 types:

  • ->success() (+ transientSuccess())
  • ->info() (+ transientInfo())
  • ->warning() (+ transientWarning())
  • ->error() (+ transientError())

So what’s new in 2020

In the new CakePHP 4 version (v2 of the plugin), we can now also work with the Flash component more easily.
Especially regarding AJAX it now has a key change included, that really makes quite the difference here:
In that case, it doesn’t write to session anymore but serves the messages completely through the built-in transient approach.
Let me explain that now a bit more in the next paragraph.

Next or Same Request

This is the key question you need to ask yourself.
If you want to persist a flash message (usually either success or error) for after a redirect, you clearly need to store it in the session.
Here the next request can read and display it.
What it needs here to function properly is the assurance that the next request (directly the one after the redirect) will consume it.
In case another request would come in, or the redirect dies, a different page might consume it on top, creating a confusing response.

AJAX

There are now also some requests, that by definition would need to return the messages directly in the response, and those are AJAX ones.
So for the same request, you want to make sure, they are passed along in the header (X-Flash) for example, so the frontend JS code can handle and display those.

In the new version the normal calls to ->success() or ->error() are in this case also auto-transformed into transient ones.
So we don’t even write them to session anymore, as it is clear that those should not appear on a different request, even if not processed now in this same one for some reason (exceptions or alike).
So we basically now removed side effects from flash message handling. If they are not processed by the end of this AJAX request and given to the view to handle, then sure any other non-AJAX request doesn’t want to have to deal with those.

Use cases

This is now especially useful for cases, where you want to serve the same controller action for both normal and AJAX requests.
With this now, there is no need to change anything – it will work out of the box for both.
Often, you would use this for view-less POST only actions like delete, toggle active/inactive and alike.
This plays well together with the Ajax plugin that further helps to keep the code here agnostic and simple.

Let’s image, we have the following delete action in use:

public function delete($id = null) {
    $this->request->allowMethod(['post', 'delete']);
    $message = $this->Messages->get($id);

    $this->Messages->delete($message);
    $this->Flash->success(__('The message has been deleted.'));

    return $this->redirect(['action' => 'index']);
}

Now using our Flash and Ajax plugin, we can AJAX post to the same action, and will get a response with the redirect it would have been redirected in the body, and the flash messages in the header.
So to access the flash messages, we parse the JSON in the X-Flash header:

$.ajax({
    beforeSend: function(xhr) {
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    },
    type: 'post',
    url: ...,
}).success(function(response, textStatus, xhr) {
    var flash = xhr.getResponseHeader("X-Flash");
    var messages = JSON.parse(flash);

    if (messages) {
        $.each(messages, function(index, message) {
            if (message.type === 'error') {
                // display message.message
            }
            ...
        });
    }

Note: The Ajax plugin could also be used standalone, in that case the messages would go into the body as _messages key.
But here the session would be used and we would have side-effects across requests here once in a while. So Ajax alone should not be used if possible.

Demos

Check out the demos in the sandbox.

0.00 avg. rating (0% score) - 0 votes

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.