Controller

Un controlador es una función PHP creada por nosotros que lee información del objeto Request y crea y devuelve un objeto Response. La respuesta podría ser una página HTML, JSON, XML, una descarga de archivos, una redirección, un error 404 o cualquier otra cosa que puedas hacer. El controlador ejecuta cualquier lógica arbitraria que tu aplicación necesita para representar el contenido de una página.

En apartados anteriores hemos visto el uso básico de los controladores y cómo definir las rutas.

Redireccionar

Si queremos redirigir al usuario a otra página, usamos los métodos redirectToRoute() y redirect():

<?php
use Symfony\Component\HttpFoundation\RedirectResponse;

...
public function indexAction()
{
    // redirect to the "homepage" route
    return $this->redirectToRoute('homepage');

    // redirectToRoute is a shortcut for:
    // return new RedirectResponse($this->generateUrl('homepage'));

    // do a permanent - 301 redirect
    return $this->redirectToRoute('homepage', array(), 301);

    // redirect to a route with parameters
    return $this->redirectToRoute('app_lucky_number', array('max' => 10));

    // redirect externally
    return $this->redirect('http://symfony.com/doc');
}

Gestionar errores y páginas 404

Cuando las cosas no se encuentran, debemos devolver una respuesta 404. Para hacer esto, lanzamos un tipo especial de excepción:

<?php
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
// ...
public function indexAction()
{
    // retrieve the object from database
    $product = ...;
    if (!$product) {
        throw $this->createNotFoundException('The product does not exist');

        // the above is just a shortcut for:
        // throw new NotFoundHttpException('The product does not exist');
    }

    return $this->render(...);
}

Por supuesto, podemos lanzar cualquier clase de excepción en su controlador: Symfony devolverá automáticamente un código de respuesta HTTP de 500.

<?php
throw new \Exception('Something went wrong!');

Por ejemplo:

<?php
//BlogController.php
class BlogController  extends Controller{
    // ...
    /**
  * @Route("/blog/{page}", name="blog_list", requirements={"page"="\d+"}, defaults={"page"=1})
  */
    public function list()
    {
      throw $this->createNotFoundException('Esta entrada no existe');
    }

De esta forma, al visitar la página http://localhost/symfony/blog/1 nos genera la siguiente salida HTML, cuando estamos en modo developer, (dev) Y la siguiente salida cuando estamos en modo production (prod): Para cambiar el modo de entorno (environment) de symfony, se debe editar el fichero .env

APP_ENV=prod // prod || dev

Se puede cambiar la plantilla devuelta por defecto por Symfony cuando se producen errores. En la siguiente página se explica cómo hacerlo.

El objeto Request

Podemos usar el objeto Request de Symfony si lo pasamos como argumento a una función

<?php
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');
}

Devolver una respuesta JSON

Para devolver JSON desde un controlador, usamos el método helper json(). Esto devuelve un objeto especial JsonResponse que codifica los datos automáticamente:

<?php
// ...
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());
}

Devolver ficheros en streaming

Podemos usar el helper file() para servir un archivo desde dentro de un controlador:

<?php
use Symfony\Component\HttpFoundation\File\File;
// ...
public function fileAction()
{
    // send the file contents and force the browser to download it
    return $this->file('../static/hola.txt');
}

El fichero está en este caso en la carpeta static (creada a la altura de public)

El helper file() proporciona algunos argumentos para configurar su comportamiento:

<?php
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

public function fileAction()
{
    // load the file from the filesystem
    $file = new File('/path/to/some_file.pdf');

    return $this->file($file);

    // rename the downloaded file
    return $this->file($file, 'custom_name.pdf');

    // display the file contents in the browser instead of downloading it
    return $this->file('invoice_3241.pdf', 'my_invoice.pdf', ResponseHeaderBag::DISPOSITION_INLINE);
}

Uso de sesiones

Podemos usar el objeto SessionInterface de Symfony si lo pasamos como argumento a una función

<?php
use Symfony\Component\HttpFoundation\Session\SessionInterface;

public function indexAction(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());
}

Mensajes Flash

También podemos almacenar mensajes especiales, llamados mensajes “flash”, en la sesión del usuario. Por diseño, los mensajes flash deben usarse exactamente una vez: desaparecen de la sesión automáticamente tan pronto como los recuperamos. Esta función hace que los mensajes “flash” sean especialmente útiles para almacenar notificaciones de usuario.

Por ejemplo, imagina que está procesando un envío de formulario:

<?php
use Symfony\Component\HttpFoundation\Request;

public function updateAction(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(...);
}

Después de procesar la request, el controlador establece un mensaje flash en la sesión y luego redirige. La clave del mensaje (aviso en este ejemplo) puede ser cualquier cosa: usará esta clave para recuperar el mensaje.

En la plantilla siguiente (o incluso mejor, en la plantilla de diseño base), leemos los mensajes flash de la sesión usando app.flashes():

# templates/base.html.twig #}

{# you can read and display just one flash message type... #}
{% for message in app.flashes('notice') %}
    <div class="flash-notice">
        {{ message }}
    </div>
{% endfor %}

{# ...or you can read and display every flash message available #}
{% for label, messages in app.flashes %}
    {% for message in messages %}
        <div class="flash-{{ label }}">
            {{ message }}
        </div>
    {% endfor %}
{% endfor %}