Skip to content

Lab Instructions: Implementing Flash Messages

In this lab, you will implement a flash messaging system for your Slim 4 application. Flash messages provide temporary user feedback after form submissions, login attempts, and other actions. By the end of this lab, you’ll have a fully functional flash messaging system using Bootstrap alerts.


By completing this lab, you will:

  • Understand what flash messages are and when to use them.
  • Create a FlashMessage helper class for managing temporary messages.
  • Integrate flash messages with the BaseController redirect() method.
  • Display flash messages in views using Bootstrap alerts.
  • Implement the Post-Redirect-Get (PRG) pattern correctly.
  • Handle success, error, info, and warning messages.

Before starting this lab, ensure you have:

  • Completed the Session Middleware lab (flash messages require sessions).
  • A working Slim 4 application with SessionMiddleware registered
  • Basic understanding of the BaseController pattern.
  • Bootstrap CSS included in your views (for styled alerts).
  • Your development environment set up and running.

Step 1: Create the FlashMessage Helper Class

Section titled “Step 1: Create the FlashMessage Helper Class”

Objective: Create a helper class that manages flash messages stored in the session.

Instructions:

  1. Navigate to your app/Helpers/ directory
  2. Create a new file named FlashMessage.php
  3. Copy and paste the following code:
app/Helpers/FlashMessage.php
<?php
namespace App\Helpers;
class FlashMessage
{
private const FLASH_KEY = 'flash_messages';
/**
* Add a success message.
*/
public static function success(string $message): void
{
// TODO: Call the add() method with 'success' as the type
}
/**
* Add an error message.
*/
public static function error(string $message): void
{
// TODO: Call the add() method with 'error' as the type
}
/**
* Add an info message.
*/
public static function info(string $message): void
{
// TODO: Call the add() method with 'info' as the type
}
/**
* Add a warning message.
*/
public static function warning(string $message): void
{
// TODO: Call the add() method with 'warning' as the type
}
/**
* Add a flash message of any type.
*/
public static function add(string $type, string $message): void
{
// TODO: Check if $_SESSION[self::FLASH_KEY] is not set
// If not set, initialize it as an empty array
// TODO: Add a new message to the $_SESSION[self::FLASH_KEY] array
// The message should be an associative array with 'type' and 'message' keys
}
/**
* Get all flash messages and clear them.
*/
public static function get(): array
{
// TODO: Retrieve all messages from $_SESSION[self::FLASH_KEY]
// Hint: Use the null coalescing operator (??) to default to an empty array
// TODO: Remove the flash messages from the session using unset()
// TODO: Return the retrieved messages
}
/**
* Check if there are any flash messages.
*/
public static function has(): bool
{
// TODO: Check if $_SESSION[self::FLASH_KEY] exists and is not empty
// Hint: Use the empty() function
}
/**
* Clear all flash messages without retrieving them.
*/
public static function clear(): void
{
// TODO: Remove the flash messages from the session using unset()
}
/**
* Render all flash messages as Bootstrap alerts.
*
* This method is provided for you as it involves complex HTML generation.
*/
public static function render(bool $dismissible = true): string
{
$messages = self::get();
if (empty($messages)) {
return '';
}
$bootstrapTypes = [
'success' => 'success',
'error' => 'danger',
'info' => 'info',
'warning' => 'warning'
];
$html = '';
foreach ($messages as $flash) {
$type = $bootstrapTypes[$flash['type']] ?? 'info';
$message = htmlspecialchars($flash['message']);
if ($dismissible) {
$html .= <<<HTML
<div class="alert alert-{$type} alert-dismissible fade show" role="alert">
{$message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
HTML;
} else {
$html .= <<<HTML
<div class="alert alert-{$type}" role="alert">
{$message}
</div>
HTML;
}
}
return $html;
}
}
  1. Implement all the TODO comments in the code above
  2. Save the file

What you need to implement:

  • success(), error(), info(), warning() methods - each should call add() with the appropriate type
  • add() method - stores flash messages in the session
  • get() method - retrieves and clears flash messages from the session
  • has() method - checks if flash messages exist
  • clear() method - removes flash messages from the session

Already provided:

  • The render() method that generates Bootstrap alert HTML with XSS protection

Objective: Create a controller to demonstrate flash message functionality.

Instructions:

  1. Navigate to your app/Controllers/ directory
  2. Create a new file named FlashDemoController.php
  3. Implement a controller class that extends BaseController with the following requirements:

Class Structure:

<?php
namespace App\Controllers;
use App\Helpers\FlashMessage;
use DI\Container;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class FlashDemoController extends BaseController
{
public function __construct(Container $container)
{
parent::__construct($container);
}
// TODO: Implement the methods below
}

Controller callback methods to implement:

Create the following public controller callback methods. Each controller callback method should:

  • Accept the standard Slim framework callback method parameters: Request $request, Response $response, array $args
  • Return a Response object
Callback Method NameWhat It Should Do
index()Render the flash/flashIndexView.php view with a title “Flash Messages Demo”
success()Add a success flash message, then redirect to the flash.demo route
error()Add an error flash message, then redirect to the flash.demo route
info()Add an info flash message, then redirect to the flash.demo route
warning()Add a warning flash message, then redirect to the flash.demo route
multiple()Add 2-3 flash messages of different types, then redirect to the flash.demo route

Implementation Hints:

  • Use FlashMessage::success(), FlashMessage::error(), FlashMessage::info(), or FlashMessage::warning()
  • Always use $this->redirect($request, $response, 'route.name') after setting flash messages
  • The message text can be anything descriptive (e.g., “This is a success message!”)
  • For multiple(), set 2-3 different flash messages before redirecting
  1. Save the file

Objective: Add routes for the flash message demo controller.

Instructions:

  1. Open your app/Routes/web-routes.php file
  2. Add the following import at the top:
use App\Controllers\FlashDemoController;
  1. Add these routes:
// Flash message demo routes
$app->get('/flash', [FlashDemoController::class, 'index'])->setName('flash.demo');
$app->post('/flash/success', [FlashDemoController::class, 'success'])->setName('flash.success');
$app->post('/flash/error', [FlashDemoController::class, 'error'])->setName('flash.error');
$app->post('/flash/info', [FlashDemoController::class, 'info'])->setName('flash.info');
$app->post('/flash/warning', [FlashDemoController::class, 'warning'])->setName('flash.warning');
$app->post('/flash/multiple', [FlashDemoController::class, 'multiple'])->setName('flash.multiple');
  1. Save the file

Objective: Create a view that displays flash messages and provides buttons to test each message type.

Instructions:

  1. Navigate to your app/Views/ directory
  2. Create a new folder named flash/
  3. Inside flash/, create a file named flashIndexView.php
  4. Copy and paste the following code:
app/Views/flash/flashIndexView.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?= htmlspecialchars($title ?? 'Flash Demo') ?></title>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<h1 class="mb-4"><?= htmlspecialchars($title ?? 'Flash Demo') ?></h1>
<!-- Flash Messages Display Area -->
<div class="mb-4">
<?= App\Helpers\FlashMessage::render() ?>
</div>
<div class="card">
<div class="card-header">
<h5>Test Flash Messages</h5>
</div>
<div class="card-body">
<p class="card-text">Click the buttons below to test different types of flash messages:</p>
<div class="d-grid gap-2">
<form method="POST" action="flash/success">
<button type="submit" class="btn btn-success w-100">
Show Success Message
</button>
</form>
<form method="POST" action="flash/error">
<button type="submit" class="btn btn-danger w-100">
Show Error Message
</button>
</form>
<form method="POST" action="flash/info">
<button type="submit" class="btn btn-info w-100">
Show Info Message
</button>
</form>
<form method="POST" action="flash/warning">
<button type="submit" class="btn btn-warning w-100">
Show Warning Message
</button>
</form>
<form method="POST" action="flash/multiple">
<button type="submit" class="btn btn-primary w-100">
Show Multiple Messages
</button>
</form>
</div>
</div>
</div>
<div class="alert alert-info mt-4" role="alert">
<strong>Note:</strong> Flash messages appear once and then disappear. Refresh the page to clear any visible messages.
</div>
</div>
<!-- Bootstrap 5 JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
</body>
</html>
  1. Save the file

What you just created:

  • A view that displays flash messages using FlashMessage::render()
  • Buttons to test each message type
  • Bootstrap-styled layout
  • Forms using POST method to demonstrate PRG pattern

Objective: Verify that flash messages work correctly.

Instructions:

  1. Start your development server (if not already running)
  2. Visit http://localhost/[your-app-name]/flash in your browser
  3. Click each button and observe the flash messages:
    • “Show Success Message” → Green alert
    • “Show Error Message” → Red alert
    • “Show Info Message” → Blue alert
    • “Show Warning Message” → Yellow alert
    • “Show Multiple Messages” → Three different alerts

Expected Behavior:

  • Messages appear at the top of the page after redirect
  • Messages have appropriate colors (success=green, error=red, info=blue, warning=yellow)
  • Messages have close buttons (dismissible)
  • Refreshing the page clears all messages
  • Multiple messages can be displayed at once

If messages don’t appear:

  • Verify SessionMiddleware is registered in config/middleware.php
  • Check browser console for JavaScript errors
  • Ensure Bootstrap CSS and JS are loading
  • Verify the FlashMessage::render() line is in your view

MethodDescriptionExample
success($msg)Add a success message (green alert)FlashMessage::success('Saved!')
error($msg)Add an error message (red alert)FlashMessage::error('Invalid input')
info($msg)Add an info message (blue alert)FlashMessage::info('Check your email')
warning($msg)Add a warning message (yellow alert)FlashMessage::warning('Trial ending soon')
add($type, $msg)Add a custom message typeFlashMessage::add('custom', 'Message')
render($dismissible)Display all messages as Bootstrap alerts<?= FlashMessage::render() ?>
get()Retrieve and clear all messages$messages = FlashMessage::get()
has()Check if messages existif (FlashMessage::has())
clear()Clear all messages without retrievingFlashMessage::clear()
  1. Setting: Flash message is stored in $_SESSION['flash_messages']
  2. Redirect: User is redirected to another page (PRG pattern)
  3. Display: Next page renders messages using FlashMessage::render()
  4. Auto-clear: Messages are automatically removed after being retrieved
  5. Result: Message only appears once, then disappears

Cause: SessionMiddleware not registered or sessions not working

Solution:

  • Verify SessionMiddleware is in config/middleware.php
  • Test that sessions work with the /test-session route
  • Check browser accepts cookies

Cause: Calling FlashMessage::render() multiple times

Solution:

  • Only call render() once per page
  • Check your layout/view for duplicate calls

Cause: render() not being called, so messages aren’t cleared

Solution:

  • Ensure FlashMessage::render() is in your view
  • Alternatively, call FlashMessage::get() or clear() manually

Cause: Bootstrap CSS not loaded

Solution:

  • Add Bootstrap CDN link to your view’s <head>:
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">