Controller

A controller is a PHP callable you create that takes information from the
HTTP request and creates and returns an HTTP response (as a Symfony
Response object). The response could be an HTML page, an XML document,
a serialized JSON array, an image, a redirect, a 404 error or anything else
you can dream up. The controller contains whatever arbitrary logic your
application needs to render the content of a page.

See how simple this is by looking at a Symfony controller in action.
This renders a page that prints the famous Hello world!:

The goal of a controller is always the same: create and return a Response
object. Along the way, it might read information from the request, load a
database resource, send an email, or set information on the user's session.
But in all cases, the controller will eventually return the Response object
that will be delivered back to the client.

There's no magic and no other requirements to worry about! Here are a few
common examples:

Controller A prepares a Response object representing the content
for the homepage of the site.

Controller B reads the slug parameter from the request to load a
blog entry from the database and creates a Response object displaying
that blog. If the slug can't be found in the database, it creates and
returns a Response object with a 404 status code.

Controller C handles the form submission of a contact form. It reads
the form information from the request, saves the contact information to
the database and emails the contact information to you. Finally, it creates
a Response object that redirects the client's browser to the contact
form "thank you" page.

Every request handled by a Symfony project goes through the same simple lifecycle.
The framework takes care of all the repetitive stuff: you just need to write
your custom code in the controller function:

Each request is handled by a single front controller file (e.g. app.php
or app_dev.php) that bootstraps the application;

The Router reads information from the request (e.g. the URI), finds
a route that matches that information, and reads the _controller parameter
from the route;

The controller from the matched route is executed and the code inside the
controller creates and returns a Response object;

The HTTP headers and content of the Response object are sent back to
the client.

Creating a page is as easy as creating a controller (#3) and making a route that
maps a URL to that controller (#2).

Note

Though similarly named, a "front controller" is different from the
"controllers" talked about in this chapter. A front controller
is a short PHP file that lives in your web directory and through which
all requests are directed. A typical application will have a production
front controller (e.g. app.php) and a development front controller
(e.g. app_dev.php). You'll likely never need to edit, view or worry
about the front controllers in your application.

Note that the controller is the indexAction method, which lives
inside a controller class (HelloController). Don't be confused
by the naming: a controller class is simply a convenient way to group
several controllers/actions together. Typically, the controller class
will house several controllers/actions (e.g. updateAction, deleteAction,
etc).

This controller is pretty straightforward:

line 4: Symfony takes advantage of PHP's namespace functionality to
namespace the entire controller class. The use keyword imports the
Response class, which the controller must return.

line 6: The class name is the concatenation of a name for the controller
class (i.e. Hello) and the word Controller. This is a convention
that provides consistency to controllers and allows them to be referenced
only by the first part of the name (i.e. Hello) in the routing configuration.

line 8: Each action in a controller class is suffixed with Action
and is referenced in the routing configuration by the action's name (index).
In the next section, you'll create a route that maps a URI to this action.
You'll learn how the route's placeholders ({name}) become arguments
to the action method ($name).

# app/config/routing.ymlhello:path:/hello/{name}# uses a special syntax to point to the controller - see note belowdefaults:{_controller:AppBundle:Hello:index}

XML

1
2
3
4
5
6
7
8
9
10
11
12

<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routesxmlns="http://symfony.com/schema/routing"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://symfony.com/schema/routing http://symfony.com/schema/routing/routing-1.0.xsd"><routeid="hello"path="/hello/{name}"><!-- uses a special syntax to point to the controller - see note below --><defaultkey="_controller">AppBundle:Hello:index</default></route></routes>

PHP

1
2
3
4
5
6
7
8
9
10
11

// app/config/routing.phpuseSymfony\Component\Routing\Route;useSymfony\Component\Routing\RouteCollection;$collection=newRouteCollection();$collection->add('hello',newRoute('/hello/{name}',array(// uses a special syntax to point to the controller - see note below'_controller'=>'AppBundle:Hello:index',)));return$collection;

Now, you can go to /hello/ryan (e.g. http://localhost:8000/hello/ryan
if you're using the built-in web server)
and Symfony will execute the HelloController::indexAction() controller
and pass in ryan for the $name variable. Creating a "page" means
simply creating a controller method and an associated route.

Simple, right?

The AppBundle:Hello:index controller syntax

If you use the YML or XML formats, you'll refer to the controller using
a special shortcut syntax: AppBundle:Hello:index. For more details
on the controller format, see Controller Naming Pattern.

The controller has a single argument, $name, which corresponds to the
{name} parameter from the matched route (ryan if you go to /hello/ryan).
When executing your controller, Symfony matches each argument with a parameter
from the route. So the value for {name} is passed to $name.

Mapping route parameters to controller arguments is easy and flexible. Keep
the following guidelines in mind while you develop.

The order of the controller arguments does not matter

Symfony matches the parameter names from the route to the variable
names of the controller. The arguments of the controller could be totally
reordered and still work perfectly:

1
2
3
4

publicfunctionindexAction($lastName,$firstName){// ...}

Each required controller argument must match up with a routing parameter

The following would throw a RuntimeException because there is no foo
parameter defined in the route:

1
2
3
4

publicfunctionindexAction($firstName,$lastName,$foo){// ...}

Making the argument optional, however, is perfectly ok. The following
example would not throw an exception:

1
2
3
4

publicfunctionindexAction($firstName,$lastName,$foo='bar'){// ...}

Not all routing parameters need to be arguments on your controller

If, for example, the lastName weren't important for your controller,
you could omit it entirely:

1
2
3
4

publicfunctionindexAction($firstName){// ...}

Tip

Every route also has a special _route parameter, which is equal to
the name of the route that was matched (e.g. hello). Though not usually
useful, this is also available as a controller argument. You can also
pass other variables from your route to your controller arguments. See
How to Pass Extra Information from a Route to a Controller.

What if you need to read query parameters, grab a request header or get access
to an uploaded file? All of that information is stored in Symfony's Request
object. To get it in your controller, just add it as an argument and
type-hint it with the Request class:

For convenience, Symfony comes with an optional base Controller class.
If you extend it, you'll get access to a number of helper methods and all
of your service objects via the container (see Accessing other Services).

Add the use statement atop the Controller class and then modify the
HelloController to extend it:

This doesn't actually change anything about how your controller works: it
just gives you access to helper methods that the base controller class makes
available. These are just shortcuts to using core Symfony functionality that's
available to you with or without the use of the base Controller class.
A great way to see the core functionality in action is to look in the
Controller class.

If you're curious about how a controller would work that did not extend
this base class, check out Controllers as Services.
This is optional, but can give you more control over the exact objects/dependencies
that are injected into your controller.

The Symfony templating engine is explained in great detail in the
Templating chapter.

Referencing Templates that Live inside the Bundle

You can also put templates in the Resources/views directory of a
bundle and reference them with a
BundleName:DirectoryName:FileName syntax. For example,
AppBundle:Hello:index.html.twig would refer to the template located in
src/AppBundle/Resources/views/Hello/index.html.twig. See Referencing Templates in a Bundle.

Symfony comes packed with a lot of useful objects, called services. These
are used for rendering templates, sending emails, querying the database and
any other "work" you can think of. When you install a new bundle, it probably
brings in even more services.

When extending the base controller class, you can access any Symfony service
via the get() method. Here are several common services you might need:

When things are not found, you should play well with the HTTP protocol and
return a 404 response. To do this, you'll throw a special type of exception.
If you're extending the base controller class, do the following:

1
2
3
4
5
6
7
8
9
10

publicfunctionindexAction(){// retrieve the object from database$product=...;if(!$product){throw$this->createNotFoundException('The product does not exist');}return$this->render(...);}

The createNotFoundException() method is just a shortcut to create a
special NotFoundHttpException
object, which ultimately triggers a 404 HTTP response inside Symfony.

Symfony provides a nice session object that you can use to store information
about the user (be it a real person using a browser, a bot, or a web service)
between requests. By default, Symfony stores the attributes in a cookie
by using the native PHP sessions.

Storing and retrieving information from the session can be easily achieved
from any controller:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

useSymfony\Component\HttpFoundation\Request;publicfunctionindexAction(Request$request){$session=$request->getSession();// store an attribute for reuse during a later user request$session->set('foo','bar');// get the attribute set by another controller in another request$foobar=$session->get('foobar');// use a default value if the attribute doesn't exist$filters=$session->get('filters',array());}

These attributes will remain on the user for the remainder of that user's
session.

You can also store small messages that will be stored on the user's session
for exactly one additional request. This is useful when processing a form:
you want to redirect and have a special message shown on the next page.
These types of messages are called "flash" messages.

For example, imagine you're processing a form submit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

useSymfony\Component\HttpFoundation\Request;publicfunctionupdateAction(Request$request){$form=$this->createForm(...);$form->handleRequest($request);if($form->isValid()){// do some sort of processing$this->addFlash('notice','Your changes were saved!');// $this->addFlash is equivalent to $this->get('session')->getFlashBag()->addreturn$this->redirectToRoute(...);}return$this->render(...);}

After processing the request, the controller sets a notice flash message
in the session and then redirects. The name (notice) isn't significant -
it's just something you invent and reference next.

In the template of the next action, the following code could be used to render
the notice message:

The only requirement for a controller is to return a Response object. The
Response class is an abstraction
around the HTTP response: the text-based message filled with headers and
content that's sent back to the client:

1
2
3
4
5
6
7
8

useSymfony\Component\HttpFoundation\Response;// create a simple Response with a 200 status code (the default)$response=newResponse('Hello '.$name,Response::HTTP_OK);// create a JSON-response with a 200 status code$response=newResponse(json_encode(array('name'=>$name)));$response->headers->set('Content-Type','application/json');

The headers property is a HeaderBag
object and has some nice methods for getting and setting the headers. The
header names are normalized so that using Content-Type is equivalent to
content-type or even content_type.

There are also special classes to make certain kinds of responses easier:

Besides the values of the routing placeholders, the controller also has access
to the Request object. The framework injects the Request object in the
controller if a variable is type-hinted with
Request:

1
2
3
4
5
6
7
8
9
10
11
12

useSymfony\Component\HttpFoundation\Request;publicfunctionindexAction(Request$request){$request->isXmlHttpRequest();// is it an Ajax request?$request->getPreferredLanguage(array('en','fr'));$request->query->get('page');// get a $_GET parameter$request->request->get('page');// get a $_POST parameter}

Like the Response object, the request headers are stored in a HeaderBag
object and are easily accessible.

Don't worry! There is a lot more information about the Request object
in the component documentation. See Request.

Though not very common, you can also forward to another controller internally
with the forward()
method. Instead of redirecting the user's browser, it makes an internal sub-request,
and calls the controller. The forward() method returns the Response
object that's returned from that controller:

1
2
3
4
5
6
7
8
9
10
11

publicfunctionindexAction($name){$response=$this->forward('AppBundle:Something:fancy',array('name'=>$name,'color'=>'green',));// ... further modify the response or return it directlyreturn$response;}

Notice that the forward() method uses a special string representation
of the controller (see Controller Naming Pattern). In this case, the
target controller function will be SomethingController::fancyAction()
inside the AppBundle. The array passed to the method becomes the arguments on
the resulting controller. This same idea is used when embedding controllers
into templates (see Embedding Controllers). The target
controller method would look something like this:

Just like when creating a controller for a route, the order of the arguments of
fancyAction doesn't matter. Symfony matches the index key names (e.g.
name) with the method argument names (e.g. $name). If you change the
order of the arguments, Symfony will still pass the correct value to each
variable.

Sometimes, you want to use CSRF protection in an action where you don't want to
use the Symfony Form component. If, for example, you're doing a DELETE action,
you can use the isCsrfTokenValid()
method to check the CSRF token:

1
2
3

if($this->isCsrfTokenValid('token_id',$submittedToken)){// ... do something, like deleting an object}

New in version 2.6: The isCsrfTokenValid() shortcut method was introduced in Symfony 2.6.
It is equivalent to executing the following code::

Whenever you create a page, you'll ultimately need to write some code that
contains the logic for that page. In Symfony, this is called a controller,
and it's a PHP function where you can do anything in order to return the
final Response object that will be returned to the user.

To make life easier, you can choose to extend a base Controller class,
which contains shortcut methods for many common controller tasks. For example,
since you don't want to put HTML code in your controller, you can use
the render() method to render and return the content from a template.

In other chapters, you'll see how the controller can be used to persist and
fetch objects from a database, process form submissions, handle caching and
more.