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 a that displays the blog post. Response object. If {slug} cannot be retrieved from the database, the controller will create and return a Response 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:

  1. Each request is handled by a single front-end controller (such as app.phpProduction environment or app_dev.phpdevelopment environment) file processing, the front-end controller is responsible for booting the framework;

  2. The only job of the front-end controller It is to initialize the Symfony engine (call Kernel) and pass in a Request object to let it process.

  3. Symfony core asks the router to check the request;

  4. The router looks at and matches the request information and points it to a specific route, which Routing determines which controller to call;

  5. Execute the controller, the code in the controller will create and return a Response object;

  6. 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.

1466410869_65826_51226_http-xkcd-request.png

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 the Response class, which our controller must return;

  • Line 6: The class name is a concatenation of the controller class name (such as hello) plus the Controller 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?

AppBundle:Hello:index Controller Syntax

If you are using YAML or XML format, the one you use for your controller A specific shortcut syntax is called a logical controller name, such as AppBundle:Hello:index. For more information about controller formats, read Controller Naming Patterns in the Router chapter.

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:

1. The order of controller parameters does not matter

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.

If you want to know how a controller works without inheriting the controller base class, you can check out how to define a controller as a service. This is optional, but it gives you precise control over more of the "objects/dependencies" that can be injected into your controller.

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.

Template naming pattern

You can also put the template in a bundleResources/views Directory and refer to their special shortcut syntax, such as @App/Hello/index.html.twig or @App/layout.html.twig. These will be stored in the bundle's Resources/views/Hello/index.html.twig and Resources/views/layout.html.twig

respectively.

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.