lunes, 2 de septiembre de 2013

Introducción a Symfony 2

Symfony y Bundles

Un Bundle es un directorio con una estructura bien definida donde colocaremos los elementos de la arquitectura MVC de un proyecto Symfony 2. Podemos comparar a nivel de concepto los bundles con los plugins de Joomla (por ejemplo).
La primera idea que debe quedar clara, expresada de manera simplista, es que “todo es un bundle” en Symfony2. Por tanto, si queremos desarrollar una aplicación necesitaremos, por lo menos, tener un bundle para alojar el código de la misma. Gracias a este concepto, la distribución de nuestra aplicación o la utilización de funcionalidades de aplicaciones de terceros es muy sencilla.

Nota: También hay que tener en cuenta que la creación de un Bundle significa la creación de un espacio de nombres (enlace a tut. espacio de nombres). Que tendremos que tener en cuenta a la hora de ir creando la aplicación.

La estructura de un bundle 

La solución más utilizada para organizar el código de una aplicación web es mediante el patrón de diseño MVC. En pocas palabras, se pretende organizar el código de acuerdo a su naturaleza. Lo que significa que separaremos dicho código en tres capas:

1. La capa del modelo. Aquí definiremos la lógica de la aplicación (acceso a los datos y su manipulación). Lo que incluye la base de datos. Para ello Symfony 2 almacena todas las clases y ficheros relativos a la lógica en el directorio /Entity/ del bundle que forma la aplicación.

2. La vista es la parte con la que el usuario interactúa. En Symfony 2 la capa de la vista está formada principalmente por plantillas Twig. Dichas plantillas son almacenadas en el directorio /Resources/views dentro del bundle.
El directorio /Resources/ tiene especial importancia ya que ademas de contener las vista, tiene un subdirectorio llamado /Resources/config/ donde deberemos de añadir el fichero que 'mapeará' las URL's que reciba el servidor para llamar al controlador correspondiente: config.yml. En el apartado de enrutamiento se describirá con más profundidad.

3. El controlador es la parte del código que llama al modelo para solicitar información y muestra la vista al cliente, con dicha información. Los controladores se crearán en el subdirectorio /Controller/ de nuestro bundle.

A grandes rasgos, esta es la estructura básica de cualquier Bundle. Evidentemente no solo existen controladores, vistas y modelos de datos. Existen otros elementos como formularios, tests o datos de inicialización que tiene sus subdirectorios dentro de la estructura de un Bundle. Pero estos ya los veremos en posteriores tutoriales donde se mostrará la creación de una sencilla aplicación paso a paso.

Otros directorios de la estructura del bundle:

- /Datafixtures/: En él crearemos las clases encargadas para añadir datos iniciales a la aplicación.
- /Form/: Directorio donde crearemos los formularios.
- /Test/:  Directorio donde colocaremos los tests unitarios de la aplicación.
- /Resources/Public/: Directorio que contendrá los recursos web (imágenes, hojas de estilo, etc.) y será copiado o enlazado simbólicamente  con el directorio web/ del proyecto. Lo veremos en los siguiente tutoriales.

Crear nuestro Bundle

Simfony 2 proporciona scripts gracias  a cuales podremos crear de forma automática diferentes componentes de un proyecto. Una de estas herramientas nos evitará crear a mano cada uno de los directorios de la estructura de un Bundle. Además inicializará ciertas configuraciones necesarias (enrutamiento y registro del Bundle) y creará las plantillas para un controlador y una vista básica.

A continuación vamos a crear un Bundle cuyo espacio de nombres será Tarea/ListadoBundle. Además al comando le indicaremos el tipo de formato para los ficheros de configuración. Es aconsejable el formato YML para definir ficheros YAML. Aunque también podríamos utilizar XML o PHP para dichos ficheros de configuración.

Nota: es muy importante si se utiliza los ficheros YAML que las identaciones se deben de hacer con cuatro espacios y no usar el tabulador.

 php app/console generate:bundle --namespace=Tarea/ListadoBundle --format=yml  

Tendremos que completar una serie de cuestiones relativas al Bundle a crear. Si aceptamos el valor que sugiere cada una de las cuestiones (valor entre corchetes), simplemente presionamos Enter. Si no modificamos el valor (valor en negrita del siguiente ejemplo).

 Welcome to the Symfony2 bundle generator   

 In your code, a bundle is often referenced by its name. It can be the  
 concatenation of all namespace parts but it's really up to you to come  
 up with a unique name (a good practice is to start with the vendor name).  
 Based on the namespace, we suggest TareaListadoBundle.  

 Bundle name [TareaListadoBundle]:  

 The bundle can be generated anywhere. The suggested default directory uses  
 the standard conventions.  

 Target directory [/home/ivan/public_html/ListaTareasSymfony/src]:   

 To help you get started faster, the command can generate some  
 code snippets for you.  

 Do you want to generate the whole directory structure [no]? yes  

 You are going to generate a "Tarea\ListadoBundle\TareaListadoBundle" bundle  
 in "/home/ivan/public_html/ListaTareasSymfony/src/" using the "yml" format.  

 Do you confirm generation [yes]?   

 Bundle generation   

 Generating the bundle code: OK  
 Checking that the bundle is autoloaded: OK  
 Confirm automatic update of your Kernel [yes]?   
 Enabling the bundle inside the Kernel: OK  
 Confirm automatic update of the Routing [yes]?   
 Importing the bundle routing resource: OK  

 You can now start using the generated code!   

Tras esto se habrá creado el Bundle, quedando registrado en el fichero raiz_proyecto/app/AppKerne.php.

Estructura del Bundle:
Estructura de un Bundle Symfony 2
Sistema de enrutado

La última pregunta del cuestionario de creación del Bundle preguntaba si deseamos actualizar las rutas y evidentemente contestamos que sí. Con esto lo que hemos hecho es “enlazar” la tabla enrutamiento general de la aplicación con la tabla de enrutamiento particular del bundle. La tabla de enrutamiento es la responsable de indicar al framework como deben mapearse las URL’s en acciones PHP. O lo que es lo mismo, asociaremos patrones de rutas con los controladores encargados de realizar acciones.

Symfony carga todas las rutas de tu aplicación desde un archivo de configuración de enrutamiento: app/config/routing.yml. Normalmente este fichero es utilizado para importar los ficheros de configuración de los bundles. Aunque podríamos definir aquí directamente las rutas.

Cuando importas recursos desde archivos YAML, el valor que asignes como clave (tarea_listado) de la opción resource es indiferente, ya que no se utiliza para nada.

 tarea_listado:  
   resource: "@TareaListadoBundle/Resources/config/routing.yml"  
   prefix:  /  

La clave resource indica el recurso desde el que se deben cargar las rutas. En este ejemplo, este recurso es la ruta completa de un archivo del sistema, donde la cadena @TareaListadoBundle es un atajo que utiliza Symfony para interpretar la ruta hasta el directorio donde se encuentra ese Bundle. Simplemente une el nombre de los espacios de nombre o directorios.

Ahora vemos una entrada del fichero de configuración importado:

 homepage:  
   pattern: /  
   defaults: { _controller: TareaListadoBundle:Tarea:index }  
   requirements:  { _method: "GET" }  

El cual especifica que el controlador (Tarea) y su método (index) será el encargado de tratar las peticiones GET sobre la URI '/' (pattern). En posteriores tutoriales se profundizará más sobre el sistema de enrutamiento.

Con lo visto hasta ahora, la creación de aplicaciones web con Symfony2 involucra cuatro pasos:

1. Creación del Bundle que va a contener la estructura de la aplicación.
2. Creación de la ruta que mapea la URL de la página en una acción de algún controlador. Dicha ruta se registra en el archivo Resources/config/routing.yml del bundle, que a su vez debe estar correctamente importado en el archivo de rutas general de la aplicación app/config/routing.
3. Creación de dicha acción en el controlador correspondiente. La acción, haciendo uso del modelo, realizará las operaciones necesarias y obtendrá los datos crudos (raw), es decir sin ningún tipo de formato, que facilitará a una plantilla para ser renderizados. El código de los controladores debe ubicarse en el directorio Controllers del bundle.
4. Creación de dicha plantilla. Esto se hace en el directorio Resources/view. Con el fin de organizar bien las plantillas, es recomendable crear un directorio con el nombre de cada controlador. También es muy recomendable utilizar Twig como sistema de plantillas, aunque también se puede utilizar PHP.

Controladores frontales app.php y app_dev.php

Como en todo desarrollo web, es importante restringir a las páginas que serán directamente accesibles por el navegador. Por eso, Symfony solo permite el acceso desde el navegador al contenido del directorio /web/. Todo lo demás forma parte de la programación interna del proyecto. Y eso incluye a los componentes guardados dentro de /src/. Por lo tanto necesitamos algún mecanismo que esté dentro de /web/ y acceda a la parte interna del proyecto. Este mecanismo se llama controlador frontal.

Dentro de la carpeta \web\ vemos que existen dos archivos: “app.php” y “app_dev.php”. Estos archivos se llaman controladores frontales y son creados por el framework (son creados tras la instalación).  A través de ellos accederemos a nuestros componentes privados de /src/. La diferencia entre ambos es que Symfony maneja el concepto de entornos de trabajo. Simplificando, podemos decir que a través de ambos controladores podemos acceder a las mismas páginas pero con diferentes configuraciones. Existen dos entornos configurados por defecto en un proyecto Symfony 2: desarrollo y producción. Y el entorno de desarrollo proporciona las herramientas necesarias para depurar la aplicación.

Cualquier petición de página que llegue a la aplicación debe de ser sobre uno de nuestros controladores frontales. Por ejemplo:

http://mi_servidor/app.php
http://mi_servidor/app.php/insertar
http://mi_servidor/app.php/ver/4

O podríamos utilizar http://mi_servidor/app_dev.php/insertar para poder depurar algún error.

Nombres de rutas

Ya hemos visto que en Symfony 2, hasta ahora, todas las peticiones a la aplicación se realizan a través de un script PHP que se llama controlador frontal (app.php o app_dev.php). Este script “sabe” lo que debe devolver como respuesta al usuario “mirando” la ruta que lo acompaña en cada petición. Cada URL que llega a Symfony 2 consiste en un conjunto de parámetros separados por el carácter '/'. Es decir, los parámetros que siguen al controlador frontal y que indican la acción y los argumentos de la misma (dependiendo de la URL).
Esta forma de pasar parámetros a través de la URL mejora en varios aspectos a la clásica query string del tipo: ?param1=val1&param2=val2&...&paramN=valN

A)En primer lugar el usuario que utiliza el navegador “siente” que la URL que aparece en la barra de direcciones forma parte de la aplicación que está utilizando. Por tanto, cualquier URL llena de carácteres extraños y demasiado larga redunda en una degradación estética.
B)En segundo lugar y más allá de cuestiones estéticas, cuando utilizamos query strings clásicas estamos dando información innecesaria al usuario, ya que el nombre de los parámetros (paramX) es algo que tiene sentido únicamente para la aplicación en el servidor. Esta información extra, además de dar lugar a URL’s horribles, supone un problema de seguridad, ya que el usuario podría utilizarlas para sacar conclusiones acerca de la aplicación y utilizarla para comprometerla. 

Y ahora nos podemos preguntar: ¿Es posible que una aplicación Symfony 2 acepte URL's donde no se especifique el controlador frontal?. Y la respuesta es sí. Ya que Symfony 2 incluye reglas de reglas de reescritura para que podamos utilizar URL's sin necesidad de especificar dicho controlador. De esta manera, además de mejorar el estilo de la URL, ocultamos al usuario información acerca del lenguaje de programación que estamos utilizando en el servidor. Por lo tanto podríamos utiilzar las URL’s de este modo:

http://mi_servidor/
http://mi_servidor/insertar
http://mi_servidor/editar/4

Las reglas de reescritura están especificadas en el fichero .htaccess en el directorio web/ del proyecto. Básicamente indica al servidor que si le llega una URL donde no se especifica el controlador frontal, reescriba internamente dicha ruta anteponiendo dicho controlador de producción (app.php). Para que esto funcione es necesario que el servidor web tenga instalado el módulo Rewrite, y permita el cambio de directivas a través de ficheros .htaccess.

La reglas especificadas en el .htaccess son más complejas que las que vimos en el tutorial de introducción de reglas de reescritura. Sin embargo la regla que permite la reescritura con el controlador frontal (simplicada) se asemeja a una regla que ya vimos:

 <IfModule mod_rewrite.c>  
  RewriteEngine On  
  RewriteCond %{REQUEST_FILENAME} !-f  
  RewriteRule ^(.*)$ app.php [QSA,L]  
 </IfModule>  


Entradas relacionadas

Reglas de reescritura - Parte 1: Introducción
Reglas de reescritura - Parte 2: Directivas  
Reglas de reescritura - Parte 3: Ejemplos completos
Symfony 2: Instalación y configuración

No hay comentarios:

Publicar un comentario