# Execute middleware after route

**URL:** https://discourse.slimframework.com/t/execute-middleware-after-route/5506
**Category:** Questions
**Created:** [February 1, 2023, 4:38pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506 "2023-02-01T16:38:46Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![webcimes](https://avatars.discourse-cdn.com/v4/letter/w/8dc957/32.png) [@webcimes](https://discourse.slimframework.com/u/webcimes)
#### Post date: [February 1, 2023, 4:38pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/1 "2023-02-01T16:38:46Z")

</div>

Hi,

I try to create a simply flash middleware that unset `$_SESSION['flash']` after my page render.

Inside my index.php I have:

```auto
$app = AppFactory::create();
$app->add(FlashMiddleware::class);
$app->addErrorMiddleware(true, true, true);
$app->get('login', App\Controllers\LoginController::class.':index')->setName('login');

```

Inside my FlashMiddlware I have:

```auto
class FlashMiddleware extends Middleware
{
    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): Response
    {
        // Get response
        $response = $handler->handle($request);

        // Unset flash SESSION 
        if(isset($_SESSION['flash']))
        {
            unset($_SESSION['flash']);
        }
        
        // Return response
        return $response;
    }
}

```

And inside my LoginController I have:

```auto
public function index(ServerRequestInterface $request, ResponseInterface $response, array $args)
    {
        $args['flash'] = $_SESSION['flash'];
        return $this->render($response, 'login.php', $args);
    }

```

But when I set my flash session with some message, and I redirect to my `/login` page, I can’t get the value of my `$_SESSION['flash']`, it’s already unset by my FlashMiddleware, so how I can tell to FlashMiddleware to execute after I get this value on my LoginController ?

Thanks

---

<div class="post-metadata">

### Author: ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)
#### Post date: [February 1, 2023, 7:36pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/2 "2023-02-01T19:36:53Z")

</div>

Hi @webcimes Instead of using a middleware to unset the value, you may try to add a Flash message class that deletes the value after it has been fetched from the session.

You may also try to use the [slim/message](https://github.com/slimphp/Slim-Flash) package instead.

---

<div class="post-metadata">

### Author: ![webcimes](https://avatars.discourse-cdn.com/v4/letter/w/8dc957/32.png) [@webcimes](https://discourse.slimframework.com/u/webcimes)
#### Post date: [February 2, 2023, 11:06am UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/3 "2023-02-02T11:06:51Z")

</div>

Hi @odan, thanks for your answer, with the “slim/message” it’s working well for my controllers and views.  
But I have another problem, in some routes I call a middleware for specific route, for auth the user like this:

```auto
$app->get('/admin', App\Controllers\AdminController::class.':index')->setName('admin')->add(new AuthMiddleware(['ADMIN']));

```

In the AuthMiddleware.php I check if the user has the right roles, and if the roles are wrong for the user, I redirect the user to login page with a flash message like this :

```auto
class AuthMiddleware extends Middleware
{
    private $tabLevels;

    public function __construct(array $tabLevels = [])
    {
        $this->tabLevels = $tabLevels;
    }

    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): Response
    {

        $response = $handler->handle($request);

        // My code for check roles

        $this->container->get('flash')->addMessage('errorMessage', $errorMessage);;
        return $response->withHeader('Location', '/login')->withStatus(302);
    }
}

```

and in my Middleware.php class:

```auto
class Middleware
{
    public $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }
}

```

But I get an error “Call to a member function get() on null” for the file AuthMiddleware.php, but In the my Controllers class I have the same type of code (and extend to Controller for get the container) and it’s working well, so I don’t understand why I get this error ?

Thanks for your help

---

<div class="post-metadata">

### Author: ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)
#### Post date: [February 2, 2023, 12:13pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/4 "2023-02-02T12:13:46Z")

</div>

Within the application, the DI container should not be used directly. Instead the DI container should inject the dependencies for you when you declare it within a class constructor.

To solve this issue, make sure that you set up the DI container correctly for autowiring.  
Then declare the `Message` class instead of the DI container within the constructor of the middleware.

---

<div class="post-metadata">

### Author: ![webcimes](https://avatars.discourse-cdn.com/v4/letter/w/8dc957/32.png) [@webcimes](https://discourse.slimframework.com/u/webcimes)
#### Post date: [February 2, 2023, 8:57pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/5 "2023-02-02T20:57:58Z")

</div>

Thanks for your help, I don’t understand everything, I have declare my DI container like this (I think autowiring is active by default):

```auto
<?php

use DI\Container;
use Slim\Flash\Messages;
use Slim\Factory\AppFactory;

// Create Container
$container = new Container();
AppFactory::setContainer($container);

// Set flash in Container
$container->set('flash', function()
{
    $storage = [];
    return new Messages($storage);
});

```

Then in my FlashMiddleware I have try two ways but I don’t get it.

First try:

```auto
<?php

namespace App\Middlewares;

use DI\Container;
use Slim\Psr7\Response;
use App\Middlewares\Middleware;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * Flash Middleware
 */
class FlashMiddleware extends Middleware
{
    public $container;

    public function __construct(Container $container)
    {
        $this->container = $container;
    }
    
    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): Response
    {
        // Change flash message storage
        $this->container->get('flash')->__construct($_SESSION);

        // Return response
        return $handler->handle($request);
    }
}

```

Second try:

```auto
<?php

namespace App\Middlewares;

use Slim\Psr7\Response;
use Slim\Flash\Messages;
use App\Middlewares\Middleware;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

/**
 * Flash Middleware
 */
class FlashMiddleware extends Middleware
{
    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): Response
    {
        new Messages($_SESSION);

        // Return response
        return $handler->handle($request);
    }
}

```

I don’t know if it’s the good way to do this (first try or second try) ?

Thanks

---

<div class="post-metadata">

### Author: ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)
#### Post date: [February 3, 2023, 12:13pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/6 "2023-02-03T12:13:44Z")

</div>

I think neither the first nor the second is a good way to go because the DI container should not be injected. I would recommend declaring the `Slim\Flash\Messages` within the Middleware constructor instead.

Make sure the DI container can inject the Messages instance:

```php
use Slim\Flash\Messages;
// ...

$container->set(Messages::class, function()
{
    $storage = [];
    return new Messages($storage);
});

```

The middleware constructor:

```php
use Slim\Flash\Messages;
// ...

public function __construct(Messages $flash)
{
    $this->flash = $flash;
}

```

---

<div class="post-metadata">

### Author: ![webcimes](https://avatars.discourse-cdn.com/v4/letter/w/8dc957/32.png) [@webcimes](https://discourse.slimframework.com/u/webcimes)
#### Post date: [February 3, 2023, 9:05pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/7 "2023-02-03T21:05:10Z")

</div>

Thanks foŕ your help, I didn’t know that we could set the class directly with the container, it’s seems to work with controller but in my authMiddleware I get an error when I try to add a message

Just for be sure, the constructor is enough to call the flash class from the container ? I don’t need this ?

```auto
$this->flash = $container->get(Flash::class);

```

My custom Middlewares class:

```auto
<?php
namespace App\Middlewares;

use Slim\Flash\Messages;

class Middleware
{
    public $flash;
    public $test;

    public function __construct(Messages $flash)
    {
        $this->flash = $flash;
        $this->test = 'test';
    }
}

```

And in my authMiddleware class I get this error:

```auto
Call to a member function addMessage() on null

```

I have also try to put a simple variable “test” into the constructor and in my authMiddleware if I do an `echo $this->test;` I get nothing. So I think the extends not working / get constructor on middleware class ? Can you confirm ?

```auto
class AuthMiddleware extends Middleware
{
    public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): Response
    {
        $this->flash->addMessage('errorMessage', 'test');
        exit($this->test);
    }
}

```

Thanks

---

<div class="post-metadata">

### Author: ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)
#### Post date: [February 5, 2023, 12:14pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/8 "2023-02-05T12:14:05Z")

</div>

It seems like the `$flash` object is not being properly instantiated in your Middleware class. A typical middleware should also implement the `Psr\Http\Server\MiddlewareInterface`.

In order for Slim or the DI container to be able to create your Middleware objects correctly, you may use this syntax when you add a middleware:

```php
use App\Middleware\MyMiddleware;

$app->add(MyMiddleware::class);

```

There are other things to consider when using this flash message package. You can find a complete article in my new [Slim 4 eBook Vol. 2](https://odan.github.io/donate.html).

---

<div class="post-metadata">

### Author: ![webcimes](https://avatars.discourse-cdn.com/v4/letter/w/8dc957/32.png) [@webcimes](https://discourse.slimframework.com/u/webcimes)
#### Post date: [February 6, 2023, 8:48am UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/9 "2023-02-06T08:48:15Z")

</div>

Ok thanks it’s working with normal class call, but I have just a last question, in my root I call my AuthMiddleware class for specific route, with specific parameters (array of level authorized).

So I can’t do something like this:

```auto
$app->get('/admin', App\Controllers\AdminController::class.':index')->setName('admin')->add(AuthMiddleware::class);

```

And I must do this for pass my parameters (array of level authorized) to my constructor:

```auto
$app->get('/admin', App\Controllers\AdminController::class.':index')->setName('admin')->add(new AuthMiddleware(['SUPERADMIN','ADMIN']));

```

But it create a problem to instancie Messages class with autowiring in authMiddleware, because I need to also pass the “Messages” parameter when I add the AuthMiddleware class to my route, because I use `new AuthMiddleware(['SUPERADMIN','ADMIN'])`.

My AuthMiddleware constructor:

```auto
<?php

namespace App\Middlewares;

use Slim\Flash\Messages;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;

final class AuthMiddleware implements MiddlewareInterface
{
    private $tabLevels;
    private $flash;

// Problem here because I need to get my TabLevels, 
// so I also need to pass Messages parameters when I call this class in the route file.
    public function __construct(array $tabLevels = [], Messages $flash)
    {
        $this->tabLevels = $tabLevels;
        $this->flash = $flash;
    }

    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    // public function __invoke(ServerRequestInterface $request, RequestHandlerInterface $handler): Response
    {
.... my code

```

What is the best way to do it in this case?

Thanks for your time, I will look to your eBook

---

<div class="post-metadata">

### Author: ![odan](https://avatars.discourse-cdn.com/v4/letter/o/9de053/32.png) [@odan](https://discourse.slimframework.com/u/odan)
#### Post date: [February 6, 2023, 12:53pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/10 "2023-02-06T12:53:22Z")

</div>

To solve this issue, you may consider the following approaches:

1. Creating different `AuthMiddleware` classes: Instead of having a single `AuthMiddleware` class, you can create separate classes for different authorization levels.
2. Using a Factory class: You can create a factory class that creates and returns an instance of the `AuthMiddleware` class with the required authorization level. This way, you need tho fetch the Container instance from the App instance within the routes, which is not a good practice.
3. Checking the route within the `AuthMiddleware`: Within the `AuthMiddleware` class, you can access the current route from the `$request` object and determine the required authorization level based on the route name. This way, you don’t need to create different middleware classes or a factory class, and can determine the authorization level dynamically.

---

<div class="post-metadata">

### Author: ![webcimes](https://avatars.discourse-cdn.com/v4/letter/w/8dc957/32.png) [@webcimes](https://discourse.slimframework.com/u/webcimes)
#### Post date: [February 6, 2023, 8:18pm UTC](https://discourse.slimframework.com/t/execute-middleware-after-route/5506/11 "2023-02-06T20:18:22Z")

</div>

Ok it’s make sense, I will choose the option (3) I think it’s the better way to do this.

Thanks for your help.
