0

If we look at the Middleware concept published on the slim4 website and elsewhere.

It should be executed before a request reaches the application or when sending the response to the user.

The question is this, because even if a Middleware is executed before, a container is called before by the application:

Show me the code.

config

'providers' => [,
    App\ServiceProviders\Flash::class => 'http'
],
'middleware' => [
    App\Middleware\Session::class => 'http,console',
],

Session Middleware

class Session
{
    public function __invoke(Request $request, RequestHandler $handler)
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {

            $settings = app()->getConfig('settings.session');

            if (!is_dir($settings['filesPath'])) {
                mkdir($settings['filesPath'], 0777, true);
            }

            $current = session_get_cookie_params();
            $lifetime = (int)($settings['lifetime'] ?: $current['lifetime']);
            $path = $settings['path'] ?: $current['path'];
            $domain = $settings['domain'] ?: $current['domain'];
            $secure = (bool)$settings['secure'];
            $httponly = (bool)$settings['httponly'];

            session_save_path($settings['filesPath']);
            session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);
            session_name($settings['name']);
            session_cache_limiter($settings['cache_limiter']);
            session_start();
        }

        return $handler->handle($request);
    }
}

Flash Message Container

class Flash implements ProviderInterface
{

    public static function register()
    {
        $flash = new Messages();
        return app()->getContainer()->set(Messages::class, $flash);
    }
}

Execution app

...
 // Instantiate PHP-DI ContainerBuilder
    $containerBuilder = new ContainerBuilder();
    AppFactory::setContainer($containerBuilder->build());
    $app = AppFactory::create();


    $providers = (array)$this->getConfig('providers');
    array_walk($providers, function ($appName, $provider) {
        if (strpos($appName, $this->appType) !== false) {
            /** @var $provider ProviderInterface */
            $provider::register();
        }
    });



    $middlewares = array_reverse((array)$this->getConfig('middleware'));
    array_walk($middlewares, function ($appType, $middleware) {
        if (strpos($appType, $this->appType) !== false) {
            $this->app->add(new $middleware);
        }
    });


.... 

$app->run();

Result

`Fatal error: Uncaught RuntimeException: Flash messages middleware failed. Session not found.` 

Flash message needs a session started to work this already I know, and Middleware should be responsible for doing this, but it is always executed after the container

Jerfeson Guerreiro
  • 745
  • 1
  • 10
  • 19
  • 1
    When adding multiple middlewares to an app (or to a route), they form a _stack_, this means the last one you add is the first one being executed. So you need to make sure the session middleware which is responsible for starting a new session is added as the last middleware. – Nima May 02 '20 at 03:37
  • That I understand perfectly, it happens that, there is only one middleware in this project, 1 middleware and 4 containers (dependency) I'm writing a new skeleton for slim 4. Would you like to see the repository, to see if you can help? – Jerfeson Guerreiro May 02 '20 at 03:43
  • 1
    Sure, I'll have a look, but it would be nice if you include all the required information included in the question. I see you're trying to add dependencies to the container after adding the middlewares. That seems to be the problem with your code. Dependencies should be already defined before other parts of code (which depend on them) are being executed. – Nima May 02 '20 at 04:26
  • This is the repository. I would appreciate it very much if you can help me untie this knot. https://github.com/jerfeson/slim4-skeleton – Jerfeson Guerreiro May 02 '20 at 05:22
  • 2
    Please add all relevant details to your question - external resources can change at any time and won't be useful for people who come across the question in the future. In particular, add your middleware sequence and how you've configured these containers. Adding debug information about middlewares and dependencies being registered and in what sequence would also be useful. Making people dig through a git repository to find the relevant information should be avoided. – MatsLindh May 02 '20 at 07:03
  • @MatsLindh please check if it is better now ,. – Jerfeson Guerreiro May 03 '20 at 01:43

1 Answers1

2

First, you are using dependency and container terms as if they are the same thing, which they are not.

About the problem with your code, in Flash::register() method, you are creating a new object from Messages class and putting this in the DI container. You are calling this method and forcing creation of the Message object, which needs the session to be already started, before letting the middleware start the session. You really should avoid storing objects in DIC, instead of storing their definition (how they are built). The following change is what I mean:

class Flash implements ProviderInterface
{
    public static function register()
    {
        return app()->getContainer()->set(Messages::class, function() {
            return new Messages();
        });
    }
}
Nima
  • 3,309
  • 6
  • 27
  • 44