6

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?

3 Answers 3

3

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

Sign up to request clarification or add additional context in comments.

Comments

1

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 :)

1 Comment

See my answer, you can use annotations
0

Seems like you forgot to write an extension class that loads your services.xml file:

namespace MDP\API\ImageBundle\DependencyInjection;

use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\Config\FileLocator;

class ImageExtension extends Extension
{
    /**
     * @param array $configs
     * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $loader = new XmlFileLoader(
            $container, 
            new FileLocator(__DIR__.'/../Resources/config')
        );

        $loader->load('services.xml');
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.