1

getting the following exception:

Catchable Fatal Error: Argument 1 passed to AppBundle\Controller\AudienceController::__construct() must be an instance of AppBundle\Repository\AudienceRepository, none given, called in /home/eddy/Projects/tm/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php on line 162 and defined

Meaning, I defined my controller with a custom repository as a constructor argument, but or the repository is never passed or not created. I tried debugging into ControllerResolver but to no avail.

[services.yml]
services:
    app.audience_repository:
        class: Doctrine\ORM\EntityRepository
        factory: ["@doctrine.orm.entity_manager", getRepository]
        arguments:
            - AppBundle\Entity\Audience
    app.audience_controller:
        class: AppBundle\Controller\AudienceController
        arguments:
            - "@app.audience_repository"


[AppBundle\Controller\AudienceController.php]
    class AudienceController extends Controller
    {
        /**
         * @var AudienceRepository
         */
        private $repository;

        /**
         * @param AudienceRepository $repository
         */
        public function __construct(AudienceRepository $repository)
        {
            $this->repository = $repository;
        }

[AppBundle\Repository\AudienceRepository]
class AudienceRepository extends EntityRepository
{
    public function save(Audience $audience)
    {
        $this->getEntityManager()->persist($audience);
        $this->getEntityManager()->flush();
    }
}

[AppBundle\Entity\Audience.php]
/**
 * Audience
 *
 * @ORM\Table(name="audience")
 * @ORM\Entity(repositoryClass="AppBundle\Repository\AudienceRepository")
 */
class Audience

I think this is according to http://php-and-symfony.matthiasnoback.nl/2014/05/inject-a-repository-instead-of-an-entity-manager/ with a modification for symfony3 (see https://stackoverflow.com/a/20348821/30759) and should work, but I keep getting this error.

Stacktrace:
at ErrorHandler ->handleError ('4096', 'Argument 1 passed to AppBundle\Controller\AudienceController::__construct() must be an instance of AppBundle\Repository\AudienceRepository, none given, called in /home/eddy/Projects/tm/vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php on line 162 and defined', '/home/eddy/Projects/tm/src/AppBundle/Controller/AudienceController.php', '23', array()) 
in src/AppBundle/Controller/AudienceController.php at line 23   + 
at AudienceController ->__construct () 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php at line 162   + 
at ControllerResolver ->instantiateController ('AppBundle\Controller\AudienceController') 
in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php at line 81   + 
at ControllerResolver ->instantiateController ('AppBundle\Controller\AudienceController') 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php at line 150   + 
at ControllerResolver ->createController ('AppBundle\Controller\AudienceController::newAction') 
in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php at line 73   + 
at ControllerResolver ->createController ('AppBundle\Controller\AudienceController::newAction') 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/ControllerResolver.php at line 76   + 
at ControllerResolver ->getController (object(Request)) 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Controller/TraceableControllerResolver.php at line 46   + 
at TraceableControllerResolver ->getController (object(Request)) 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 127   + 
at HttpKernel ->handleRaw (object(Request), '1') 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/HttpKernel.php at line 62   + 
at HttpKernel ->handle (object(Request), '1', true) 
in vendor/symfony/symfony/src/Symfony/Component/HttpKernel/Kernel.php at line 169   + 
at Kernel ->handle (object(Request)) 
in web/app_dev.php at line 30   + 
at require ('/home/eddy/Projects/tm/web/app_dev.php') 
in vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Resources/config/router_dev.php at line 40   + 

Any help is greatly appreciated :)

Community
  • 1
  • 1
eddy147
  • 4,853
  • 8
  • 38
  • 57
  • You need to tell your route that the controller is defined as a service: http://symfony.com/doc/current/cookbook/controller/service.html. By the way, you won't be able to use any of the helper methods (like render) from the base controller class unless you add setContainer to your controller service definition. – Cerad Mar 21 '16 at 12:10

1 Answers1

2

In the article you linked to ("Inject a repository instead of an entity manager") he writes about "normal" services and I also think you should inject repositories instead of the entity manager if applicable. But: In symfony a controller is not a service by default.

There are basically two options:

Option 1: Tell Symfony that your Controller is a service

As this is a bit more complex, I just leave you this link here: How to Define Controllers as Services

In that case you should not extend the Controller base class, which in turn means you can't use the methods provided by it. If you don't use them anyway, this is okay and you can go for it.

If not (for example you want to use the "render" method), you also have to inject the service container into your controller using the setContainer method and you did a lot of work to just use the base controller again. That's why I would recommend using Option 2.

Option 2: Use the helper methods from the Controller class (I prefer this one)

$audienceRepo = $this->getDoctrine()->getRepository(Audience::class);

In that case you don't have to define the controller as service and you can just use it as before.

Tobias Xy
  • 2,039
  • 18
  • 19
  • Option 3: Extend your controller from the base controller and call setContainer from your service definition. Inject the repository as well as other controller specific services into the constructor. Best of both worlds. – Cerad Mar 22 '16 at 11:25
  • That is what I (tried to) describe in option 1, but in my opinion it is too much effort to just avoid using the "get" method of the base controller. But of course it is possible, if you want to do it. – Tobias Xy Mar 22 '16 at 11:31
  • Adding one line to a dervice definition in exchange for getting all the standard controller helper functions seems reasonable to me but too each their own. – Cerad Mar 22 '16 at 14:27
  • Let me see if I understand option #2: so the repository is then not injected as a dependency in the constructor? – eddy147 Mar 23 '16 at 18:52
  • Exactly. Basically this is a violation of DI principles, because you request the service from inside the controller, but it is easier to use. You should also read this article, to get more information why to do it (or why not): https://knpuniversity.com/screencast/question-answer-day/controllers-services – Tobias Xy Mar 24 '16 at 08:33