在controller的构造函数中获取一个doctrine的实例

Get an instance of doctrine in the constructor of controller

我对变量的初始化有疑问

我的控制器:

namespace SB\FrontendBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManager;
use Mie\FrontendBundle\Entity\Product;


class FrontendController extends Controller
{
  protected $em;

  public function __construct(EntityManager $entityManager = null)
  {
    $this->em = $this->getDoctrine()->getManager(); //--->TEST 1

    $this->em = $entityManager; //--->TEST2
  }

  public function dispatchUrl(Request $request)
  {
      $this->em = $this->getDoctrine()->getManager(); //--->TEST 3

      $product = new Product();
      $product->setName('A Foo Bar');
      $product->setPrice('19.99');
      $product->setDescription('Lorem ipsum dolor');


      $this->em->persist($product);
      $this->em->flush();
      die();  
}

}

在我的 services.yml 中,配置将原则服务传递给我的控制器 FrontendController

parameters:
    mie.frontend.controller.frontend.class: Mie\FrontendBundle\Controller\FrontendController

services:
# ---> ESSAI 1
    mie.frontend.controller:
        class: "%mie.frontend.controller.frontend.class%"
        arguments:
            - "@doctrine.orm.entity_manager"

# ---> ESSAI 2
    mie.frontend.controller:
        class: "%mie.frontend.controller.frontend.class%"
        arguments: [ @doctrine.orm.entity_manager ]

# ---> ESSAI 3
#    mie.frontend.controller:
#        class: "%mie.frontend.controller.frontend.class%"
#        calls:
#            - [setEntityManager, ["@doctrine.orm.entity_manager"]]

在测试 1 中,出现以下错误: 错误:在 null 上调用成员函数 has() 在 vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle\Controller\Controller.php 中第 291

有测试 2 $entityManager(__construct 的参数)为 NULL

我没有读到任何反对在控制器中使用 entitymanager 实例初始化变量的内容。 使用 Symfony2.3,我认为 TEST 2 有效。

我是不是忘了配置 doctrine 的东西了?

谢谢,

菲尔

当您扩展 class Symfony\Bundle\FrameworkBundle\Controller\Controller 时,您有许多感兴趣的方法,特别是 getDoctrine

因此,我建议您在需要时直接在控制器操作内部调用实体管理器。

    public function dispatchUrl(Request $request)
{
  $this->em = $this->getDoctrine()->getManager();
  ... // your business logic
}

选项 3 是最好的:没有服务,也没有构造函数。

你的问题有点令人费解。您似乎有两个相同的服务。也不清楚你在做什么测试。您是否已将路由配置为使用控制器服务?

无论如何,要将标准框架控制器用作服务,您需要注入容器以及其他服务。 "has" 错误似乎表明您正在尝试使用依赖于容器的基本控制器方法之一。注入它很容易:

mie.frontend.controller:
  class: Mie\FrontendBundle\Controller\FrontendController
  calls: [[setContainer, ['@service_container']]]
  arguments:
    - '@doctrine.orm.entity_manager'

基本上,容器负责所有基本功能。使用构造函数注入来注入任何特定于控制器本身的东西。

然后你的路由需要指定服务而不是控制器class。基本上少了一个:在_controller参数中。

project_game_export:
  path:     /export
  methods:  [GET,POST]
  defaults:
    _controller: sportacus_project_game_export_controller:exportAction 

http://symfony.com/doc/current/cookbook/controller/service.html

http://symfony.com/doc/current/cookbook/controller/service.html

如果你只需要获取实体管理器的实例,就按照@scoolnico 写的那样做,或者如果你真的想将你的控制器声明为服务,请阅读上面的文档,不要打扰Controller class 来自 FrameworkBundle..

此处为简单示例(从文档中复制并修改):

// src/AppBundle/Controller/HelloController.php
namespace AppBundle\Controller;

use Symfony\Component\HttpFoundation\Response;

class HelloController
{
    private $em;

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

    public function indexAction($name)
    {
        $em = $this->em;
        ...
    }
}

services.yml:

services:
    app.hello_controller:
        class: AppBundle\Controller\HelloController
        arguments:
            - @doctrine.orm.entity_manager

因为要求是在 ctor 中获得学说,所以你应该像 http://symfony.com/doc/current/cookbook/controller/service.html#defining-the-controller-as-a-service:

FrontendController.php

<?php
class FrontendController /* extends Controller // no need for this */
{
  /**
   * @var EntityManagerInterface
   */
  protected $em;

  public function __construct(EntityManagerInterface $entityManager) {
    $this->em = $entityManager;
  }
}

services.yml

services:
  front_controller:
    class: ...\FrontendController
    arguments:
      entityManager: "@doctrine.orm.default_entity_manager"

routing.yml

homepage:
  path: /
  defaults:
    _controller: frontend_controller:yourAction

作为一个小的最佳实践方法,我试图将所有控制器作为一项服务并且从不扩展 Controller,因为在将容器注入 ContainerAware 时,您不必要地打开了上下文.如您所见,单元测试是可能的,而无需使用 WebTestCase,这有时非常好。