Symfony 2.4, el libro oficial

5.3. Asociando una URI a un controlador

El nuevo controlador devuelve una página HTML simple. Para poder probar realmente esta página en tu navegador, debes crear una ruta cuyo path sea la URI que quieres asociar al controlador:

# app/config/routing.yml
hello:
    path:         /hello/{name}
    defaults:     { _controller: AcmeHelloBundle:Hello:index }
<!-- app/config/routing.xml -->
<route id="hello" path="/hello/{name}">
    <default key="_controller">AcmeHelloBundle:Hello:index</default>
</route>
// app/config/routing.php
$collection->add('hello', new Route('/hello/{name}', array(
    '_controller' => 'AcmeHelloBundle:Hello:index',
)));

Ahora, al acceder a la URI /hello/ryan se ejecuta el controlador HelloController::indexAction() y se pasa el valor ryan como una variable llamada $name. De nuevo, crear una página significa simplemente que debes crear un método controlador y una ruta asociada.

Observa la sintaxis utilizada para referirse al controlador: AcmeHelloBundle:Hello:index. Symfony2 utiliza esta notación corta para referirse a los controladores. Se trata de la sintaxis recomendada y le dice a Symfony2 que busque una clase controlador llamada HelloController dentro de un paquete llamado AcmeHelloBundle y que después ejecute el método indexAction().

Nota Este ejemplo define la configuración de enrutamiento directamente en el directorio app/config/. Una mejor manera de organizar tus rutas es colocar cada una en el bundle al que pertenece.

Truco Puedes aprender mucho más sobre el sistema de enrutado en el capítulo de enrutamiento.

5.3.1.  Parámetros de la ruta como argumentos del controlador

Como ya se explicó anteriormente, el valor AcmeHelloBundle:Hello:index del parámetro _controller se refiere al método HelloController::indexAction() del bundle AcmeHelloBundle. Lo más interesante son los argumentos que se pasan a ese método:

<?php
// src/Acme/HelloBundle/Controller/HelloController.php

namespace Acme\HelloBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class HelloController extends Controller
{
    public function indexAction($name)
    {
      // ...
    }
}

El controlador anterior tiene un solo argumento, llamado $name, cuyo valor corresponde al parámetro {name} de la ruta asociada (este valor es ryan en nuestro ejemplo). De hecho, cuando ejecutas tu controlador, Symfony2 asocia cada argumento del controlador con un parámetro de la ruta. Considera el siguiente ejemplo:

# app/config/routing.yml
hello:
    path:         /hello/{firstName}/{lastName}
    defaults:     { _controller: AcmeHelloBundle:Hello:index, color: green }
<!-- app/config/routing.xml -->
<route id="hello" pattern="/hello/{firstName}/{lastName}">
    <default key="_controller">AcmeHelloBundle:Hello:index</default>
    <default key="color">green</default>
</route>
// app/config/routing.php
$collection->add('hello', new Route('/hello/{firstName}/{lastName}', array(
    '_controller' => 'AcmeHelloBundle:Hello:index',
    'color'       => 'green',
)));

Ahora el controlador admite varios argumentos:

public function indexAction($firstName, $lastName, $color)
{
    // ...
}

Las variables {firstName} y {lastName} de la ruta se llaman placeholders, ya que "guardan el sitio" para que cualquier valor sustituya esa variable. Por otra parte, la variable color es una variable de tipo default, ya que su valor siempre está definido para todas las rutas.

Independientemente del tipo de variable, los valores de {first_name}, {last_name} y color están disponibles en el controlador. Cuando se ejecuta una ruta, tanto los placeholders como las variables por defecto se fusionan en un único array que se pasa al controlador.

Asociar parámetros de la ruta a los argumentos del controlador es bastante fácil y flexible. Pero debes tener en cuenta las siguientes pautas mientras desarrollas.

1. El orden de los argumentos del controlador no importa:

Symfony2 es capaz de asociar los nombres de los parámetros de la ruta con los nombres de las variables en la declaración del método controlador. En otras palabras, se da cuenta de que el parámetro {lastName} coincide con el argumento $lastName.

Así que puedes cambiar el orden de los argumentos como quieras y todo seguirá funcionando bien:

public function indexAction($lastName, $color, $firstName)
{
    // ...
}

2. Cada argumento obligatorio del controlador debe tener asociado un parámetro en la ruta

El siguiente código producirá una excepción de tipo RuntimeException porque no hay ningún parámetro foo definido en la ruta:

public function indexAction($firstName, $lastName, $color, $foo)
{
    // ...
}

Sin embargo, es perfectamente válido hacer que el argumento sea opcional. El siguiente ejemplo no lanzará una excepción:

public function indexAction($firstName, $lastName, $color, $foo = 'bar')
{
    // ...
}

3. No todos los parámetros de la ruta deben ser argumentos en tu controlador

Si por ejemplo, lastName no es tan importante para tu controlador, lo puedes omitir por completo:

public function indexAction($firstName, $color)
{
    // ...
}

Truco Todas las rutas incluyen además un parámetro especial llamado _route, que guarda el nombre de la propia ruta (en este ejemplo, hello). Normalmente no se utiliza, pero también está disponible como argumento del controlador.

5.3.2. El objeto Request como argumento del controlador

Suele ser muy útil disponer en el controlador del objeto Request asociado a la petición del usuario, especialmente cuando trabajas con formularios. Para hacer que Symfony pase este objeto automáticamente como argumento del controlador, utiliza el siguiente código:

use Symfony\Component\HttpFoundation\Request;

public function updateAction(Request $request)
{
    $form = $this->createForm(...);

    $form->handleRequest($request);

    // ...
}