Step 6: Creating a Controller
Creating a Controller
When an HTTP request comes in, like for the homepage (), Symfony tries to find a route that matches the request path (/
here). A route is the link between the request path and a PHP callable, a function that creates the HTTP response for that request.
These callables are called “controllers”. In Symfony, most controllers are implemented as PHP classes. You can create such a class manually, but because we like to go fast, let’s see how Symfony can help us.
To generate controllers effortlessly, we can use the symfony/maker-bundle
package:
As the maker bundle is only useful during development, don’t forget to add the --dev
flag to avoid it being enabled in production.
The maker bundle helps you generate a lot of different classes. We will use it all the time in this book. Each “generator” is defined in a command and all commands are part of the make
command namespace.
The Symfony Console built-in list
command lists all commands available under a given namespace; use it to discover all generators provided by the maker bundle:
$ symfony console list make
Before creating the first controller of the project, we need to decide on the configuration formats we want to use. Symfony supports YAML, XML, PHP, and annotations out of the box.
For configuration related to packages, YAML is the best choice. This is the format used in the config/
directory. Often, when you install a new package, that package’s recipe will add a new file ending in .yaml
to that directory.
For configuration related to PHP code, annotations are a better choice as they are defined next to the code. Let me explain with an example. When a request comes in, some configuration needs to tell Symfony that the request path should be handled by a specific controller (a PHP class). When using YAML, XML or PHP configuration formats, two files are involved (the configuration file and the PHP controller file). When using annotations, the configuration is done directly in the controller class.
To manage annotations, we need to add another dependency:
$ symfony composer req annotations
Create your first Controller via the make:controller
command:
The command creates a ConferenceController
class under the src/Controller/
directory. The generated class consists of some boilerplate code ready to be fine-tuned:
src/Controller/ConferenceController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class ConferenceController extends AbstractController
{
#[Route('/conference', name: 'conference')]
public function index(): Response
{
return $this->render('conference/index.html.twig', [
'controller_name' => 'ConferenceController',
]);
}
}
The #[Route('/conference', name: 'conference')]
annotation is what makes the index()
method a controller (the configuration is next to the code that it configures).
When you hit /conference
in a browser, the controller is executed and a response is returned.
Tweak the route to make it match the homepage:
patch_file
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
class ConferenceController extends AbstractController
{
- #[Route('/conference', name: 'conference')]
+ #[Route('/', name: 'homepage')]
public function index(): Response
{
return $this->render('conference/index.html.twig', [
The route name
will be useful when we want to reference the homepage in the code. Instead of hard-coding the /
path, we will use the route name.
Instead of the default rendered page, let’s return a simple HTML one:
patch_file
The main responsibility of a controller is to return an HTTP Response
for the request.
To demonstrate how a response can leverage information from the request, let’s add a small #In_computing). Whenever the homepage contains a query string like ?hello=Fabien
, let’s add some text to greet the person:
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -3,6 +3,7 @@
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
+use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
@@ -11,11 +12,17 @@ class ConferenceController extends AbstractController
#[Route('/', name: 'homepage')]
- public function index(): Response
+ public function index(Request $request): Response
{
+ $greet = '';
+ if ($name = $request->query->get('hello')) {
+ $greet = sprintf('<h1>Hello %s!</h1>', htmlspecialchars($name));
+ }
+
return new Response(<<<EOF
<html>
<img src="/images/under-construction.gif" />
</body>
</html>
Symfony exposes the request data through a Request
object. When Symfony sees a controller argument with this type-hint, it automatically knows to pass it to you. We can use it to get the name
item from the query string and add an <h1>
title.
Try hitting /
then /?hello=Fabien
in a browser to see the difference.
Note
Notice the call to htmlspecialchars()
to avoid XSS issues. This is something that will be done automatically for us when we switch to a proper template engine.
We could also have made the name part of the URL:
--- a/src/Controller/ConferenceController.php
+++ b/src/Controller/ConferenceController.php
@@ -9,13 +9,19 @@ use Symfony\Component\Routing\Annotation\Route;
class ConferenceController extends AbstractController
{
- #[Route('/', name: 'homepage')]
+ #[Route('/hello/{name}', name: 'homepage')]
- public function index(): Response
+ public function index(string $name = ''): Response
{
+ $greet = '';
+ if ($name) {
+ $greet = sprintf('<h1>Hello %s!</h1>', htmlspecialchars($name));
+ }
+
return new Response(<<<EOF
<html>
<body>
+ $greet
<img src="/images/under-construction.gif" />
</body>
</html>
The {name}
part of the route is a dynamic route parameter - it works like a wildcard. You can now hit /hello
then /hello/Fabien
in a browser to get the same results as before. You can get the value of the {name}
parameter by adding a controller argument with the same name. So, .
Going Further
- The Symfony Routing system;
- ;
- Annotations in PHP;
- The component;
- The Symfony Routing Cheat Sheet.