1
votes

I have a probleme with the initialization of a variable

My 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();  
}

}

In my services.yml, in configure the passing of doctrine service to my controller 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"]]
  • TEST 1 doesn't work
  • TEST 2 with ESSAI 1,2,3 (services.yml) doesn'twork
  • TEST 3 works

With TEST 1, I get the following error : Error: Call to a member function has() on null in vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle\Controller\Controller.php at line 291

With TEST 2 $entityManager (argument of __construct) is NULL

I don't read anything against the initialization, in the controller, of variable with instance of entitymanager. With Symfony2.3, TEST 2 works, I think.

Did I forget something in the configuration of doctrine ?

thanks,

Phil

4

4 Answers

0
votes

As you extend the class Symfony\Bundle\FrameworkBundle\Controller\Controller, you have many interested methods and particulary getDoctrine.

So, I propose you to call directly inside controller action(s), the entity manager, when you need it.

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

Option 3 is the best: No service and no constructor.

3
votes

As the requirement is to get doctrine in the ctor you should do it like 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

As a small best-practices approach, I'm trying to have all controllers as a service and never extend Controller, because you unnecessarily open the context when injecting the container into that ContainerAware. As you can see then is, that unit-testing is possible, without using WebTestCase which is sometimes quite nice.

1
votes

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

If you only need to get the instance of the entity manager, just do as written by @scoolnico, or if you really want to declare your controller as a service read the documentation above, and don't bother the Controller class from the FrameworkBundle..

Simple example here (copied from the doc and modified):

// 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
1
votes

Your question is somewhat confusing. It appears that you have two identical services. It is also unclear what sort of testing you are doing. Have you configured your routes to use controller services?

In any event, to use the standard framework controller as a service you need to inject the container as well as your other services. The "has" error seems to indicate you are trying to use one of the base controller methods which rely on having the container. It's easy enough to inject it:

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

Basically, the container takes care of all the base functionality. Use constructor injection to inject anything specific to the controller itself.

And then your route needs to specify the service and not the controller class. Basically one less : in the _controller parameter.

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