$this->контейнер равен НУЛЮ в контроллере на Symfony3


У меня возникла досадная проблема, когда я вызываю это в контроллере (clientdomaincontroller):

    $this->getDoctrine()->getManager();

Я получил эту ошибку:

    Call to a member function has() on null

Я посмотрел трассировку стека и вижу, что:

    $this->container is null

Мой контроллер расширяется из компонента контроллера Symfony:

    use Symfony\Bundle\FrameworkBundle\Controller\Controller;

Самое забавное, что в другом контроллере (HomeController) Я делаю точно такие же вещи:

  1. Расширение от контроллера (точно такого же класса)
  2. Получить доктрину
  3. Получить Менеджер сущностей
  4. Используйте менеджера

И это без какой-либо ошибки.

Единственное различие между домашним контроллером и контроллером домена клиента заключается в том, что второй является сервисом. Поэтому я написал это в службах.файл yml:

    services:
        client_domain:
            class: AppBundle\Controller\ClientDomainController

Наконец, я протестировал многие вещи, такие как создание конструктора для моего контроллера и добавление его в сервисы.файл yml (вещи, которые a никогда не делал с функциональным файлом):

    arguments: [ 'doctrine.orm.entity_manager' ]
Author: Veve, 2017-10-12

3 answers

Когда вы регистрируете свой контроллер в качестве службы, Symfony создает его точно так, как вы ему говорите.

Таким образом, разница в том, что, хотя ваш контроллер реализует ContainerAwareInterface (через расширение класса Controller), в конце концов никто не вызывает метод setContainer для использования этого интерфейса и установки значения $container. Вы должны сделать это вручную в своих сервисах.конфигурация yml, например:

    calls:
        - [ setContainer, [ @service_container ] ]

Но это не лучшее решение

Регистрация ваших контроллеров в качестве служб хороша в главный. Это делает их более проверяемыми и ремонтопригодными.

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

  1. Ваш экземпляр контроллера может иметь недопустимое состояние, если вы не передадите контейнер (или вам следует учесть, что он может быть установлен не везде, где вы его используете), что плохо по замыслу.
  2. Это трудно проверить, так как вам нужно имитировать весь контейнер, а не только зависимости, которые этот контроллер использует.
  3. Зависимости явно не определены, так как вам нужно заглянуть в код контроллера, чтобы узнать, какие зависимости извлекаются из контейнера.

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

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

 2
Author: Jakub Matczak, 2017-10-12 15:47:16

Ваш контроллер должен быть таким:

class HelperController extends Controller
{

    /**
     * @var \Symfony\Component\DependencyInjection\ContainerInterface
     */
    protected $container;

    /**
     * HelperController constructor.
     *
     * @param ContainerInterface $container
     */
    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }
  }

И в файле конфигурации (в моем случае xml)

    <service id="xxx.helper_controller" class="xxx\EspacePROBundle\Controller\HelperController">
        <argument type="service" id="service_container" />
    </service>

Я надеюсь, что это поможет.

 0
Author: Mohammad Trabelsi, 2018-01-02 13:23:37

Как указано в ответе Якуба Матчака, контейнер DI для контроллера не установлен.

В качестве альтернативы добавлению раздела calls в ваши сервисы.yml вы можете вызвать setContainer в конструкторе класса, в котором вы хотите использовать контроллер.

use App\Controller\MyController;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyClass {

    /**
     * The injected controller
     * @var MyController
     */
    protected $my_controller;

    public function __construct(MyController $my_controller, ContainerInterface $container) {
        $this->my_controller = $my_controller;
        $this->my_controller->setContainer($container);
    }
}
 -1
Author: Johannes Buchholz, 2018-08-14 11:39:49