Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to define my controllers as service in Symfony2 — the arguments are never passed to the constructor

Tags:

php

symfony

So, here is a controller I've just built:

namespace MDP\API\ImageBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

class RetrieverController {

    private $jsonResponse;

    private $request;

    public function __construct(JsonResponse $jsonResponse, Request $request) {
        $this->jsonResponse = $jsonResponse;
        $this->request = $request;
    }

    /**
     * @Route("/image/{amount}")
     * @Template("MDPAPIImageBundle:Retriever:index.json.twig")
     */
    public function retrieve($amount)
    {
    }
}

I want to make this controller work as a service, to use DependencyInjection. So, here is my services.xml file:

<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">


    <services>
        <service id="mdpapi_image.json_response" class="Symfony\Component\HttpFoundation\JsonResponse" />
        <service id="mdpapi_image.request" class="Symfony\Component\HttpFoundation\Request" />
        <service id="mdpapi_image.controller.retriever" class="MDP\API\ImageBundle\Controller\RetrieverController">
            <argument type="service" id="mdpapi_image.json_response" />
            <argument type="service" id="mdpapi_image.request" />
        </service>
    </services>
</container>

However, when I try to execute my controller, I always get this exception:

Catchable Fatal Error: Argument 1 passed to MDP\API\ImageBundle\Controller\RetrieverController::__construct() must be an instance of Symfony\Component\HttpFoundation\JsonResponse, none given, called in /home/steve/projects/APIs/app/cache/dev/jms_diextra/controller_injectors/MDPAPIImageBundleControllerRetrieverController.php on line 13 and defined in /home/steve/projects/ImageAPI/ImageBundle/Controller/RetrieverController.php line 13

When I am in dev mode, I see that Symfony generate this file in the cached files...

class RetrieverController__JMSInjector
{
    public static function inject($container) {
        $instance = new \MDP\API\ImageBundle\Controller\RetrieverController();
        return $instance;
    }
}

How can I make it so that the arguments are added correctly to the controller, like specified in my services.xml file?

like image 751
iRESTful Avatar asked Sep 25 '12 21:09

iRESTful


2 Answers

Just found the answer to your question, hope this helps you (or others who find this question)

<?php
namespace MDP\API\ImageBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\JsonResponse;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

/**
* @Route("/image", service="mdpapi_image.controller.retriever")
*/
class RetrieverController {

    private $jsonResponse;

    private $request;

    public function __construct(JsonResponse $jsonResponse, Request $request) {
        $this->jsonResponse = $jsonResponse;
        $this->request = $request;
    }

    /**
     * @Route("/{amount}")
     * @Template("MDPAPIImageBundle:Retriever:index.json.twig")
     */
    public function retrieve($amount)
    {
    }
}

Sources:

http://richardmiller.co.uk/2011/10/25/symfony2-routing-to-controller-as-service-with-annotations/

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

like image 102
Matt Avatar answered Oct 09 '22 02:10

Matt


So, I fixed my problem. I had to stop using Annotations in my controller and changed my routing.yml so write the routes directly.

image_retrieve:
    pattern:   /image/{amount}
    defaults:  { _controller: mdp_api_image_retriever_retrieve:retrieve }
    requirements:
      _method:  GET

That fixed the whole problem. The problem with annotations is that on this class (JMS\DiExtraBundle\HttpKernel\ControllerResolver) on line 90, in the Symfony core, you see this core:

// If the cache warmer tries to warm up a service controller that uses
// annotations, we need to bail out as this is handled by the service
// container directly.
if (null !== $metadata->getOutsideClassMetadata()->id
                && 0 !== strpos($metadata->getOutsideClassMetadata()->id, '_jms_di_extra.unnamed.service')) {
            return;
}

Then on line 69, it tries to call the method call_user_func from the returned data, which was null.

In other words, using Annotation and creating your Controllers as Service does NOT work together. I lost 4 hours debugging this issue, so I hope this might help someone in the future :)

like image 27
iRESTful Avatar answered Oct 09 '22 00:10

iRESTful