簡體   English   中英

$ this-> container在Symfony3上的Controller中為NULL

[英]$this->container is NULL in Controller on Symfony3

當我在控制器(ClientDomainController)中調用它時,我遇到了一個煩人的問題:

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

我收到此錯誤:

    Call to a member function has() on null

我查看了堆棧跟蹤,發現:

    $this->container is null

我的控制器來自Symfony Controller組件:

    use Symfony\Bundle\FrameworkBundle\Controller\Controller;

有趣的是,在另一個控制器(HomeController)中,我做了完全一樣的事情:

  1. 從Controller擴展(完全相同的類)
  2. 獲取學說
  3. 獲取EntityManager
  4. 使用經理

而且這沒有任何錯誤。

HomeController和ClientDomainController之間的唯一區別是第二個是服務。 所以我把它寫在services.yml文件中:

    services:
        client_domain:
            class: AppBundle\Controller\ClientDomainController

最后,我測試了很多事情,例如在控制器中創建一個構造函數,並將其添加到services.yml文件中(從不對功能函數執行此操作):

    arguments: [ 'doctrine.orm.entity_manager' ]

然后,當您將控制器注冊為服務時,Symfony會像您說的那樣創建它。

因此區別在於,盡管您的控制器實現了ContainerAwareInterface (通過擴展Controller類),但最終沒有人調用setContainer方法來利用此接口並設置$container的值。 您必須在services.yml配置中手動執行此操作,例如:

    calls:
        - [ setContainer, [ @service_container ] ]

但這不是最好的解決方案

將您的控制器注冊為服務通常是好的。 它使它們更具可測試性和可維護性。

但這是正確的,只要您遵守OOP的良好規則即可 在這種情況下,當您傳遞整個容器時,這意味着:

  1. 如果您不傳遞容器,則控制器實例的狀態可能無效(或者應該處理它可能不會在使用它的任何地方設置),這在設計上是很糟糕的。
  2. 很難測試,因為您必須模擬整個容器,而不僅僅是模擬該控制器使用的依賴項。
  3. 沒有明確定義依賴關系,因為您需要查看控制器的代碼才能知道從容器中獲取的依賴關系是什么。

簡而言之,應該像最后一樣通過依賴者傳遞依賴關系,或者當僅在此特定操作中使用依賴關系時,可以使用基於操作的依賴關系注入

實際上,最好的解決方案甚至是不擴展基礎Controller類以使您的控制器框架獨立。

您的控制器應如下所示:

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>

希望對您有所幫助。

如Jakub Matczak的回答所述,未設置控制器的DI容器。

除了在services.yml中添加calls部分之外,您還可以在要使用控制器的類的構造函數中調用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);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM