Как получить доступ к $container в классе промежуточного программного обеспечения в Slim v3?

Я читал, что в Slim v2 $app был привязан к классу промежуточного программного обеспечения. Я считаю, что это не так в v3? Ниже приведен мой класс промежуточного программного обеспечения, но я просто не определен:

<?php
namespace CrSrc\Middleware;

class Auth
{
    /**
     * Example middleware invokable class
     *
     * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
     * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
     * @param  callable                                 $next     Next middleware
     *
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function __invoke($request, $response, $next)
    {
        // before

var_dump($this->getContainer()); // method undefined
var_dump($this->auth); exit; // method undefined
        if (! $this->get('auth')->isAuthenticated()) {
            // Not authenticated and must be authenticated to access this resource
            return $response->withStatus(401);
        }

        // pass onto the next callable
        $response = $next($request, $response);

        // after


        return $response;
    }
}

Каков правильный способ доступа к контейнеру DI в промежуточном программном обеспечении? Я предполагаю, что должен быть способ?


person Martyn    schedule 17.01.2016    source источник


Ответы (2)


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

$container = $app->getContainer();
$app->add(new Auth($container));

И вашему промежуточному ПО нужен конструктор

<?php
namespace CrSrc\Middleware;

class Auth
{

    private $container;

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

    /**
     * Example middleware invokable class
     *
     * @param  \Psr\Http\Message\ServerRequestInterface $request  PSR7 request
     * @param  \Psr\Http\Message\ResponseInterface      $response PSR7 response
     * @param  callable                                 $next     Next middleware
     *
     * @return \Psr\Http\Message\ResponseInterface
     */
    public function __invoke($request, $response, $next)
    {
        // $this->container has the DI

    }
}

LE: Немного расширив первоначальный ответ, контейнер внедряется в конструктор. если вы предоставляете промежуточное ПО в виде класса string

$app->add('Auth');

or

$app->add('Auth:similarToInvokeMethod')
person the-noob    schedule 18.02.2016
comment
Спасибо. Я думаю, в конце концов, я просто предположил, что это был путь в v3. Кажется, работает хорошо в любом случае. - person Martyn; 18.02.2016
comment
Отличный ответ. Многие люди, использующие Slimphp, ищут этот ответ, но он скрыт за кустами, известными как внедрение зависимостей. Спасибо! - person user2800382; 16.01.2018

Насколько я понимаю код, Slim (v3) работает следующим образом:

  • если вы передаете закрытие как промежуточное ПО, оно вызывает bindTo с контейнером в качестве параметра.
  • если вы передаете класс/строку, которая разрешается в класс, тогда Слим создает экземпляр и передает контейнер как параметр конструктору

    <?php
    $app->add(Auth);
    
  • в противном случае (например, если вы добавите экземпляр промежуточного программного обеспечения, созданный ранее), похоже, вам придется позаботиться о передаче всех необходимых ссылок.

person Rafael    schedule 21.01.2016
comment
Это частично верно: bindTo применяет Closures при передаче в качестве промежуточного программного обеспечения, но если вы передаете класс, он ничего не предоставит в конструкторе. - person the-noob; 18.02.2016
comment
@the-noob Я только что протестировал его с Slim 3.0.0 и добавил промежуточное ПО, используя $app->add(ClassName) созданный экземпляр ClassName, предоставляющий контейнер в качестве первого параметра конструктору. - person Rafael; 18.02.2016
comment
это происходит только в том случае, если вы предоставляете вызываемое промежуточное ПО в виде строки. Он будет отправлен на CallableResolver::resolve и этот метод создаст экземпляр вашего класса. Я предполагаю, что неправильное утверждение class/string... на самом деле это просто string. - person the-noob; 18.02.2016
comment
Для теста, упомянутого в предыдущем комментарии, я передал имя класса напрямую, а не в виде строки. Дело в том, что вызов $app->add(ClassName) PHP обрабатывает параметр как строку, потому что классы в PHP не являются гражданами первого класса. Таким образом, он проходит через путь строки внутри файла CallableResolver::resolve. - person Rafael; 18.02.2016