controller
The controller is a php function you create, which can obtain http request information and build and return an http response (as a Symfony Response object). Response may be an html page, xml document, or a serialization json array, image, redirect, 404 error or anything else you can imagine. Controllers contain any logic your application needs to render the page.
Take a look at symfony's simple controller. The following controller will output hello word
:
use Symfony\Component\HttpFoundation\Response; public function helloAction(){ return new Response('Hello world!');}
The goal of the controller is the same: to create and return a Response
object. During this process, it may read information from the request, load database resources, send emails, and set information in the user session. But in all cases, the controller will eventually return the Response
object to the client.
Nothing magical, don’t worry about any other requirements! Here are some common examples:
Controller A prepares a
Response
object on the home page. -Controller B reads the
{slug}
parameters from the request, loads a blog post from the database, and creates athat displays the blog post. Response
object. If{slug}
cannot be retrieved from the database, the controller will create and return aResponse
object with a 404 status code.Controller C handles form submissions regarding contacts. It reads the form information from the request, stores the contact information in the database and sends an email containing the contact information to the website administrator. Finally, it creates a
Response
object that redirects the user's browser to the contact form's "Thank you" page.
The life cycle of requests, controllers, and responses ¶
Every request processed by symfony will have the same life cycle. The framework will be responsible for ultimately executing many repetitive tasks with a controller that executes your custom application code:
Each request is handled by a single front-end controller (such as
app.php
Production environment orapp_dev.php
development environment) file processing, the front-end controller is responsible for booting the framework;The only job of the front-end controller It is to initialize the Symfony engine (call
Kernel
) and pass in aRequest
object to let it process.Symfony core asks the router to check the request;
The router looks at and matches the request information and points it to a specific route, which Routing determines which controller to call;
Execute the controller, the code in the controller will create and return a Response object;
HTTP header and the contents of the Response object will be sent back to the client.
Creating a controller is as easy as creating a page, and maps a URI to the controller.
Although the names are similar, the front-end controller is different from the controller we are talking about in this chapter. The front-end controller is a PHP applet in your web/
directory. file, all requests go directly through it. A typical application will have a front-end controller for production (such as app.php
) and a front-end controller for development (such as app_dev.php
). You never need to edit, view, or worry about front controllers. The "controller classes" in this chapter use a convenient method to organize their respective "controllers", also called actions, into one class (for example, updateAction()
, deleteAction( )
, wait). Therefore, a controller is a method in the controller class. They will hold the code you created and return the Response
response object.
A simple controller ¶
Although a controller can be any PHP callable (function, object method or Closure
), in Symfony, the controller is usually a method in the controller class, and the controller is often called action:
// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Response; class HelloController{ public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); }}
The controller here is indexAction
method, which belongs to a controller class HelloController
.
This controller is very simple:
Line 2: Symfony uses the PHP namespace function to name the entire controller class
Line 4: Symfony makes full use of the namespace function of PHP5.3:
use
keyword imports theResponse
class, which our controller must return;Line 6: The class name is a concatenation of the controller class name (such as
hello
) plus theController
keyword. This is a convention that provides consistency to controllers and allows them to reference the controller name (e.g.hello
) as routing configuration.Line 8: Each action in the controller class has the suffix
Action
, and the action name (index
) is Referenced to the routing configuration file. In the next section, we will use routing to map a URI to the action and show how to turn the route placeholder ({name}
) into the action parameter ($name
) ;Line 10: The controller creates and returns a
Response
object.
Mapping URIs to Controllers ¶
Our new controller returns a simple HTML page. To be able to render this controller at a specified URI, we need to create a route for it. We'll discuss the details of routing components in the routing chapter, but for now let's create a simple route for our controller:
Annotations:// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Component\HttpFoundation\Response;use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class HelloController{ /** * @Route("/hello/{name}", name="hello") */ public function indexAction($name) { return new Response('<html><body>Hello '.$name.'!</body></html>'); }}
YAML:# app/config/routing.ymlhello: path: /hello/{name} # uses a special syntax to point to the controller - see note below defaults: { _controller: AppBundle:Hello:index }.
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="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"> <route id="hello" path="/hello/{name}"> <!-- uses a special syntax to point to the controller - see note below --> <default key="_controller">AppBundle:Hello:index</default> </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\Route;use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection();$collection->add('hello', new Route('/hello/{name}', array( // uses a special syntax to point to the controller - see note below '_controller' => 'AppBundle:Hello:index',))); return $collection;
Now, you come to /hello/ryan
(for example, if you use the built-in web service http://localhost:8000/hello/ryan
), then it The HelloController::indexAction()
controller will be executed, and ryan
will be assigned to the $name
variable. Creating such a page allows a simple association between routing and controllers.
Simple, right?
Pass routing parameters into the controller ¶
We now know that the route points to the HelloController::indexAction()
method in the AppBundle. What is even more interesting is the parameter passing of the controller method:
// src/AppBundle/Controller/HelloController.php// ...use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; /** * @Route("/hello/{name}", name="hello") */public function indexAction($name){ // ...}
The controller has a parameter $name
, which corresponds to the {name}
parameter of the matched route ( If you visit /hello/ryan
, in this case ryan
). In fact, when your controller is executed, Symfony matches every parameter in the parameterized controller in the matched route. So this {name}
value is passed into $name
. Just make sure the placeholder name matches the parameter name.
Here is a more interesting example, where the controller has two parameters:
Annotations:// src/AppBundle/Controller/HelloController.php// ... use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class HelloController{ /** * @Route("/hello/{firstName}/{lastName}", name="hello") */ public function indexAction($firstName, $lastName) { // ... }}
YAML:# app/config/routing.ymlhello: path: /hello/{firstName}/{lastName} defaults: { _controller: AppBundle:Hello:index }
XML:<!-- app/config/routing.xml --><?xml version="1.0" encoding="UTF-8" ?><routes xmlns="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"> <route id="hello" path="/hello/{firstName}/{lastName}"> <default key="_controller">AppBundle:Hello:index</default> </route></routes>
PHP:// app/config/routing.phpuse Symfony\Component\Routing\Route;use Symfony\Component\Routing\RouteCollection; $collection = new RouteCollection();$collection->add('hello', new Route('/hello/{firstName}/{lastName}', array( '_controller' => 'AppBundle:Hello:index',))); return $collection;
Mapping route parameters to controller parameters is very easy and flexible. Please follow the following ideas when you develop:
Symfony can match controller method parameters based on route parameter names. In other words, it can match the last_name
parameter with the $last_name
parameter. The controller can work normally with any arrangement of parameters.
public function indexAction($lastName, $firstName){ // ...}
2. The parameters required by the controller must match the routing parameters
A runtime exception will be thrown below (RuntimeException
) , because there is no foo
parameter in the route definition:
public function indexAction($firstName, $lastName, $foo){ // ...}
It would be nice if the parameter was optional. The following example will not throw an exception:
public function indexAction($firstName, $lastName, $foo = 'bar'){ // ...}
3. Not all routing parameters need to have response parameters on the controller
If, for example, last_name
is not very important to your controller, you can ignore it completely:
public function indexAction($firstName){ // ...}
you You can also pass other parameters from your router to your controller parameters. See how to pass additional information from the route to the controller
Controller base class ¶
For convenience, Symfony provides an optional Controller
base class. If you inherit from it, it doesn't change anything about how your controller works, and you can easily inherit some helper methods and service containers (see Accessing Other Containers, below): allowing you to access everything in the system Useful object, similar to an array object. These useful objects are called services, and symfony comes with these service objects, which can render templates, record log information, etc.
Use the use statement at the top to add the Controller
class, and then modify HelloController
to inherit it. As shown below:
// src/AppBundle/Controller/HelloController.phpnamespace AppBundle\Controller; use Symfony\Bundle\FrameworkBundle\Controller\Controller; class HelloController extends Controller{ // ...}
Regardless of whether you use the Controller
base class, these helper methods just allow you to easily use the core functions of Symfony. In fact, the best way to view the core functionality is to look at the Controller
class itself.
Generate URL ¶
generateUrl()
Auxiliary method that can generate a URL to the router.
Redirect ¶
If you want to redirect the user to another page, please use redirectToRoute()
Method:
public function indexAction(){ return $this->redirectToRoute('homepage'); // redirectToRoute is equivalent to using redirect() and generateUrl() together: // return $this->redirect($this->generateUrl('homepage'));}
By default, the redirectToRoute()
method performs a 302 (temporary) redirect. If you want to perform a 301 (permanent) redirect, please modify the 2nd parameter:
public function indexAction(){ return $this->redirectToRoute('homepage', array(), 301);}
From directing to an external website, use redirect()
and pass in the external URL:
public function indexAction(){ return $this->redirect('http://symfony.com/doc');}
For more details, please refer to Framework Start Routing.
The redirectToRoute()
method is a simple shortcut than creating a Response
object that specializes in redirecting users. Equivalent to:
use Symfony\Component\HttpFoundation\RedirectResponse; public function indexAction() { return new RedirectResponse($this->generateUrl('homepage')); }
Rendering Templates ¶
If you use HTML, you should want to render a template. The render()
method can be used to render the template and put the output content into your Response
object:
// renders app/Resources/views/hello/index.html.twig return $this->render('hello/index.html.twig', array('name' => $name));
The template can also prevent deeper sub- Table of contents. But you should avoid creating unnecessary deep structures:
// renders app/Resources/views/hello/greetings/index.html.twigreturn $this->render('hello/greetings/index.html.twig', array( 'name' => $name));
Templates can render content in a universal way in any file format. Although in most cases you use templates to render HTML content, templates can also easily generate JavaScript, CSS, XML, or any other format you can think of. To learn how to format different templates, see "Template Formatting" in Creating and Using Templates.
Access other services ¶
Symfony has stuffed many useful objects into services. These services are used to render templates, send emails, query databases, and any other "job" you can think of. When you install a new bundle, it may also bring more services.
After inheriting the controller
base class, you can access any Symfony service through the get()
method. Some common services are listed below:
$templating = $this->get('templating'); $router = $this->get('router'); $mailer = $this->get('mailer');
What services exist? I want to see all services, please use the debug:container
command line view:
$ php bin/console debug:container
For more information, please see the service container
Manage Errors and 404 page ¶
If some actions are not found, a 404 response will be returned. To do this, you need to throw an exception. If you inherit the base Controller
class, you can do the following:
public function indexAction(){ // retrieve the object from database $product = ...; if (!$product) { throw $this->createNotFoundException('The product does not exist'); } return $this->render(...);}
createNotFoundException()
method creates a special NotFoundHttpException
Object to trigger the 404 response of http inside symfony.
Of course, you are also free to throw any Exception
class in your controller, and Symfony will automatically return HTTP response code 500.
throw new \Exception('Something went wrong!');
In each example, a formatted error page is displayed to the end user, while a debug page full of errors is displayed to the developer (when in debug modeapp_dev.php
When viewing this page - you can view the configuration of Symfony (and environment)).
These error pages can be customized. To learn more read "How to Customize Error Pages".
Request object as a controller parameter ¶
What if you need to get query parameters, grab request headers or get an uploaded file? This information is stored in Symfony's Request
object. To get them in your controller, just add the Request
object as a parameter and force the type to the Request
class:
use Symfony\Component\HttpFoundation\Request; public function indexAction($firstName, $lastName, Request $request){ $page = $request->query->get('page', 1); // ...}
Manage Session ¶
Symfony provides a useful Session object that can store information about the user (it can be a person using a browser, a bot, or a web service) between requests. By default, Symfony saves attributes in cookies by using PHP's native Session.
To obtain this session, you need to call the getSession()
method of the Request
object. This method will return a SessionInterface
, which uses the simplest method to store and retrieve session data:
use Symfony\Component\HttpFoundation\Request; public function indexAction(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 be retained during the validity period of the user session.
Flash Message ¶
You can also store some specified messages in the user session. This message is called a "flash message". As a rule of thumb, flash messages can only be used once: they disappear automatically when you retrieve them. This property makes "flash" messages particularly suitable for storing user notifications.
Let's look at our example of handling form submission:
use Symfony\Component\HttpFoundation\Request; public function updateAction(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()->add return $this->redirectToRoute(...); } return $this->render(...);}
After processing the request, the controller sets a flash message called notice and then redirects. The name (notice
) is not important – it is an identifier that identifies the message.
Next is the template (or better yet, a template in your base layout) that reads each piece of information from the session:
XML:{% for flash_message in app.session.flashBag.get('notice') %} <div class="flash-notice"> {{ flash_message }} </div>{% endfor %}
PHP:<?php foreach ($view['session']->getFlash('notice') as $message): ?> <div class="flash-notice"> <?php echo "<div class='flash-error'>$message</div>" ?> </div><?php endforeach ?>
Usually used notice
, warning
and error
are used as keys for different types of prompt messages, but you can use any key you need.
You can use the peek()
method to get the message, which allows the message to be saved.
Request and Response Object ¶
As mentioned earlier, the Request
object of the framework will be passed in as a parameter of the controller and the data type is forced to be Request
Class:
use Symfony\Component\HttpFoundation\Request; public function indexAction(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');}
This Request
class has some public properties and methods that can return any request information you need.
Like Request
, the Response
object also has a public headers
property. It's a ResponseHeaderBag
It has some nice methods for getting and setting response headers. The normalization of header names makes Content-Type
equal to content-type
or even equal to content_type
, which are all the same.
For the controller, the only requirement is to return a Response object. The Response class is a PHP abstraction for HTTP responses. A text-based message fills the HTTP header, and its content is sent back to the client:
use Symfony\Component\HttpFoundation\Response; // create a simple Response with a 200 status code (the default)$response = new Response('Hello '.$name, Response::HTTP_OK); // create a CSS-response with a 200 status code $response = new Response('<style> ... </style>'); $response->headers->set('Content-Type', 'text/css');
There are also some special classes that can simplify certain responses:
For JSON: This is a
JosnResponse
. Viewable Create a JOSN response.For file operations: this is
BinaryFileResponse
. Serving Files can be viewed.For streaming responses, there is
StreamedResponse
. See: Streaming a Response
JSON Helper ¶
##3.1json() The helper was introduced starting from symfony3.1.
The return JSON type is increasingly popular in API-based applications. For this reason, the controller base class defines the json()
method to create a JsonResponse
and automatically encode the given content:
// ...public function indexAction(){ // returns '{"username":"jane.doe"}' and sets the proper Content-Type header return $this->json(array('username' => 'jane.doe')); // the shortcut defines three optional arguments // return $this->json($data, $status = 200, $headers = array(), $context = array());}
if the Serializer service If enabled in your application, content passed to json()
will be automatically encoded. Otherwise, you will want to use the json_encode function.
You now understand the basics of the Symfony Request
and Response
objects. You can also refer to the HttpFoundation component to learn more. .
Create a static page ¶
You can create a static page without a controller (just a route and template are required). Reference How to render templates without using a custom controller.
Summary ¶
When you create a page, you need to write some business logic code in the page. In symfony, these are controllers, which are PHP functions that can do anything to return the final Response
object to the user.
And you can inherit the Controller
base class to make your work easy. For example, instead of writing html code into the controller, you can use render()
to render the template and return the template content.
In other chapters, you'll see how controllers are used to read objects from the database and persist them, handle form submissions, operate caching, and more.
Keep Going ¶
Next, focus on learning to use Twig to render templates.