The problem is that Slim\Flash\Messages relies on $_SESSION by default. But the session is not startet if you define the container definition. The session should be startet later in a middleware.
To solve this I define an array as default flash storage and change it after the session has been startet to $_SESSION as flash storage.
Example:
// config/container.php
use Slim\Views\Twig;
use Slim\Flash\Messages;
// ...
// flash
Messages::class => function () {
// Array as default storage
// Later the storage will be changed to $_SESSION
$storage = [];
return new Messages($storage);
},
Then add this session middleware to start the session and change the flash storage:
<?php
namespace App\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Flash\Messages;
class SessionStartMiddleware implements MiddlewareInterface
{
/**
* @var Messages
*/
private $flash;
public function __construct(Messages $flash)
{
$this->flash = $flash;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
// Check that the session hasn't already been started
if (session_status() !== PHP_SESSION_ACTIVE && !headers_sent()) {
session_start();
}
// Change the storage
$this->flash->__construct($_SESSION);
return $handler->handle($request);
}
}
use App\Middleware\SessionStartMiddleware;
//...
$app->add(SessionStartMiddleware::class);
Then add a message:
$this->flash->addMessage('success', 'You are now logged in.');
To show all flash messages in twig:
<div class="ui container flash">
{% for name, messages in flash.getMessages() %}
<div class="ui {{ name }} message">
<div class="header">
{% for message in messages %}
{{ message }}
{% endfor %}
</div>
</div>
{% endfor %}
</div>
I don’t understand the first two code samples… where do you put those? What do they do? (I don’t have a config/container.php and I’m not familiar with the notation.)
You’re right, I’m using slim/twig-view 2.5.1, that’s because I’m still using Twig 1.x; slim/twig-view 3 works with Twig 3 (Planning to upgrade Twig itself, and a bunch of others things, once done upgrading Slim.)
However, I don’t believe that’s the source problem, seeing as all my views render fine and I’m able to access Flash variables through PHP, e.g.:
$app->get('/tests/flash/php/', function ($request, $response, $args) {
$this->get('flash')->addMessage(
'hello',
"is it me you're looking for? (PHP)"
);
return $response->withStatus(302)->withHeader(
'Location',
'/tests/flash/php/get/'
);
});
$app->get('/tests/flash/php/get/', function ($request, $response, $args) {
$messages = $this->get('flash')->getMessages();
print_r($messages);
// Get the first message from a specific key
$test = $this->get('flash')->getFirstMessage('hello');
print_r($test);
return $response;
});
…works fine, visiting the 1st route will redirect to the 2nd, where the Flash value will be shown as expected.
offsetSet is the Pimple (Slim 3) of doing things. What’s the equivalent in Slim 4?
EDIT: and $_SESSION contains the expect flash messages… so the challenge really is in making {{ flash.getMessages }} / {{ flash.message('x') }} available to Twig.
offsetSet is the Pimple (Slim 3) of doing things. What’s the equivalent in Slim 4?
Pimple has been replaced by a PSR-11 container interface, e.g. PHP-DI. So the answer depends on the container implementation. Overwriting an container entry afterwards could cause some strange bugs, because other instances could still keep the old (flash) reference.
You could register a global Twig variable, e.g. flash.