-
Notifications
You must be signed in to change notification settings - Fork 0
Recipe Flash Messages
Show a one-time message after a redirect (the classic "Saved successfully!"
banner) using a short per-key TTL and pull() so the message is read exactly
once.
A flash message should appear on the next request and then vanish. Two mechanisms combine here:
-
pull()reads the value and removes it in the same call, so the message cannot be shown twice. - A short per-key TTL is a safety-net: if the user never lands on the page that reads the flash (closed the tab, etc.), the message expires on its own instead of lingering. See TTL & Expiry.
use InitPHP\Cookies\Cookie;
function flash(string $type, string $message): void
{
$cookie = new Cookie('app_session', getenv('COOKIE_SALT'));
// 60s is plenty to survive a redirect; it self-cleans if unread.
$cookie->set('flash_type', $type, 60);
$cookie->set('flash_message', $message, 60);
$cookie->send(); // before the redirect header / any output
}
// In a controller after a successful action:
flash('success', 'Your profile was saved.');
header('Location: /profile');use InitPHP\Cookies\Cookie;
function consumeFlash(): ?array
{
$cookie = new Cookie('app_session', getenv('COOKIE_SALT'));
if (!$cookie->has('flash_message')) {
return null;
}
$flash = [
'type' => $cookie->pull('flash_type', 'info'),
'message' => $cookie->pull('flash_message'),
];
// pull() removed both keys from the working copy; persist that.
$cookie->send();
return $flash;
}
// In your view layer:
$flash = consumeFlash();
if ($flash !== null) {
// render the banner with $flash['type'] and $flash['message']
}Output for a single round trip:
['type' => 'success', 'message' => 'Your profile was saved.']
A second consumeFlash() on a later request returns null — pull() already
removed the keys.
Wrapping the two calls keeps controllers tidy. Type-hint
CookieInterface so the helper is easy to
test:
use InitPHP\Cookies\CookieInterface;
final class FlashBag
{
public function __construct(private CookieInterface $cookie) {}
public function add(string $message, string $type = 'info', int $ttl = 60): void
{
$this->cookie->set('flash_message', $message, $ttl);
$this->cookie->set('flash_type', $type, $ttl);
}
/** @return array{type: string, message: string}|null */
public function consume(): ?array
{
if (!$this->cookie->has('flash_message')) {
return null;
}
return [
'type' => (string) $this->cookie->pull('flash_type', 'info'),
'message' => (string) $this->cookie->pull('flash_message'),
];
}
}Note: the promoted-property constructor above is PHP 8 syntax. Under PHP 7.4 use a classic constructor body assigning
$this->cookie = $cookie;.
Remember to send() the underlying Cookie once per request (after add()
on the writing request, after consume() on the reading request). See
Testing for wiring FlashBag to a recording writer in tests.
-
Using
get()instead ofpull().get()leaves the message in place, so it shows again on the next page load until the TTL expires. -
Forgetting
send()afterconsume().pull()removes the keys from the working copy, but the browser still holds the old values until yousend()the emptied state. - TTL too short. If the redirect or round trip can take longer than the TTL (slow networks, intermediate auth), the flash may expire before it is read. A minute is a safe default.
-
Storing rich data. Flash values are scalars only. To carry structured
data,
json_encode()it into a string and decode on read. See Basic Usage.
-
Reading & Removing —
pullvs.get. - TTL & Expiry — the short per-key TTL safety-net.
- Recipe: Remember Me — a long-lived counterpart.
initphp/cookies · MIT License · part of the InitPHP family
Source · Issues · Discussions · Packagist · Contributing · Security Policy
Getting Started
Core Usage
Reference
Practical Guides
Migration & Help