Closed gRegorLove closed 1 year ago
The DI container is not tied to a specific HTTP request context, whereas the Session instance is specific to the HTTP context. Therefore, if you instantiate Twig before the SessionStartMiddleware
initiates the actual session handler, both the session and its flash storage in Twig will be empty. This is because the session hasn't been started when the DI container is being defined.
To correctly load the Flash reference in Twig, you must pass the flash variable within the HTTP-specific context. Implement a middleware to achieve this:
First, remove Session (and Twig-Environment) -specific lines from the DI container definition:
$environment = $twig->getEnvironment();
$session = $container->get(SessionInterface::class);
$environment->addGlobal('flash', $session->getFlash());
Next, add a middleware to set the appropriate Flash instance as a global variable in Twig:
File: src/Middleware/TwigFlashMiddleware.php
<?php
namespace App\Middleware;
use Odan\Session\SessionInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Views\Twig;
final class TwigFlashMiddleware implements MiddlewareInterface
{
private Twig $twig;
private SessionInterface $session;
public function __construct(Twig $twig, SessionInterface $session)
{
$this->twig = $twig;
$this->session = $session;
}
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
): ResponseInterface {
$flash = $this->session->getFlash();
$this->twig->getEnvironment()->addGlobal('flash', $flash);
return $handler->handle($request);
}
}
Then add the TwigFlashMiddleware::class
before the SessionStartMiddleware::class
.
// ...
$app->add(TwigFlashMiddleware::class);
$app->add(SessionStartMiddleware::class);
// ...
I hope this helps.
Thanks so much! I'll try this out.
That worked a charm!
Next, add a middleware to set the appropriate Flash instance as a global variable in Twig:
This is super helpful and should be in the docs under Twig section.
I'm having an issue where I can add flash messages from a Controller or Service class and confirm the messages are in flash storage with a debug of the
getFlash()
method, but then they don't appear in the Twig template.General usage of the
get
andset
methods is working OK. For example I can authenticate a user and store their information in the session for subsequent page views.Environment: odan/session: 6.1.0 slim: 4.12.0 slim/twig-view: 3.2.0 php-di: 6.3.4 php-di/slim-bridge: 3.4.0
My relevant container definitions:
In a Twig partial I have:
Then in a Controller method:
That debug (
dd
) call shows the message in storage:But if I remove the debug call and let the Twig template load, it doesn't display the message.
I thought there might be an issue with scope of included Twig partials, so tried debugging directly in index.twig:
{{ debug(flash) }}
shows it's a Flash object, but it appears to be empty:I've also tried this with setting a flash message on one page and redirecting to another, but the same thing happens.
I realize this might be an issue with my PHP-DI configuration, but I've tried a lot of variations and haven't had luck. I wanted to ask here in case you have any examples of Slim+PHP-DI+Twig implementations of this. I checked your slim-skeleton package and didn't see it there.
Oh, almost forgot. I did try changing the order of middleware but that doesn't seem to have an impact. Initially I had:
And I tried moving the SessionStartMiddleware below the TwigMiddleware:
Thanks for any pointers you might have!