How to Define Controllers as Services
Warning: You are browsing the documentation for Symfony 3.x, which is no longer maintained.
Read the updated version of this page for Symfony 7.1 (the current stable version).
In Symfony, a controller does not need to be registered as a service. But if you're using the default services.yml configuration, your controllers are already registered as services. This means you can use dependency injection like any other normal service.
Referencing your Service from Routing
Registering your controller as a service is great, but you also need to make sure that your routing references the service properly, so that Symfony knows to use it.
If the service id is the fully-qualified class name (FQCN) of your controller, you're
done! You can use the normal AppBundle:Hello:index
syntax in your routing and
it will find your service.
But, if your service has a different id, you can use a special SERVICEID:METHOD
syntax:
1 2 3 4 5 6 7 8 9 10 11 12
// src/AppBundle/Controller/HelloController.php
// You need to use Sensio's annotation to specify a service id
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
/**
* @Route(service="app.hello_controller")
*/
class HelloController
{
// ...
}
Note
You cannot drop the Action
part of the method name when using the
single colon notation.
Invokable Controllers
Controllers can also define a single action using the __invoke()
method,
which is a common practice when following the ADR pattern
(Action-Domain-Responder):
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// src/AppBundle/Controller/Hello.php
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
/**
* @Route("/hello/{name}", name="hello")
*/
class Hello
{
public function __invoke($name = 'World')
{
return new Response(sprintf('Hello %s!', $name));
}
}
Alternatives to base Controller Methods
When using a controller defined as a service, you can still extend any of the normal base controller classes and use their shortcuts. But, you don't need to! You can choose to extend nothing, and use dependency injection to access different services.
The base Controller class source code is a great way to see how to accomplish
common tasks. For example, $this->render()
is usually used to render a Twig
template and return a Response. But, you can also do this directly:
In a controller that's defined as a service, you can instead inject the templating
service and use it directly:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// src/AppBundle/Controller/HelloController.php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use Twig\Environment;
class HelloController
{
private $twig;
public function __construct(Environment $twig)
{
$this->twig = $twig;
}
public function indexAction($name)
{
$content = $this->twig->render(
'hello/index.html.twig',
['name' => $name]
);
return new Response($content);
}
}
You can also use a special action-based dependency injection to receive services as arguments to your controller action methods.
Base Controller Methods and Their Service Replacements
The best way to see how to replace base Controller
convenience methods is to
look at the ControllerTrait that holds its logic.
If you want to know what type-hints to use for each service, see the
getSubscribedServices()
method in AbstractController.