Definición de rutas con comodines
No sólo de rutas estáticas se compone una aplicación web, usualmente se necesitan pasar parámetros variables por GET, es decir, por la URL y es aquí en donde el Routing saca lo mejor que tiene. Un marcador de posición o comodín es un segmento de la ruta variable, como por ejemplo: /blog/articulo_x dónde articulo_x es una parte variable que representa la página a consultar, en Symfony2 estos comodines se definen entre llaves "{}":
# src/MDW/DemoBundle/Resources/config/routing.yml blog_mostrar: pattern: /blog/{slug} defaults: { _controller: MDWDemoBundle:Blog:show }
# src/MDW/DemoBundle/Resources/config/routing.yml blog_mostrar: pattern: /blog/{slug} defaults: { _controller: MDWDemoBundle:Blog:show }
La parte {slug} representa nuestro comodín y como es variable cualquier URL que coincida con la expresión: /blog/* empatará con dicha ruta, además el mismo comodín (slug) va a coincidir con el parámetro slug que definamos en el Controlador, por ejemplo, en una ruta /blog/el_articulo_de_symfony en el controlador la variable (parámetro) $slug contendrá “el_articulo_del_symfony”.
De forma predeterminada los comodines son requeridos, si tuvieses, por ejemplo, una ruta de paginación como esta: /blog/page/1 tendrías que definir un comodín para el número de página, pero estarías obligado siempre en agregar “1”, esto se resuelve añadiendo un valor por defecto:
# src/MDW/DemoBundle/Resources/config/routing.yml blog_index: pattern: /blog/page/{page} defaults: { _controller: MDWDemoBundle:Blog:index, page: 1 }
De esta forma añadimos el valor por defecto del comodín page: 1 como parámetro del atributo defaults.
Agregando Requisitos a la ruta
Hasta ahora tenemos dos rutas: /blog/{slug} y /blog/page/{page}, la segunda es poco práctica ¿que pasaría si la simplificamos como /blog/{slug} y /blog/{page}?, que ambos patrones asemejan con /blog/* y el Routing solo tomará en cuenta la primera ruta coincidente. La solución a este problema es añadir requerimientos, como por ejemplo definir que el comodín {page} acepte solo números que es lo que realmente lo diferencia del {slug}:
# src/MDW/DemoBundle/Resources/config/routing.yml blog_index: pattern: /blog/{page} defaults: { _controller: MDWDemoBundle:Blog:index, page: 1 } requirements: page: \d+ blog_mostrar: pattern: /blog/{slug} defaults: { _controller: MDWDemoBundle:Blog:show }
Nótese que con el nuevo parámetro requirements: puedes definir expresiones regulares para cada comodín, en el caso anterior al añadirle \d+ a {page} le indicamos al Routing que dicho parámetro debe coincidir con la expresión regular, lo que te permite definir el requerimiento de acuerdo a tus necesidades.
Es importante aclarar que debes declarar tus rutas en un orden lógico, debido a que el Routing toma en cuenta la primera ruta que coincide, por ejemplo, si defines la ruta blog_mostrar antes de blog_index no funcionará porque como blog_mostrar no tiene requerimientos, cualquier número coincide perfectamente con {slug} y llegar a {page} nunca será posible de esa forma.
Además de especificar requisitos para cada comodín, existen otros de mucha ayuda:
- _method: [GET | POST ] como lo indica su nombre, permite establecer como restricción que la ruta solo coincida si la petición fue POST o GET, muy útil cuando nuestra acción del controlador consista en manipulación de datos o envío de forms.
- _format: es un parámetro especial que permite definir el content-type de la Respuesta (Response), puede ser utilizado en el patrón como el comodín {_format} y de esta forma pasarlo al Controlador.
Con todo esto ya somos capaces de crear rutas dinámicas con Symfony2, pero el sistema de Routing es tan flexible que permite crear rutas avanzadas, veamos:
# src/MDW/DemoBundle/Resources/config/routing.yml blog_articulos: pattern: /articulos/{culture}/{year}/{titulo}.{_format} defaults: { _controller: MDWDemoBundle:Blog:articulos, _format: html } requirements: culture: en|es _format: html|rss year: \d{4}+
En este ejemplo podemos apreciar que {culture} debe coincidir con en o es, además {year} es un número de cuatro dígitos y el {_format} por defecto es html, así que las siguientes rutas empatan con nuestra anterior definición:
- /articulos/es/2000/patron_mvc
- /articulos/es/2000/patron_mvc.html
- /articulos/es/2000/patron_mvc.rss
Generando Rutas
Como anteriormente indicamos, el Routing es un sistema bidireccional, en el cual nos permite generar URLs desde las mismas definiciones de rutas, el objetivo es obvio: si deseas cambiar el patrón de la ruta lo haces y ya. No necesitas buscar los link’s internos hacia esa ruta dentro de tu aplicación si utilizas el generador de rutas de Symfony2.
La forma más común de utilizar el generador de rutas es desde nuestras plantillas (Vistas/Views) y para ello solo necesitamos acceder al objeto “router”, ejemplos:
Con TWIG como gestor de plantillas usamos path para obtener la url relativa
<a href="{{ path('blog_mostrar', { 'slug': 'mi-articulo' }) }}"> lee el artículo. </a>
O url si queremos una url absoluta:
<a href="{{ url('blog_mostrar', { 'slug': 'mi-articulo' }) }}"> lee el artículo. </a>
Con PHP como gestor de plantillas vemos que en realidad accedemos al helper router para obtener la url relativa:
<a href="<?php echo $view['router']->generate('blog_mostrar', array('slug' => 'mi-articulo')) ?>"> lee el artículo </a>
En el caso de querer una url absoluta solo debemos especificar true en el tercer parámetro de la función generate:
<a href="<?php echo $view['router']->generate('blog_mostrar', array('slug' =>'mi-articulo'), true) ?>;"> lee el artículo </a>
Así de sencillo. Si en nuestras vistas usamos el generador de rutas no tendremos que preocuparnos por la eventualidad de cambiar las URLs de nuestra aplicación, además de que también podemos acceder desde nuestros controladores gracias a la inyección de dependencias(DI) donde obtendremos el servicio “router”:
// src/MDW/DemoBundle/Controller/DefaultController.php class BlogController extends Controller { public function showAction($slug) { // ... $url = $this-&amp;gt;get('router')-&amp;gt;generate('blog_mostrar', array('slug' =&amp;gt; 'mi-articulo')); // Atajo si extiendes la clase Controller: $url = $this-&amp;gt;generateUrl('blog_mostrar', array('slug' =&amp;gt; 'mi-articulo')); } }
Esto es todo lo básico que debes saber para generar rutas dinámicas y concisas en Symfony2.
Resumen Final
Como podemos observar el sistema de rutas de Symfony2 no sólo nos permite definir caminos claros y concisos para nuestros usuarios, sino que también nos hace más fácil su implementación, con lo cual al cambiar el patrón de una ruta no tenemos que buscar todas las llamadas de la misma en la aplicación.
Además aprendimos a definir rutas condicionadas, entendimos la importancia del orden de declaración de las mismas y vimos como utilizar el sistema de routing bidireccional en nuestras vistas y controladores.
En el próximo capítulo profundizaremos sobre los controladores en Symfony2, aprenderemos a como definirlos y adaptarlos a nuestras necesidades.
Muy buen capítulo del curso de Symfony.
Hace poco escribí este tutorial en Cristalab sobre el uso del componente de rutas: http://www.cristalab.com/tutoriales/crear-urls-amigables-en-php-con-symfony2-y-el-componente-routing-c104486l/
Es interesante saber que aún si no usas Symfony para tu proyecto puedes valerte de casi todas sus clases por separado.
Interesante artículo, que demuestra la versatilidad y desacoplamiento de los componentes de Symfony2, gracias por el aporte 😀
[…] con la explicación del capítulo anterior de la guía de Symfony 2, hoy se ha publicado la segunda parte del sistema de routing en donde se entra más en detalle sobre la definición de URLs con […]
Exacto @Duilio una gran ventaja de Symfony es que funciona como framework o puedes utilizar los componentes por separado
Gracias por este capitulo, esta muy bueno. Les comento que ayer compre el libro Desarrollo web ágil con Symfony2 de Javier Eguiluz, que libro!!! lo recomiendo 100%
Genial, todavía no he tenido la oportunidad de comprar el libro (ni lo he visto), ha de ser excelente, en está Guía tendrás los conceptos claves bien definidos y explicados, espero que la disfrutes tanto como el libro de Eguiluz 😉
Hola, me surge una duda:
Y si por ejemplo quisiera utilizar blog/ para inglés y cuaderno/ para castellano deberia crear tantas entradas como idiomas?
Siempre tiene que haber una palabra reservada como blog o en su lugar se puede utilizar tambien un comodín?
@maycolalvarez tengo una pregunta que he buscado por todos lados durante toda la tarde, todos los tutoriales muestran como generar las entidades para luego crear las tablas en base de datos, pero nadie explica en ningún lado como seria el proceso inverso. Mi caso: tengo un desarrollo y lo quiero pasar a symfony 2, como hago para crear las entidades partiendo de las tablas existentes?
Eso corresponde al ORM Doctrine, el cual tiene un conversor de schema http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html, mas sin embargo el analizador tiene una efectividad de entre 70-80% por lo que una vez generadas las entidades tengas que hacer algunos ajustes.
De hecho en mi experiencia con las tablas para Asterisk en Postgres me resulto mas fácil crear las entidades manualmente de modo de Doctrine no me cambiara su estructura y así Asterisk pudiera seguir escribiendo los registros del CDR y queue_log.
Yo no lo haría de esa forma, lo ideal es tener como parte de la ruta un comodín para el idioma como /blog/{culture}/{slug}, que lo conserva semántico en este mundo globalizado por lo cual el inglés es el idioma predominante (así algunos no nos guste), pero también puedes predominar el español si quieres como /cuaderno/{culture}/{slug}, de lo contrario si deseas tener /{idioma}/{slug} tendrías que controlar $idioma desde el controlador, así no tendrías que definir una ruta por idioma :S, cosa que veremos en el próximo capítulo.
El Libro Desarrollo web ágil con Symfony2 de Javier Eguiluz es muy bueno, ampliamente recomendado para todos los interesados en desarrollar en Symfony2
para maycol alvarez,lo felicito por sus conocimientos y porque su asporte a las personas que lo necesecitan ,sencillamente creo que de gran utilidad., yo agradeceria en forma grandiosa el que usted conparta todo ese caudal de enlaces que utilizan y que son indispensables para los webmasters .
yo quiero comentarle que mi certificado de seguridad ha expirado o ha sido bloqueado ,y yo requiero ir a paginas web para encontrar solucion a un problema que tengo tuve un accidente un esfuerzo muy grande y mi columna trono y el resultado fue .,desviacion de columna por eso requiero ir a paginas web ., pero cuando ingreso a una pagina de ese tipo internet explorer me cierra la pagina .., hace tres dias ingrese a una carpeta y encontre lo que al parecer es una copia o como recupertar el certificado de seguridad yo deseo enviarle los datos para que los analize y si es asi le pido respetuasamente me ayude a recuperar mi certificado ojala y si fueran los datos para lo cual me refiero atentamente emeterio mendiola., de una vez le dejo los datos PFX PK G5= 12certutill exe wroot,realizar copia de seguridad de una entidad emisora de certificados.,ojala sean los datos ,para restablecer mi certificado de seguridad,es todo joven maycolalvarez estare al pendiente de su respuesta en cuanto el tiempo se lo permita gracias
Con todo respeto lo que requiere no tiene que ver con el tema, de todas formas he de aclararle que los certificados de seguridad tienen fecha de caducidad, además de que los mismos se adquieren ante organismos debidamente autorizados, los cuales siguen la cadena de confianza, de no serlo el certificado es rechazado. http://es.wikipedia.org/wiki/Autoridad_de_certificaci%C3%B3n
Aún así cualquiera puede generar un certificado gratuito para el uso, por ejemplo en intranets, para dar mayor seguridad a backends internos, pero en e caso de frontend públicas lo ideal es adquirir el certificado y renovarlo cada año.
Dbo guardar la url amigable en un campo de la tabla para poder hacer blog/{slug} y luego recuperar el artículo? como se generan url’s amigables con Symfony a partir de uan cadena?
La idea general es definir la ruta lo más simple y concisamente posible “/blog/{dyna_route}”, luego en tu controlador puedes interpretar $dyna_route y en función de ello llamar a los Modelos, Controladores y Vistas que consideres necesarios.
También aclaro que es una buena práctica guardar en todo caso el “slug” que no es nada más que un campo con índice único para la tabla como si fuera la PK pero no es la PK ya que los campos numéricos son mejor para indices primarios. Cuando envías el parámetro para buscar el artículo envías el slug en lugar del id y lo buscas por medio de ese campo único.
Supongamos que se tiene que acceder a mis datos, mi id podría ser el 54 y mi slug juan-ardissone (como lo armes dependerá de ti) para acceder a los datos de maycol podría ser id 105 con slug maycol-alvarez.
Esto es bueno también a nivel de seguridad ya que hay veces en los que es peligroso dejar a las personas modificar los ids que vienen por el request (?factura_id=1). Es mucho más fácil ir probando con números aleatorios que con los slugs
Gracias chicos, es lo que hago hasta ahora sin framework, eso no supone un problema. Mi duda era más a la hora de guardar en la base de datos el {dyna_route} a partir de un input de texto al que el usuario ha escrito porejemplo “Juan Ardissone”, provee algun metodo/classe Symfony para tratar y transformar dicha cadena a “juan-ardissone”?
Si te refieres a la generación de “Slugs”, Symfony2 no lo provee por defecto, pero puedes añadírselo con el Behavior Slug del StofDoctrineExtensionsBundle por Christophe Coevoet
(https://github.com/stof/StofDoctrineExtensionsBundle) el cual hace una implementación del complemento Doctrine2 behavioral extensions creado por Gediminas Morkevicius (https://github.com/l3pp4rd/DoctrineExtensions), de forma que Doctrine2 te cree Automáticamente los Slugs que necesites, los detalles de ésta implementación los expongo en el Capítulo 12 “Instalando Bundles de Terceros”, donde se verá un Tutorial para instalarlos Paso a Paso y generar los Slug’s, lo malo es que te tocará esperar alrededor de 6 semanas :-S, debido a la exigencia técnica de dicho capítulo, saludos y suerte 😉
[…] el capítulo anterior aprendimos a crear las rutas hacia nuestros controladores, como algunos ya saben el […]
[…] Alvarez para Maestros del Web. Agrega tu comentario | Enlace permanente al […]
Muy bueno el curso, con lenguaje ameno y explicaciones superentendibles… felicidades!!
Respecto éste capítulo, he probado el tema de las expresiones regulares… y la opción ‘solo digitos’ del parametro {page} me funciona únicamente si añadimos una contrabarra delante: \d+
Por cierto, en algunos ejemplos no se lee muy bien el código (por ejemplo: url = $this-&gt;get(‘router’)-&gt;gene…) …si lo pudierais arreglar estaría genial!
muchas gracias por compartir vuestro conocimiento!
Tienes razón, el “\” se ha perdido por el analizador de wordpress, ya he pedido las modificaciones, gracias 😉
Los cambios han sido realizados, muchas gracias 😉
Hola!! Muy buen post
Aqui mi pregunta
¿Porque una serie de enlaces del tipo
Hospital funcionan perfectamente en entorno de desarrollo pero no en prod?
he de decir que la ruta se encuentra en el routing.yml del Bundle no en el principal.
Gracias
Hola, estoy tratando de hacer este curso.. pero tengo una duda.. por que en una parte utilizan MDWDemoBundle:Default:index y en otras MDWDemoBundle:Blog:index, page: 1, esto quiere decier que debo crear un controlador BlogController.php o trabajo en DemoBundle? y como deberia configurar el archivo routing.yml..(C:\xampp\htdocs\Symfony\src\MDW\DemoBundle\Resources\config) para que lea cual el Demo o el Blog?.. a mi me sale el siguiente error cuanod trato de dar la siguiente url articulos/es/2000/patron_mvc.html,
Error Cannot import resource “C:\xampp\htdocs\Symfony\src\MDW\DemoBundle/Resources/config/routing.yml” from “C:\xampp\htdocs\Symfony\app/config\routing.yml”
Por favor puden decir que estoy haciendo mal, la verdad no me es claro como configuro la parte del blog?
a espera de la respuesta.. gracias
Se utilizó el DefaultController para parte del manual debido a que es el que crea Sf2 por defecto, y se utiliza el BlogController para darle más semántica a la explicación en esta parte del artículo, en realidad el objeto de esto es introducir el concepto con pequeños ejemplos prácticos, no una aplicación 100% funcional.
Con respecto al error que indicas me parece que tienes un error de sintaxis en el routing.yml del Bundle, recuerda que un Bundle puede tener N controllers, pero las rutas hacia ambos se declaran en el mismo routing.yml, revisa bien la sintaxis del yml, recuerda que dicho formato solo acepta espacios en blanco y debes de configurar tu editor de texto para que no utilice TAB’s.
Recuerda que para el entorno de producción debes de borrar la cache de Symfony
~$ php app/console cache:clear
O borrar manualmente el directorio prod en el de cache.
Gracias Maycol,
Yo utilizaba el comando pero hasta que no borre manualmente el directorio no funciono.
Muchas gracias
Hola Maycol cómo va?
Te escribo con referencia a tu comentario (No. 17) de este post.
Quería preguntarte si es que los complementos para generar slugs que mencionas funcionan bien con caracteres especiales como ser vocales acentuadas, eñes, etc.
O sea que el slug correspondiente a “la estación del año” no sea “la-estacin-del-ao” sino “la-estacion-del-ano”, que no supriman caracteres bah!
Estoy armando un sitio sencillo que tiene una sección de productos gastronómicos que incluye un menú de comidas y quisiera utilizar los nombres de los productos como rutas en lugar de los ID’s
Es una web sencilla, no me quiero complicar demasiado con componentes e incluso tengo alguna función que obtuve de un generoso colega para generar slugs en español y con unas pocas líneas de código podría implementar esta funcionalidad.
Sin embargo, si estos componentes cumplen con el requisito que te he mencionado estaría dispuesto a utilizarlos.
Sin más, aprovecho para agradecerte por el excelente material que provees aquí y enviarte mis saludos.
Una vez más enhorabuena por el tutorial, esta es mi segunda lectura y cada vez veo más claro el tema, pero me gustaría (si puede ser), que se explicara un poco más en detalle que significa eso de “inyección de dependencias(DI)”. Gracias
Buen día,
la verdad hasta este capitulo iba de perlas, pero me perdi!
Mi pregunta es:
que es blog? otro bundle? en que momento lo crearon? como lo creo?
salte este capitulo sin entenderlo muy bien, pero en el siguiente quede peor. Ya que usan BlogController.php…..
agradezco mucho su ayuda y muchas gracias por tan valiosa información.
La guía no tiene como objetivo crear una aplicación completa, en algunos casos se uso un Bundle base para explicar unos conceptos, y en otros se uso BlogBundle por la semántica y facilidad que ofrece a los usuarios al entender la lógica de negocio simple de un blog, pero por lo general cada capítulo trata de seguir la pista del otro, y si no, inicia con términos y un Bundle desde 0, al final, el AcmeBundle y el BlogBundle representan la versatilidad modular de Symfony2, donde tu aplicación se segmenta por funcionalidad.
Es un patrón de diseño de Software “orientado al servicio” (SOA), es uno de los patrones más actuales y exitosos en el mercado de software, puede conseguir mucha más información en el manual de Symfony o en la red, saludos 😉
Lo que se ha explicado en este articulo permitiría por ejemplo acceder a “articulos” en vez de usar http://localhost/app_dev.php/articulos y ahora podría acceder desde http://localhost/articulos
¿esto es correcto? si es asi, no he logrado que me funcione.