Symfony

Framework PHP orientado a objetos

Creando páginas con Symfony 2

En el capítulo anterior hemos creado ya nuestro primer Bundle MDW\DemoBundle. Aquí crearemos todos los ejemplos para este manual y en este capítulo vamos a ver como crear las páginas con Symfony 2.

Pasos para crear nuestras páginas

Para crear un página tenemos que tener en cuenta tres pasos:

  1. Asignación de una ruta: Una dirección URL asignada a la página para que el controlador frontal la pueda acceder.
  2. Creación de una acción (action): La lógica necesaria para la página. Corresponde al Controlador en arquitectura MVC.
  3. Creación de la plantilla (template): La estructura de nuestra página. Corresponde a la Vista en arquitectura MVC.

Tomaremos el ejemplo que fue creado al generar nuestro MDWDemoBundle y lo estudiaremos para entender estos tres pasos.

1. Asignación de una ruta

Las rutas se refieren a la dirección URL que utilizará el controlador frontal para acceder a nuestra página. Dichas rutas se especifican en el archivo de configuración app/config/routing.yml. Este paso es sumamente importante ya que de lo contrario la página existirá pero no podrá ser accedida.

Dentro de este archivo podríamos crear las rutas directamente, pero para no mezclar las rutas de nuestro Bundle con las de otros, podemos crear las rutas en un archivo dentro de nuestra carpeta MDW\DemoBundle y de esta manera logramos independencia y portabilidad. Para hacer esto, tendremos que importar el archivo routing.yml de nuestro bundle dentro del app\config\routing.yml que básicamente es el archivo de rutas genérico para todo el proyecto.

Al crear nuestro Bundle con el script “console”, en el paso 7 explicado en el capítulo anterior es justamente lo que se hace automáticamente agregando el siguiente código de importación en el archivo app\config\routing.yml:

MDWDemoBundle:
  resource: "@MDWDemoBundle/Resources/config/routing.yml"
  prefix: /

La primera línea es simplemente un texto identificador para la importación, que por convención podríamos usar el mismo identificador de nuestro Bundle. Abajo, con espacios en blanco definimos la clave “resource” que apunta a un archivo externo y haciendo uso de nuestro identificador @MDWDemoBundle que apunta a src\MDW\DemoBundle, le decimos que use el archivo ubicado en nuestra carpeta /Resources/config/routing.yml.

La segunda clave a definir es el “prefix” que indica con / que a partir del controlador frontal se crearán nuestras rutas.

Nota

Si no conoces la forma de uso de los archivos YAML puedes ver un poco de información aquí.

Una vez que tenemos ya nuestro archivo importado lo abriremos y veremos el siguiente contenido de ejemplo que se creó al generar nuestro Bundle con el generador de Symfony:

MDWDemoBundle_homepage:
  pattern: /hello/{name}
  defaults: { _controller: MDWDemoBundle:Default:index }

El primer texto es nuevamente un texto identificador para esta ruta. Los identificadores no pueden repetirse con ninguna otra ruta del proyecto, en nuestro Bundle o en cualquier otro.

Abajo, en lugar de usar la clave resource para importar un archivo, definimos el “pattern” (patrón) que indica la dirección URL a usar para esta ruta. Dentro de una ruta cuando usamos llaves {name}, indicamos que será un parámetro. Como la ruta indica la dirección que el Controlador Frontal utilizará, estamos diciendo que podremos acceder a la página escribiendo http://localhost/Symfony/web/app_dev.php/hello/Jhon donde:

  • http://localhost: Dirección del servidor.
  • /app_dev.php: corresponde al controlador frontal, que podríamos utilizar el de desarrollo o producción.
  • Finalmente /hello/Jhon: indica la ruta que acabamos de crear, donde {name} lo podremos reemplazar por el valor del parámetro que queramos.

La segunda clave obligatoria es “defaults” que utilizando llaves simulamos un array asociativo por lo que la clave “_controller” indica cual será el controlador que contendrá la lógica de la página. Para no escribir la ruta completa del archivo (\src\MDW\DemoBundle\Controller\DefaultController.php) utilizamos una forma abreviada o “dirección lógica” que está compuesta de tres partes: IdentificadorDelBundle:Controller:Action

  1. IdentificadorDelBundle: En este caso nuestro identificador es MDWDemolBundle.
  2. Controller: El nombre de la clase que contendrá los actions (acciones). Estas clases se encuentran en la carpeta “Controller” de nuestros Bundles.
  3. Action: Representado por un método de la clase arriba mencionada. Este método contendrá la lógica de negocios para nuestra página y se ejecutará antes de mostrar la página.

Entendiendo los pasos para crear nuestras páginas, vemos que nuestra ruta de ejemplo apunta a MDWDemoBundle:Default:index, lo que indica que la acción a ejecutarse al ingresar a nuestra ruta se encuentra en MDWDemoBundle en una clase DefaultController programado en un método indexAction.

Nota: Hablaremos más sobre el sistema de rutas de Symfony en el capítulo 4

2. Creación de un controlador

Así como vimos en la sección anterior, una ruta apunta a un controlador usando la clave defaults

defaults: { _controller: MDWDemoBundle:Default:index }

Si abrimos el archivo mencionado veremos lo siguiente:

//-- \src\MDW\DemoBundle\Controller\DefaultController.php
public function indexAction($name)
{
    return $this->render('MDWDemoBundle:Default:index.html.twig', array('name' => $name));
}

Vemos que nuestro método recibe el parámetro $name que debe coincidir con el escrito en nuestra ruta /hello/{name}.

No hay lógica para esta página ya que es un simple ejemplo, por lo que simplemente termina haciendo un return del resultado de un método render() que se encarga de llamar a la plantilla (paso siguiente) y pasarle datos por medio del segundo argumento, un array asociativo. En caso de que no necesitemos enviar variables a la vista simplemente enviamos un array vacío.

Como primer argumento del método render(), enviamos el “nombre lógico” del template MDWDemoBundle:Default:index.html.twig que indica donde está la plantilla. Las plantillas se encuentran organizadas dentro de la carpeta “Resources\views” de nuestros Bundles, en este caso src\MDW\DemoBundle\Resources\views\Default\index.html.twig.

3. Creación de la plantilla

Para la plantilla estamos utilizando el framework Twig y si abrimos el archivo mencionado vemos que simplemente utilizamos la variable $name como si existiera, esto lo podemos hacer porque al momento de llamar a la plantilla desde el controlador enviamos esta variable para que exista mágicamente usando el método render(): array(‘name’ => $name)

Si abrimos el archivo src\MDW\DemoBundle\Resources\views\Default\index.html.twig vemos que solo contiene como ejemplo: Hello {{ name }}!

Como habíamos hablado en el capítulo 1, Twig permite separar el código PHP del HTML por lo que por ejemplo en lugar de escribir:

Hello <?php echo htmlentities($name) ?>!

podemos simplemente poner:

Hello {{ name }}!

donde {{ $var }} significa que la variable que este dentro será impresa como si utilizaramos un echo.

Creemos nuestra primera página de ejemplo

Siguiendo las mismas instrucciones vistas en los puntos anteriores, crearemos una página de ejemplo para mostrar un listado de artículos de un blog en una tabla. Supondremos que los artículos son extraídos de una base de datos pero como todavía no hemos llegado a hablar de Doctrine los obtendremos de un array.

Ejemplo 1

Lo primero que tenemos que pensar es una dirección URL para acceder a la página, luego crearemos el action que se procesará al ejecutarse la petición de la URL y finalmente usaremos los datos devueltos por nuestro action dentro del template para mostrar la tabla de artículos.

Paso 1

Dentro del archivo src\MDW\DemoBundle\Resources\config\routing.yml de nuestro Bundle de ejemplo crearemos la ruta correspondiente agregando el siguiente código:

articulos:
  pattern: /articulos
  defaults: { _controller: MDWDemoBundle:Default:articulos }

Como habíamos mencionado la primera línea corresponde al identificador de la ruta al que llamaremos “articulos”. Este nombre será usado para mostrar los links a nuestras páginas pero esto lo veremos con más detalles más adelante.

A continuación definimos el pattern que será lo que agregaremos a la dirección del controlador frontal. Para este caso definimos que si nuestra dirección de acceso al controlador frontal es “http://localhost/Symfony/web/app_dev.php” agregaremos “/articulos” para acceder a nuestra página teniendo como URL: http://localhost/Symfony/web/app_dev.php/articulos.

Por último definimos el action que se ejecutará al llamar a esta ruta: MDWDemoBundle:Default:articulos lo que apuntaría al método articulosAction() de la clase DefaultController.php que existe dentro de nuestro MDWDemoBundle.

Paso 2

Ahora que ya tenemos nuestra ruta apuntando a nuestro action nos encargaremos de crear el método correspondiente que será ejecutado y que contendrá la lógica del negocio, que para este caso es muy simple. Dentro de nuestra clase \src\MDW\DemoBundle\Controller\DefaultController.php agregaremos el método (action) correspondiente que deberá llamarse articulosAction():

public function articulosAction()
{
    //-- Simulamos obtener los datos de la base de datos cargando los artículos a un array
    $articulos = array(
        array('id' => 1, 'title' => 'Articulo numero 1', 'created' => '2011-01-01'),
        array('id' => 2, 'title' => 'Articulo numero 2', 'created' => '2011-01-01'),
        array('id' => 3, 'title' => 'Articulo numero 3', 'created' => '2011-01-01'),
    );
    return $this->render('MDWDemoBundle:Default:articulos.html.twig', array('articulos' => $articulos));
}

Una vez que tenemos los datos dentro de nuestro array, por medio del método ->render() llamamos a nuestro template con el primer argumento y con el segundo pasamos los datos que deberán existir dentro del mismo.

Paso 3

El último paso será usar la información que nuestro action nos provee para generar nuestra vista y mostrarla al usuario. Para esto, crearemos un archivo dentro de la carpeta \Resources\views\Default de nuestro bundle con el nombre articulos.html.twig y con la ayuda de Twig recorreremos nuestro array de artículos para mostrar nuestra tabla de una manera muy sencilla:

<h1>Listado de Articulos</h1>
<table border="1">
    <tr>
        <th>ID</th>
        <th>Titulo</th>
        <th>Fecha de Creacion</th>
    </tr>
    {% for articulo in articulos %}
    <tr>
        <td>{{articulo.id}}</td>
        <td>{{articulo.title}}</td>
        <td>{{articulo.created}}</td>
    </tr>
    {% endfor %}
</table>

Twig nos provee mucha habilidad para manipular los datos sin escribir código PHP pudiendo acceder a las claves de nuestro array por medio de articulo.id o articulo['id'] indistintamente.

Con esto ya tenemos una tabla que muestra artículos haciéndolo en tres pasos bien concisos y donde cada uno tiene su responsabilidad. Para ingresar a la página podemos escribir esta URL: http://localhost/Symfony/web/app_dev.php/articulos

Ejemplo 2

Ahora que ya hemos visto como mostrar los datos de nuestro array supongamos que queremos otra página que reciba como parámetro GET un id de artículo y nos muestre sus datos. Para esto nuevamente sigamos los mismo pasos:

Paso 1

Para este caso crearemos una ruta llamada “articulo” que recibirá un parámetro {id} y hará que se ejecute el action MDWDemoBundle:Default:articulo

articulo:
  pattern: /articulo/{id}
  defaults: { _controller: MDWDemoBundle:Default:articulo }

Paso 2

Para simular la base de datos volveremos a tener nuestro array y buscaremos el id recibido. Como recibimos un parámetro GET podemos recibirlo directamente como argumento de nuestro método:

public function articuloAction($id)
{
    //-- Simulamos obtener los datos de la base de datos cargando los artículos a un array
    $articulos = array(
        array('id' => 1, 'title' => 'Articulo numero 1', 'created' => '2011-01-01'),
        array('id' => 2, 'title' => 'Articulo numero 2', 'created' => '2011-01-01'),
        array('id' => 3, 'title' => 'Articulo numero 3', 'created' => '2011-01-01'),
    );

    //-- Buscamos dentro del array el ID solicitado
    $articuloSeleccionado = null;
    foreach($articulos as $articulo)
    {
        if($articulo['id'] == $id)
        {
            $articuloSeleccionado = $articulo;
            break;
        }
    }

    //-- Invocamos a nuestra nueva plantilla, pasando los datos
    return $this->render('MDWDemoBundle:Default:articulo.html.twig', array('articulo' => $articuloSeleccionado));
 }

Paso 3

Por último mostramos los datos de nuestro artículo devuelto por nuestro controlador:

<h1>Articulo con ID {{articulo.id}}</h1>
<ul>
    <li>Titulo: {{articulo.title}}</li>
    <li>Fecha de creacion: {{articulo.created}}</li>
</ul>

Para acceder a este ejemplo podemos escribir la URL: http://localhost/Symfony/web/app_dev.php/articulo/1. Donde el parámetro “1″ sería el id del artículo que queremos ver.

Resumen Final

En este capítulo hemos visto los tres pasos básicos para crear nuestras páginas y hemos llegado a la conclusión de que primeramente se accede a una URL definida por nuestras rutas en el archivo routing.yml, luego el sistema de ruteo deriva la invocación a un método de un controlador llamado action en donde se procesan los datos y se llama a la vista pasándole como variables los datos que necesitan ser mostrados. Una vez en la vista usaremos el framework Twig para facilitar la visualización de la información.

En los siguientes 3 capítulos hablaremos un poco más detalladamente sobre la potencia del sistema de ruteo de Symfony2 y del framework Twig.

Siguiente capítulo: Sistema de Routing

Juan ArdissoneJuan Ardissone para Maestros del Web.
Agrega tu comentario | Enlace permanente al artículo

Síguenos en: Twitter @maestros | Facebook Fan page

33 comentarios

Comentarios

  1. Ezequiel

    Tablas ?, me parecio ver un TD, TR, aun se usan las tablas ?

    Responder
    1. Porsupuesto que se siguen utilizando, pero para lo que son realmente concebidas: “tabular datos”, lo que no debe hacerse nunca es utilizarlas para el diseño (layout) de una web, pero es un elemento fundamental en cuanto a representación de datos se refiere.

  2. Andresdzphp

    Hola Juan Ardissone, se entiende perfectamente el curso. Muchas gracias.

    Saludos.

    Responder
  3. Excelente capitulo.

    Me estaba confundiendo un poco con los terminos como Bundle, pero creo que ya va agarrando forma y es sencillo.

    Gracias.

    Responder
    1. Ricardo, quizás el concepto más complicado de Symfony2 es el Bundle y más si vienes de trabajar con la rama 1.x donde no existían. Pero una vez que lo entiendes te da una organización muy interesante :-) Me alegro que lo vayas entendiendo.

    2. @HaroldSOS

      YO Tambien estaba Confundiendome Bastante con esos Bundles pero este cap me desenrrollo Bastante :D

  4. Carlos

    ¿Porqué si en el array del ejemplo 1 la columna titulo me sale en blanco, si en vez de colocar “Articulo numero 1″, le pongo las tildes “Artículo número 1″?

    Responder
    1. ¿de que codificación son tus archivos?, por lo general debes utilizar un editor que los almacene como UTF-8 sin BOM, tales como NetBeans, Notepad++, entre otros

    2. Carlos

      Ese era el problema, gracias.

  5. Felicitaciones por el articulo, me sirve bastante.

    Responder
  6. Mary Iliana

    Sigo ansiosa por continuar, Es la Primera vez que uso un Framework. Y llevo el contenido realizado 100%. Gracias por tu colaboración.

    Responder
  7. juan salazar

    100% practico, todo va tomando forma…gracias por dedicarnos tu tiempo y experiencia…@okawaip

    Responder
  8. voy bien con el tutorial, pero queria saber si hay algun buen tutorial en español de Twig, quiero usarlo no necesariamente con symfony

    Responder
    1. Fredy había un proyecto llevado a cabo por @esymfony, quien se puso a traducir la guía oficial de symfony y tengo entendido que también lo ha hecho con Twig. El sitio es http://udelabs.com/symfony pero ahora mismo está abajo y lo están levantando según lo último que mire.

    2. De hecho el proyecto sigue, pero con menos continuidad, he aquí el enlace a Nacho Pacheco: http://gitnacho.github.com/symfony-docs-es/index.html y los últimos PDF que puede descargas los encuentras en la sección de descargas de mi site: http://maycolalvarez.com/downloads, espero te sirva de ayuda ;-)

  9. Oscar Miguel Amezcua Estrella

    Cada vez se pone mas bueno ya quiero llegar a la parte de los formularios jejeje sale gracias por los articulos de Symfony2 estan muy buenos

    Responder
  10. Cesar Valdez

    Hola Juan, estoy empezando con el curso y está muy interesante, pero tengo un problema, todavía no me queda claro eso de “Asignación de ruta”(específicamente a la hora de importar) y no puedo ver los resultados del ejemplo 1, me lanza este error:

    “Cannot import resource “C:\wamp\www\Symfony\app/config\routing.yml” from “C:\wamp\www\Symfony\app/config/routing_dev.yml”.
    500 Internal Server Error – FileLoaderLoadException
    1 linked Exception: ParseException »”

    Te pido ayuda y gracias de antemano, saludos desde El Salvador

    Responder
    1. Cesar, los siguientes capítulos son justamente sobre routing y ahí te ayudará a entender más en profundidad.
      Con respecto al error es raro porque el archivo routing_dev.yml es importado por el routing.yml desde un principio. Fijate si no tienes tabulaciones dentro del archivo YML. Los archivos YML deben contener solo espacios no tabulaciones y las lineas vacías generadas por los enters deben quedar vacías

  11. Gracias Juan por tu desinteresado trabajo, estoy siguiendo al pie de la letra tu manual. Tengo el mismo problema que César del Salvador con el ejercicio1, ya revise lo de las tabulaciones, pero nada..me arroja:

    ErrorException: Catchable Fatal Error: Argument 1 passed to Symfony\Component\Routing\Loader\YamlFileLoader::normalizeRouteConfig() must be an array, null given, called in C:\Apache\htdocs\Symfony\vendor\symfony\src\Symfony\Component\Routing\Loader\YamlFileLoader.php on line 65 and defined in C:\Apache\htdocs\Symfony\vendor\symfony\src\Symfony\Component\Routing\Loader\YamlFileLoader.php line 129

    Si tienes tiempo, agradezco alguna pista…Gracias

    From Colombia..

    Responder
  12. Hola Juan,

    Ya encontréla falla, tu escribiste en el archivo Router:

    articulos:
    pattern: /articulos
    defaults: { _controller: MDWDemoBundle:Default:articulos }

    Esa primera palabra articulos: no la reconoce como palabra clave para este tipo de archivo, si la quitas y dejas solo:

    pattern: /articulos
    defaults: { _controller: MDWDemoBundle:Default:articulos }

    Funciona…..

    From Colombia.

    Responder
  13. Excelente tutorial,
    No tengo ni idea de frameworks y he decidido conocer Symfony, pues dicen que es de los mejores.

    Espero poder seguir el tutorial hasta el final.

    Muchas gracias Juan.
    Un saludo.

    Responder
  14. Franco Jesus Mamani Pozo

    Excelente tutorial, es el mejor tutorial que vi hasta ahora, mis felicitaciones, Symfony2 es el primer framework que uso y me encanta!!! :D

    Responder
  15. Andre

    Estoy aprendiendo gracias ha este gran tutorial, igual tambien me estaba condundiendo con los bundles pero solo es cuestion de adaptarse, gracias por el esfuerzo, tengo una pregunta sobre symfony2 solo curiosidad si tengo una tabla en mi base de datos con symfony puedo implementar un modulo de administrador insert, edit , delete ? digo sin la necesidad de yo hacer codigo? o si entiendo bien ya habra un bundle para eso? muchas gracias por atencion saludos.

    Responder
    1. Hola Andre, tienes un task con el comando console que te crea un CRUD base para las tablas que le pidas (generate:doctrine:crud)

  16. Ricardo

    Hola Juan Ardissone, gracias por tu trabajo, te cuento que estaba aprendiendo Symfony 1.4 siguiendo la practica de 24 capitulos creado por la propia empresa y la curva de aprendizaje es bastante alta, estudie hasta el capitulo 12 y me confundia mucho con las configuraciónes y el monton de archivos que habia que manejar. Lo bueno de ese aprendizaje fue que me permitio ver mejor el cambio entre las dos versiones y enfocarme en Symfony 2 que es mas facil de aprender y de realizar el trabajo. Ademas el manejo de las vista es mucho mas facil con TWIG!

    De nuevo agradecerte el aporte que estas realizando!

    Responder
    1. Ricardo así mismo el manual de Jobeet es muy interesante para la práctica pero siempre mi recomendación es ver primero la guía y luego el Jobeet porque según ya vi la gente suele confundirse.

      Me alegro que te sirva :-)

  17. panozo

    Muy bueno el tutorial
    Podrian indicarme el ejemplo 2, me perdi. estas son mis dudas.
    en el paso 1: se vuelve a utilizar como en el ejemplo uno el archivo src\MDW\DemoBundle\Resources\config\routing.yml.
    paso 2: en la clase \src\MDW\DemoBundle\Controller\DefaultController.php se agregan los datos.
    paso 3: En el ejemplo1 se creo un archivo con el nombre de articulos.html.twig, en el ejemplo 2 tenemos que crear otro archivo o los datos adjuntamos en articulos.html.twig del ejemplo 1.
    Con las disculpas del caso podrian indicarme como solucionar el ejemplo 2.

    Saludos y Gracias

    Responder
    1. panozo no estoy entendiendo bien cual es el problema que tienes pero para aclarar ambos ejemplos

      Tanto en el 1 como en el 2 se siguen los tres pasos
      1. Agregar una ruta al archivo routing.yml
      2. Crear un método nuevo (action) dentro del controller
      3. Crear la página HTML o sea la vista

      En el primer ejemplo se crea una página que lista articulos y el segundo ejemplo nuestra UN artículo dependiendo del id que se envíe por parámetro. Por eso la primera página se llama articulos.html.twig en plural y la segunda articulo.html.twig en singular.

      Espero haberlo aclarado más

  18. Bernabe

    Estimados, estoy siguiendo el curso capitulo por capitulo, solo quiero felicitarlos por este material invaluable, claro, preciso y tan bien organizado que ponen a disposicion de los que nos estamos acercando a este framework. Sinceramente hace muchos años que no toco PHP y estuve leyendo (o intentando leer) toda la documentacion oficial de Symfony y termine perdido como perro en cancha de bochas… Por suerte encontre este tutorial!! Muchas gracias y sigan asi!!

    Responder
  19. zer0ve

    Excelente. Esta todo perfectamente explicado. Saludos.

    Responder
  20. Nathalie

    Antes que nada, un millón de gracias por este trabajo, eres muy buen pedagogo, yo estoy comenzando a trabajar con este framework y me estas ayudando muchisimo, gracias, gracias, gracias y un muy feliz día

    Responder
  21. juan

    Excelente. Esta todo muy claro

    Responder

Deja tu Comentario

Maestros del Web se reserva el derecho de moderación de los comentarios. Evita utilizar palabras soeces, ataques directos, descalificativos, insultos, de lo contrario tu comentario será eliminado.