Aunque el release de la versión final de Symfony2 haya sido retrasado, los chicos de SensioLabs (y toda la comunidad Symfony, por supuesto) siguen avanzando pasito a pasito para solucionar todos los bugs y cerrar toda la documentación, condiciones necesarias para terminar con la fase beta. Mientras tanto, nosotros los desarrolladores de a pie podemos aprovechar para ir familiarizándonos con los (considerables) cambios con respecto a la versión 1.4, aunque actualmente nos enfrentamos a una situación prácticamente inédita: la documentación existente todavía es escasa y no está actualizada (ni mucho menos traducida al castellano, para todos aquellos que no estéis a gusto con el inglés).
Como el título de este post indica, vamos a tratar una de las partes más potentes, y a su vez que más quebraderos de cabeza provoca del framework Symfony: el Routing. Aunque la definición en sí del Routing (mediante patrones de reglas y el uso de wildcards o variables) no ha cambiado (demasiado) con respecto a las versiones de Symfony 1.x, donde sí que han habido extensos cambios (y, en nuestra modesta opinión, para mucho mejor) es la forma de configurarlo, y es en estas novedades en las que nos vamos a centrar.
¿Symfony2? ¿Routing?
Lo primero es lo primero, y antes de hablar específicamente sobre el Routing, deberíamos echarle un ojo a las nuevas características que nos trae Symfony2, y para eso, recomiendo el Quick Tour de Symfony2 donde se muestran muchas novedades interesantes.
El objetivo del sistema de Routing en Symfony es mapear patrones de rutas URL a los diferentes controladores de la aplicación, con lo que nos permite utilizar de forma fácil y mantenible pretty URLs («an absolute MUST to any serious web application», en palabras de los creadores de Symfony). Una vez puestos en situación, tenemos la documentación del Routing en el libro oficial de Symfony2 (aún en inglés, claro), lectura de referencia obligada.
Formato de Configuración del Routing
La primera gran noticia es que además de utilizar YAML para definir los archivos de configuración del Routing de Symfony, también podemos definirlas tanto en XML como vía PHP de forma intercambiable y sin afectar al rendimiento de la aplicación, ya que las rutas generadas son cacheadas. Incluso podemos utilizar una combinación de todas para definir nuestras rutas. No es que tengamos problemas con el formato YAML en particular (aunque puede resultar bastante odiable, sobre todo si algo falla), pero todo lo que sean más opciones para el desarrollador es siempre bienvenido.
La sintaxis en XML es por supuesto mucho más verbosa, pero también más potente, y de todas formas, creo que a estas alturas la mayoría de desarrolladores estamos tan acostumbrados a las estructuras de nodos en formato XML que quizás nos resulte más intuitiva, y con la ventaja adicional de que nuestro IDE nos ayudará a autocompletar los nodos y nos informará amablemente si nos hemos colado en algún sitio. Por supuesto, la opción más potente pero mucho menos legible (y por tanto, yo creo que menos recomendable) será definir las rutas «a pincho» mediante código PHP. Existe una alternativa muy elegante que es definir la ruta mediante annotations (es decir, mediante comentarios en el propio código PHP) embebidas en el controlador, una pequeña joya que comentaremos exhaustivamente más adelante.
Archivos de Routing Externos
La siguiente diferencia en la configuración del Routing, y quizás con aún mayor relevancia que el punto anterior, es que ahora se pueden hacer includes (o imports) de otros ficheros externos de Routing. Si alguna vez habéis programado un proyecto relativamente grande en Symfony 1.x seguro que el routing.yml acabó siendo una pesadilla organizativa donde había casi tantos comentarios de referencia para distinguir qué rutas correspondían a qué módulos como rutas en sí. Pues bien, gracias a esta nueva y genial feature, podemos afirmar que esto es cosa del pasado. Ahora, cada controlador puede definir sus propias rutas, y tan sólo debemos importarlas desde el fichero principal de configuración de Routing.
Además, podemos definir prefijos para estas rutas cargadas externamente, lo cual nos ayudará aún más a tener nuestras rutas bien organizadas, simples y elegantes.
@Route: Annotations al poder
Las annotations son una de las features del lenguaje Java a la que más partido se le puede sacar y que, aunque no son soportadas de forma nativa por PHP, en Symfony2 pueden utilizarse para configurar muchas funcionalidades de los controladores de manera simple y concisa. Para ello, deberemos activar el SensioFrameworkExtraBundle. No te dejes intimidar por eso de experimental, sigue leyendo y verás como merece la pena «arriesgarse» por la potencia que tienen.
La annotation @Route es la que aquí nos concierne. Su función es mapear un patrón de ruta con una función controlador, y como ya hemos comentado, lo mejor es que lo hace desde el propio código del controlador. Podemos encontrar la documentación de @Route aquí. La mayor ventaja es que además, de esta manera, el código del controlador y su configuración asociada se encontrarán en el mismo archivo (el de la clase del controlador). A la hora de definir rutas más o menos complejas mediante una annotation @Route se pueden utilizar por supuesto variables, requerimientos, etc. tal y como haríamos con una ruta definida por cualquier otro método. Por ejemplo:
/** * @Route( "/lista/:nombre/:page", requirements:{ "page" = "\d+"}, defaults:{"page"="1"} ) */ public function listarAction() { //código de la acción }
Características adicionales a destacar:
-
Nombre de Ruta
Por defecto, una ruta definida con una annotation @Route recibe un nombre basado en una concatenación del nombre del controlador y el método (acción) sobre el que se define. Por nuestra experiencia, es clave que los nombres de rutas en Symfony sean fáciles de recordar, sencillos y sobre todo autoexplicativos, así que recomendamos encarecidamente el uso del atributo de annotation name para definir un nombre de ruta que cumpla esas características. Por ejemplo:
/** * @Route("/", name="lista_productos") */ public function listarAction() { //código de la acción }
-
Prefijos
Una annotation @Route definida a nivel de clase (en lugar de a nivel de método o acción) define un prefijo para todas las rutas que se definan dentro de los métodos de esta clase. Ya hemos comentado brevemente los prefijos a la hora de incluir archivos de ruta externos, pues bien utilizando annotations también podemos disfrutar de la potencia y limpieza organizativa de esta característica nueva del Routing de Symfony 2.
/** * @Route("/productos") */ class ProductoController extends Controller { /** * @Route("/:nombre", name="mostrar_producto") */ public function mostrarAction($id) { //código de la acción } }//end of class
Así, hemos mapeado la acción mostrar (definida en la función mostrarAction) dentro del controlador de producto a una regla de Routing cuyo nombre es mostrar_producto y cuyo patrón es /productos/:nombre
-
Importación for Dummies
Otra ventaja de las annotations es que nunca se nos olvidará importarlas en el archivo de configuración principal del Routing ya que podemos importar directamente las rutas de todos los controladores (así, a saco) o también por controlador individualmente.
# import routes from all controllers all: resource: annotations:*/Controller
En resumen, un montón de potentes y jugosas novedades que nos harán sin duda la vida mucho más fácil desde un punto de vista logístico. El Routing de Symfony, que ya era de por sí una pequeña maravilla, ha ganado enteros en donde más fallaba: a nivel organizativo.
EL link nuevo de la documentacion de @Route es: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/routing.html
Saludos!
[…] unos días escribimos un post informativo sobre cómo configurar el Routing de Symfony2, sobre todo atendiendo a los cambios y novedades con respecto a las versiones 1.x del Framework […]