Я пытаюсь получить доступ к $container из своего промежуточного программного обеспечения, но мне не очень везет.

В моем файле index.php у меня есть

require '../../vendor/autoload.php';
include '../bootstrap.php';

use somename\Middleware\Authentication as Authentication;

$app = new \Slim\App();
$container = $app->getContainer();
$app->add(new Authentication());

А еще у меня есть такой класс Authentication.php

namespace somename\Middleware;

class Authentication {
  public function __invoke($request, $response, $next) {
    $this->logger->addInfo('Hi from Authentication middleware');

Но я получаю сообщение об ошибке

Неопределенное свойство: somename \ Middleware \ Authentication :: $ logger in ***

Я также пробовал добавить в класс следующий конструктор, но тоже не получаю радости.

 private $container;

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

Может ли кто-нибудь помочь?

0
davidjh 5 Янв 2018 в 21:34

2 ответа

Лучший ответ

Лучшая практика реализации промежуточного программного обеспечения выглядит примерно так:

Поместите этот код в раздел зависимостей:

$app = new \Slim\App();
$container = $app->getContainer();
/** Container will be passed to your function automatically **/
$container['MyAuthenticator'] = function($c) {
    return new somename\Middleware\Authentication($c);
};

Затем внутри вашего класса аутентификации создайте функцию конструктора, как вы упомянули: namespace somename \ Middleware;

class Authentication {
    protected $container;

    public function __invoke($request, $response, $next)
    {
        $this->container->logger->addInfo('Hi from Authentication middleware');
    }

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

    /** Optional : Add __get magic method to easily use container 
        dependencies 
        without using the container name in code 
        so this code : 
        $this->container->logger->addInfo('Hi from Authentication middleware'); 
        will be this :
        $this->logger->addInfo('Hi from Authentication middleware');
    **/

    public function __get($property)
    {
        if ($this->container->{$property}) {
            return $this->container->{$property};
        }
    }
}

После того, как внутри вашего index.php добавьте промежуточное ПО, используя разрешение имен следующим образом:

$app->add('MyAuthenticator');
3
Ali Kaviani 6 Янв 2018 в 07:56

Я не согласен с ответом Али Кавиани. При добавлении этой функции __magic (__get) PHP, код будет намного сложнее протестировать.

Все необходимые зависимости должны быть указаны в конструкторе. Преимущество состоит в том, что вы можете легко увидеть, какие зависимости имеет класс, и поэтому вам нужно только имитировать эти классы в модульных тестах, иначе вам пришлось бы создавать контейнер в каждом тесте. Также Keep It Simple Stupid

Я покажу это на примере регистратора:

class Authentication {
    private $logger;

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

    public function __invoke($request, $response, $next) {
        $this->logger->addInfo('Hi from Authentication middleware');
    }
}

Затем добавьте в контейнер промежуточное ПО с параметром logger:

$app = new \Slim\App();
$container = $app->getContainer();
$container['MyAuthenticator'] = function($c) {
    return new somename\Middleware\Authentication($c['logger']);
};

Примечание: указанную выше регистрацию в контейнере можно выполнить автоматически с помощью PHP-DI Slim. (но это также должно быть медленнее).

0
jmattheis 7 Янв 2018 в 10:25