Почему контейнер запускается до промежуточного программного обеспечения? - PullRequest
0 голосов
/ 02 мая 2020

Если мы посмотрим на концепцию Middleware, опубликованную на веб-сайте slim4 и в других местах.

Она должна быть выполнена до того, как запрос достигнет приложения или при отправке ответа пользователю.

Вопрос в том, что, даже если промежуточное программное обеспечение ранее выполнялось, приложение предварительно вызывает контейнер:

Покажите мне код.

Composer json

"require": {
        "slim/slim": "4.5.*",
        "slim/psr7": "1.0.*",
        "slim/flash": "0.4.*",
        "php-di/slim-bridge": "3.0.*",

config

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

Промежуточное программное обеспечение сеанса

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);
    }
}

Fla sh Контейнер сообщений

class Flash implements ProviderInterface
{

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

Приложение выполнения

...
 // 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();

Результат

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

Fla sh сообщение требует начала сеанса, чтобы работать, это я уже знаю, и Middleware должно нести ответственность за это, но оно всегда выполняется после контейнера

1 Ответ

2 голосов
/ 02 мая 2020

Во-первых, вы используете dependency и container термины, как если бы они были одним и тем же, а не тем.

О проблеме с вашим кодом в методе Flash::register(), вы создаете новый объект из Messages class и помещаете его в контейнер DI. Вы вызываете этот метод и принудительно создаете объект Message, для которого требуется, чтобы сеанс уже был запущен, за до , позволяя промежуточному программному обеспечению начать сеанс. Вы действительно должны избегать хранения объектов в DI C, вместо того, чтобы хранить их определение (как они построены). Я имею в виду следующее изменение:

class Flash implements ProviderInterface
{
    public static function register()
    {
        return app()->getContainer()->set(Messages::class, function() {
            return new Messages();
        });
    }
}
...