Controller

A controller is a PHP function you create that reads information from the Symfony's
Request object and creates and returns a Response object. The response could
be an HTML page, JSON, XML, a file download, a redirect, a 404 error or anything
else you can dream up. The controller executes 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 a lucky (random) number:

But in the real world, your controller will probably do a lot of work in order to
create the response. 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.

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

line 7: The class can technically be called anything - but should end in the
word Controller (this isn't required, but some shortcuts rely on this).

line 12: Each action method in a controller class is suffixed with Action
(again, this isn't required, but some shortcuts rely on this). This method
is allowed to have a $max argument thanks to the {max}wildcard in the route.

That's it! You now have access to methods like $this->render()
and many others that you'll learn about next.

Tip

You can extend either Controller or AbstractController. The difference
is that when you extend AbstractController, you can't access services directly
via $this->get() or $this->container->get(). This forces you to write
more robust code to access services. But if you do need direct access to the
container, using Controller is fine.

New in version 3.3: The AbstractController class was added in Symfony 3.3.

If you want to redirect the user to another page, use the redirectToRoute()
and redirect() methods:

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

publicfunctionindexAction(){// redirect to the "homepage" routereturn$this->redirectToRoute('homepage');// do a permanent - 301 redirectreturn$this->redirectToRoute('homepage',array(),301);// redirect to a route with parametersreturn$this->redirectToRoute('blog_show',array('slug'=>'my-page'));// redirect externallyreturn$this->redirect('http://symfony.com/doc');}

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 or the base AbstractController
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(...);}

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:

Symfony provides a nice session object that you can use to store information
about the user between requests. By default, Symfony stores the token in a
cookie and writes the attributes to a file by using native PHP sessions.

New in version 3.3: The ability to request a Session instance in controllers was introduced
in Symfony 3.3.

To retrieve the session, add the SessionInterface
type-hint to your argument and Symfony will provide you with a session:

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

useSymfony\Component\HttpFoundation\Session\SessionInterface;publicfunctionindexAction(SessionInterface$session){// 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());}

Stored attributes remain in the session for the remainder of that user's session.

Tip

Every SessionInterface implementation is supported. If you have your
own implementation, type-hint this in the arguments instead.

You can also store special messages, called "flash" messages, on the user's
session. By design, flash messages are meant to be used exactly once: they vanish
from the session automatically as soon as you retrieve them. This feature makes
"flash" messages particularly great for storing user notifications.

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

After processing the request, the controller sets a flash message in the session
and then redirects. The message key (notice in this example) can be anything:
you'll use this key to retrieve the message.

In the template of the next page (or even better, in your base layout template),
read any flash messages from the session using app.flashes():

Twig

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

{# app/Resources/views/base.html.twig #}{# you can read and display just one flash message type... #}{%formessageinapp.flashes('notice')%}<divclass="flash-notice">{{message}}</div>{%endfor%}{# ...or you can read and display every flash message available #}{%forlabel,messagesinapp.flashes%}{%formessageinmessages%}<divclass="flash-{{label}}">{{message}}</div>{%endfor%}{%endfor%}

PHP

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

<!-- app/Resources/views/base.html.php -->
// you can read and display just one flash message type...
<?phpforeach($view['session']->getFlashBag()->get('notice')as$message):?><divclass="flash-notice"><?phpecho$message?></div><?phpendforeach?>
// ...or you can read and display every flash message available
<?phpforeach($view['session']->getFlashBag()->all()as$type=>$flash_messages):?><?phpforeach($flash_messagesas$flash_message):?><divclass="flash-<?phpecho$type?>"><?phpecho$message?></div><?phpendforeach?><?phpendforeach?>

New in version 3.3: The app.flashes() Twig function was introduced in Symfony 3.3. Prior,
you had to use app.session.flashBag().

Note

It's common to use notice, warning and error as the keys of the
different types of flash messages, but you can use any key that fits your
needs.

Tip

You can use the
peek()
method instead to retrieve the message while keeping it in the bag.

As mentioned earlier, the framework will
pass the Request object to any controller argument that is type-hinted with
the Request class:

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

useSymfony\Component\HttpFoundation\Request;publicfunctionindexAction(Request$request){$request->isXmlHttpRequest();// is it an Ajax request?$request->getPreferredLanguage(array('en','fr'));// retrieve GET and POST variables respectively$request->query->get('page');$request->request->get('page');// retrieve SERVER variables$request->server->get('HTTP_HOST');// retrieves an instance of UploadedFile identified by foo$request->files->get('foo');// retrieve a COOKIE value$request->cookies->get('PHPSESSID');// retrieve an HTTP request header, with normalized, lowercase keys$request->headers->get('host');$request->headers->get('content_type');}

The Request class has several public properties and methods that return any
information you need about the request.

Like the Request, the Response object has also a public headers property.
This is a ResponseHeaderBag that has
some nice methods for getting and setting response headers. The header names are
normalized so that using Content-Type is equivalent to content-type or even
content_type.

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 CSS-response with a 200 status code$response=newResponse('<style> ... </style>');$response->headers->set('Content-Type','text/css');

There are special classes that make certain kinds of responses easier:

You can use the file()
helper to serve a file from inside a controller:

1
2
3
4
5

publicfunctionfileAction(){// send the file contents and force the browser to download itreturn$this->file('/path/to/some_file.pdf');}

The file() helper provides some arguments to configure its behavior:

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

useSymfony\Component\HttpFoundation\File\File;useSymfony\Component\HttpFoundation\ResponseHeaderBag;publicfunctionfileAction(){// load the file from the filesystem$file=newFile('/path/to/some_file.pdf');return$this->file($file);// rename the downloaded filereturn$this->file($file,'custom_name.pdf');// display the file contents in the browser instead of downloading itreturn$this->file('invoice_3241.pdf','my_invoice.pdf',ResponseHeaderBag::DISPOSITION_INLINE);}

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'll probably extend the base Controller class because
this gives access to shortcut methods (like render() and redirectToRoute()).

In other articles, you'll learn how to use specific services from inside your controller
that will help you persist and fetch objects from a database, process form submissions,
handle caching and more.