Symfony

RECU-0263 (Recurso Referencia)

Descripción

Symfony es un framework cuyo principal objetivo es simplificar el desarrollo de aplicaciones en PHP mediante la automatización de algunos de los patrones utilizados para resolver las tareas comunes. Dado la normalización y estructuración que introduce el framework en el desarrollo, una de las ventajas que rápidamente se observan es un aumento en código más legible y más fácil de mantener. Por último, un framework facilita la programación de aplicaciones, ya que encapsula operaciones complejas en instrucciones sencillas.

Con este framework, es posible optimizar el desarrollo de aplicaciones web. Permite la separación de la lógica de negocio y la lógica del servidor, asi como la capa de presentación de la aplicación. Symfony aporta diversas herramientas y clases con el ojbetivo de reducir el tiempo de desarrollo de una aplicación web compleja. Proporciona automatismos para las tareas más comunes, permitiendo al desarrollador dedicarse por completo a los aspectos específicos de cada aplicación.

Symfony está desarrollado completamente con PHP 5. Ha sido probado en numerosos proyectos reales y se utiliza en sitios web de comercio electrónico de primer nivel. Symfony es compatible con la mayoría de gestores de bases de datos, como MySQL, PostgreSQL, Oracle y SQL Server de Microsoft. Se puede ejecutar tanto en plataformas nix (Unix, Linux, etc.) como en plataformas Windows. A continuación se muestran algunas de sus características. Symfony se diseñó para que se ajustara a los siguientes requisitos:

  • Tiene un proceso de instalación y configuración bastante sencillo
  • No tiene dependencias con un gestor de base de datos determinado.
  • Es muy adaptable a los caso mas complejos de negocio
  • Basado en la premisa de "convenir en vez de configurar", en la que el desarrollador solo debe configurar aquello que no es convencional
  • Sigue la mayoría de mejores prácticas y patrones de diseño para la web
  • Estructura el código de manera que resulta fácil de leer ya que incluye comentarios de phpDocumentor, lo que mejora de forma sensible, el mantenimiento del código
  • Fácil de extender, lo que permite su integración con librerías desarrolladas por terceros

La implementación del MVC que realiza Symfony

Piense por un momento cuántos componentes se necesitarían para realizar una página sencilla que muestre un listado de las entradas o artículos de un blog. Son necesarios los siguientes componentes:

  • La capa del Modelo
    • Abstracción de la base de datos
    • Acceso a los datos
  • La capa de la Vista
    • Vista
    • Plantilla
    • Layout
  • La capa del Controlador
    • Controlador frontal
    • Acción

En total son siete scripts, lo que parecen muchos archivos para abrir y modificar cada vez que se crea una página. Afortunadamente, Symfony simplifica este proceso. Symfony toma lo mejor de la arquitectura MVC y la implementa de forma que el desarrollo de aplicaciones sea rápido y sencillo.

En primer lugar, el controlador frontal y el layout son comunes para todas las acciones de la aplicación. Se pueden tener varios controladores y varios layouts, pero solamente es obligatorio tener uno de cada. El controlador frontal es un componente que sólo tiene código relativo al MVC, por lo que no es necesario crear uno, ya que Symfony lo genera de forma automática.

La otra buena noticia es que las clases de la capa del modelo también se generan automáticamente, en función de la estructura de datos de la aplicación. La librería Propel se encarga de esta generación automática, ya que crea el esqueleto o estructura básica de las clases y genera automáticamente el código necesario. Cuando Propel encuentra restricciones de claves foráneas (o externas) o cuando encuentra datos de tipo fecha, crea métodos especiales para acceder y modificar esos datos, por lo que la manipulación de datos se convierte en algo ams sencillo.

La abstracción de la base de datos es completamente transparente para el programador, ya que se realiza de forma nativa mediante PDO (PHP Data Objects). Así, si se cambia el sistema gestor de bases de datos en cualquier momento, no se debe reescribir ni una línea de código, ya que tan sólo es necesario modificar un parámetro en un archivo de configuración.

Por último, la lógica de la vista se puede transformar en un archivo de configuración sencillo, sin necesidad de programarla.

El Controlador

En Symfony, la capa del controlador, que contiene el código que liga la lógica de negocio con la presentación, está dividida en varios componentes que se utilizan para diversos propósitos:

  • El controlador frontal es el único punto de entrada a la aplicación. Carga la configuración y determina la acción a ejecutarse.
  • Las acciones contienen la lógica de la aplicación. Verifican la integridad de las peticiones y preparan los datos requeridos por la capa de presentación.
  • Los objetos request, response y session dan acceso a los parámetros de la petición, las cabeceras de las respuestas y a los datos persistentes del usuario. Se utilizan muy a menudo en la capa del controlador.
  • Los filtros son trozos de código ejecutados para cada petición, antes o después de una acción. Por ejemplo, los filtros de seguridad y validación son comúnmente utilizados en aplicaciones web. Puedes extender el framework creando tus propios filtros.

El Controlador Frontal

Todas las peticiones web son manejadas por un solo controlador frontal, que es el punto de entrada único de toda la aplicación en un entorno determinado. Cuando el controlador frontal recibe una petición, utiliza el sistema de enrutamiento para asociar el nombre de una acción y el nombre de un módulo con la URL escrita (o pinchada) por el usuario.

Si no estás interesado en los mecanismos internos de Symfony, eso es todo que necesitas saber sobre el controlador frontal. Es un componente imprescindible de la arquitectura MVC de Symfony, pero raramente necesitarás cambiarlo.

El Trabajo del Controlador Frontal en Detalle

El controlador frontal se encarga de despachar las peticiones, lo que implica algo más que detectar la acción que se ejecuta. De hecho, ejecuta el código común a todas las acciones, incluyendo:

  1. Carga la clase de configuración del proyecto y las librerías de Symfony.
  2. Crea la configuración de la aplicación y el contexto de Symfony.
  3. Carga e inicializa las clases del núcleo del framework.
  4. Carga la configuración.
  5. Decodifica la URL de la petición para determinar la acción a ejecutar y los parámetros de la petición.
  6. Si la acción no existe, redireccionará a la acción del error 404.
  7. Activa los filtros (por ejemplo, si la petición necesita autenticación).
  8. Ejecuta los filtros, primera pasada.
  9. Ejecuta la acción y produce la vista.
  10. Ejecuta los filtros, segunda pasada.
  11. Muestra la respuesta.
El Controlador Frontal por defecto

El controlador frontal por defecto, llamado index.php y ubicado en el directorio web/ del proyecto, es un simple script,

<?php
require_once(dirname(__FILE__).'/../config/ProjectConfiguration.class.php');
$configuration = ProjectConfiguration::getApplicationConfiguration('frontend', 'prod',
false);
sfContext::createInstance($configuration)->dispatch();

El controlador frontal incluye la configuración de la aplicación. La llamada al método dispatch() del objeto sfController (que es el controlador principal de la arquitectura MVC de Symfony) despacha la petición

Acciones

Las acciones son el corazón de la aplicación, puesto que contienen toda la lógica de la aplicación. Las acciones utilizan el modelo y definen variables para la vista. Cuando se realiza una petición web en una aplicación Symfony, la URL define una acción y los parámetros de la petición.

La clase de la acción

Las acciones son métodos con el nombre executeNombreAccion de una clase llamada nombreModuloActions que hereda de la clase sfActions y se encuentran agrupadas por módulos. La clase que representa las acciones de un módulo se encuentra en el archivo actions.class.php, en el directorio actions/ del módulo. Se muestra un ejemplo de un archivo actions.class.php con una única acción index para todo el módulo mimodulo. Ejemplo de la clase de la acción

class mimoduloActions extends sfActions
{
public function executeIndex()
{
// ...
}
}
Obteniendo Información en las Acciones

Las clases de las acciones ofrecen un método para acceder a la información relacionada con el controlador y los objetos del núcleo de Symfony. Se muestra como utilizarlos.

class mimoduloActions extends sfActions
{
public function executeIndex($peticion)
{
// Obteniendo parametros de la petición
$password = $peticion->getParameter('password');
// Obteniendo información del controlador
$nombreModulo = $this->getModuleName();
$nombreAccion = $this->getActionName();
// Obteniendo objetos del núcleo del framework
$sesionUsuario = $this->getUser();
$respuesta = $this->getResponse();
$controlador = $this->getController();
$contexto = $this->getContext();
// Creando variables de la acción para pasar información a la plantilla
$this->setVar('parametro', 'valor');
$this->parametro = 'valor'; // Versión corta.
}
}
El "singleton" del contexto

En el controlador frontal ya se ha visto una llamada a sfContext::createInstance(). En una acción, el método getContext() devuelve el mismo singleton. Se trata de un objeto muy útil que guarda una referencia a todos los objetos del núcleo de Symfony relacionados con una petición dada, y ofrece un método accesor para cada uno de ellos:

  • sfController: El objeto controlador (->getController())
  • sfRequest: El objeto de la petición (->getRequest())
  • sfResponse: El objeto de la respuesta (->getResponse())
  • sfUser: El objeto de la sesión del usuario (->getUser())
  • sfDatabaseConnection: La conexión a la base de datos (->getDatabaseConnection())
  • sfLogger: El objeto para los logs (->getLogger())
  • sfI18N: El objeto de internacionalización (->getI18N())

Se puede llamar al singleton sfContext::getInstance() desde cualquier parte del código.

Terminación de las Acciones

Existen varias alternativas posibles cuando se termina la ejecución de una acción. El valor retornado por el método de la acción determina como será producida la vista. Para especificar la plantilla que se utiliza al mostrar el resultado de la acción, se emplean las constantes de la clase sfView.

Si existe una vista por defecto que se debe llamar (este es el caso más común), la acción debería terminar de la siguiente manera:

return sfView::SUCCESS;

Symfony buscará entonces una plantilla llamada nombreAccionSuccess.php. Este comportamiento se ha definido como el comportamiento por defecto, por lo que si omites la sentencia return en el método de la acción, Symfony también buscará una plantilla llamada nombreAccionSuccess.php. Las acciones vacías también siguen este comportamiento.

Para utilizar una vista personalizada, se debe utilizar el siguiente valor de retorno:

return 'MiResultado';

Symfony entonces buscará una plantilla llamada nombreAccionMiResultado.php. Si no se utiliza ninguna vista (por ejemplo, en el caso de una acción ejecutada en un archivo de lotes) la acción debe terminar de la siguiente forma:

return sfView::NONE;

Sesiones de Usuario

Symfony maneja automáticamente las sesiones del usuario y es capaz de almacenar datos de forma persistente entre peticiones. Utiliza el mecanismo de manejo de sesiones incluido en PHP y lo mejora para hacerlo mas configurable y más fácil de usar.

Accediendo a la Sesión de Usuario

El objeto sesión del usuario actual se accede en la acción con el método getUser(), que es una instancia de la clase sfUser. Esta clase dispone de un contenedor de parámetros que permite guardar cualquier atributo del usuario en el. Esta información estará disponible en otras peticiones hasta terminar la sesión del usuario, como se muestra en el Listado 6-15. Los atributos de usuarios pueden guardar cualquier tipo de información (cadenas de texto, arrays y arrays asociativos). Se pueden utilizar para cualquier usuario, incluso si ese usuario no se ha identificado.

class mimoduloActions extends sfActions
{
public function executePrimeraPagina($peticion)
{
$nombre = $peticion->getParameter('nombre');
// Guardar información en la sesión del usuario
$this->getUser()->setAttribute('nombre', $nombre);
}
public function executeSegundaPagina()
{
// Obtener información de la sesión del usuario con un valor por defecto
$nombre = $this->getUser()->getAttribute('nombre', 'Anónimo');
}
}

Cuidado Puedes guardar objetos en la sesión del usuario, pero no se recomienda hacerlo. El motivo es que el objeto de la sesión se serializa entre una petición y otra. Cuando la sesión se deserializa, la clase del objeto guardado debe haber sido previamente cargada y este no es siempre el caso. Además, puede haber objetos de tipo "stalled" si se guardan objetos de Propel.

Como muchos otros getters en Symfony, el método getAttribute() acepta un segundo parámetro, especificando el valor por defecto a ser utilizado cuando el atributo no está definido.

Para verificar si un atributo ha sido definido para un usuario, se utiliza el método hasAttribute(). Los atributos se guardan en un contenedor de parámetros que puede ser accedido por el método getAttributeHolder(). También permite un borrado rápido de los atributos del usuario con los métodos usuales del contenedor de parámetros, como se muestra en el en el siguiente ejemplo eliminando información de la sesión del usuario

class mimoduloActions extends sfActions
{
public function executeBorraNombre()
{
$this->getUser()->getAttributeHolder()->remove('nombre');
}
public function executeLimpia()
{
$this->getUser()->getAttributeHolder()->clear();
}
}

Los atributos de la sesión del usuario también están disponibles por defecto en las plantillas mediante la variable $sf_user, que almacena el objeto sfUser actual

Manejo de Sesiones

El manejo de sesiones de Symfony se encarga de gestionar automáticamente el almacenamiento de los IDs de sesión tanto en el cliente como en el servidor. Sin embargo, si se necesita modificar este comportamiento por defecto, es posible hacerlo. Se trata de algo que solamente lo necesitan los usuarios más avanzados.

En el lado del cliente, las sesiones son manejadas por cookies. La cookie de Symfony se llama Symfony, pero se puede cambiar su nombre editando el archivo de configuración factories.yml, C

Cambiando el nombre de la cookie de sesión, en apps/frontend/config/
factories.yml
all:
storage:
class: sfSessionStorage
param:
session_name: mi_nombre_cookie

La sesión se inicializa (con la función de PHP session_start()) solo si el parámetro auto_start de factories.yml tiene un valor de true (que es el caso por defecto). Si se quiere iniciar la sesión manualmente, se debe cambiar el valor de esa opción de configuración del archivo factories.yml.

El manejo de sesiones de Symfony esta basado en las sesiones de PHP. Por tanto, si la gestión de la sesión en la parte del cliente se quiere realizar mediante parámetros en la URL en lugar de cookies, se debe modificar el valor de la directiva use_trans_sid en el archivo de configuración php.ini. No obstante, se recomienda no utilizar esta técnica.

session.use_trans_sid = 1

En el lado del servidor, Symfony guarda por defecto las sesiones de usuario en archivos. Se pueden almacenar en la base de datos cambiando el valor del parámetro class en factories.yml.

all:
storage:
class: sfMySQLSessionStorage
param:
db_table: session # Nombre de la tabla que guarda las sesiones
database: propel # Nombre de la conexión a base de datos que se
utiliza
# Parámetros opcionales
db_id_col: sess_id # Nombre de la columna que guarda el
identificador de la sesión
db_data_col: sess_data # Nombre de la columna que guarda los datos de
la sesión
db_time_col: sess_time # Nombre de la columna que guarda el timestamp
de la sesión

La opción database define el nombre de la conexión a base de datos que se utiliza. Posteriormente, Symfony utiliza el archivo databases.yml para determinar los parámetros con los que realiza la conexión (host, nombre de la base de datos, usuario y password).

Las clases disponibles para el almacenamiento de sesiones son sfMySQLSessionStorage, sfMySQLiSessionStorage, sfPostgreSQLSessionStorage y sfPDOSessionStorage. La clase recomendada es sfPDOSessionStorage. Para deshabilitar completamente el almacenamiento de las sesiones, se puede utilizar la clase sfNoStorage.

La expiración de la sesión se produce automáticamente después de 30 minutos. El valor de esta opción se puede modificar para cada entorno en el mismo archivo de configuración factories.yml, concretamente en la factoría correspondiente al usuario (user), tal y como muestra

// Cambiando el tiempo de vida de la sesión, en apps/frontend/config/ factories.yml

all:
user:
class: myUser
param:
timeout: 1800 # Tiempo de vida de la sesión en segundos

Seguridad de la Acción

La posibilidad de ejecutar una acción puede ser restringida a usuarios con ciertos privilegios. Las herramientas proporcionadas por Symfony para este propósito permiten la creación de aplicaciones seguras, en las que los usuarios necesitan estar autenticados antes de acceder a alguna característica o a partes de la aplicación. Añadir esta seguridad a una aplicación requiere dos pasos: declarar los requerimientos de seguridad para cada acción y autenticar a los usuarios con privilegios para que puedan acceder estas acciones seguras.

Restricción de Acceso

Antes de ser ejecutada, cada acción pasa por un filtro especial que verifica si el usuario actual tiene privilegios de acceder a la acción requerida. En Symfony, los privilegios estan compuestos por dos partes:

  • Las acciones seguras requieren que los usuarios esten autenticados.
  • Las credenciales son privilegios de seguridad agrupados bajo un nombre y que permiten organizar la seguridad en grupos.

Para restringir el acceso a una acción se crea y se edita un archivo de configuración YAML llamado security.yml en el directorio config/ del módulo. En este archivo, se pueden especificar los requerimientos de seguridad que los usuarios deberán satisfacer para cada acción o para todas (all) las acciones. SE muestra un ejemplo de security.yml.

Estableciendo restricciones de acceso, en apps/frontend/modules/mimodulo/ config/security.yml
ver:

is_secure: off # Todos los usuarios pueden ejecutar la acción "ver"
modificar:
is_secure: on # La acción "modificar" es sólo para usuarios autenticados
borrar:
is_secure: on # Sólo para usuarios autenticados
credentials: admin # Con credencial "admin"
all:
is_secure: off # off es el valor por defecto

Las acciones no incluyen restricciones de seguridad por defecto, así que cuando no existe el archivo security.yml o no se indica ninguna acción en ese archivo, todas las acciones son accesibles por todos los usuarios. Si existe un archivo security.yml, Syfmony busca por el nombre de la acción y si existe, verifica que se satisfagan los requerimientos de seguridad. Lo que sucede cuando un usuario trata de acceder una acción restringida depende de sus credenciales:

  • Si el usuario está autenticado y tiene las credenciales apropiadas, entonces la acción se ejecuta.
  • Si el usuario no está autenticado, es redireccionado a la acción de login.
  • Si el usuario está autenticado, pero no posee las credenciales apropiadas, será redirigido a la acción segura por defecto, como muestra la figura

Filtros

El mecanismo de seguridad puede ser entendido como un filtro, por el que debe pasar cada petición antes de ejecutar la acción. Según las comprobaciones realizadas en el filtro, se puede modificar el procesamiento de la petición ,por ejemplo, cambiando la acción ejecutada (default/secure en lugar de la acción solicitada en el caso del filtro de seguridad). Symfony extiende esta idea a clases de filtros. Se puede especificar cualquier número de clases de filtros a ser ejecutadas antes de que se procese la respuesta, y además hacerlo de forma sistemática para todas las peticiones. Se pueden entender los filtros como una forma de empaquetar cierto código de forma similar a preExecute() y postExecute(), pero a un nivel superior (para toda una aplicación en lugar de para todo un módulo).

La Vista

La vista se encarga de producir las páginas que se muestran como resultado de las acciones. La vista en Symfony está compuesta por diversas partes, estando cada una de ellas especialmente preparada para que pueda ser fácilmente modificable por la persona que normalmente trabaja con cada aspecto del diseño de las aplicaciones.

  • Los diseñadores web normalmente trabajan con las plantillas (que son la presentación de los datos de la acción que se está ejecutando) y con el layout (que contiene el código HTML común a todas las páginas). Estas partes están formadas por código HTML que contiene pequeños trozos de código PHP, que normalmente son llamadas a los diversos helpers disponibles.
  • Para mejorar la reutilización de código, los programadores suelen extraer trozos de las plantillas y los transforman en componentes y elementos parciales. De esta forma, el layout se modifica para definir zonas en las que se insertan componentes externos. Los diseñadores web también pueden trabajar fácilmente con estos trozos de plantillas.
  • Los programadores normalmente centran su trabajo relativo a la vista en los archivos de configuración YAML (que permiten establecer opciones para las propiedades de la respuesta y para otros elementos de la interfaz) y en el objeto respuesta. Cuando se trabaja con variables en las plantillas, deben considerarse los posibles riesgos de seguridad de XSS (cross-site scripting) por lo que es necesario conocer las técnicas de escape de los caracteres introducidos por los usuarios. Independientemente del tipo de trabajo, existen herramientas y utilidades para simplificar y acelerar el trabajo (normalmente tedioso) de presentar los resultados de las acciones.

Plantillas

En el ejemplo se muestra el código típico de una plantilla. Su contenido está formado por código HTML y algo de código PHP sencillo, normalmente llamadas a las variables definidas en la acción (mediante la instrucción $this->nombre_variable = 'valor';) y algunos helpers.

<h1>Bienvenido</h1>
<p>¡Hola de nuevo, <?php echo $nombre ?>!</p>
<ul>¿Qué es lo que quieres hacer?
<li><?php echo link_to('Leer los últimos artículos', 'articulo/leer') ?></li>
<li><?php echo link_to('Escribir un nuevo artículo', 'articulo/escribir') ?></li>
</ul>

Es recomendable utilizar la sintaxis alternativa de PHP en las plantillas para hacerlas más fáciles de leer a aquellos desarrolladores que desconocen PHP. Se debería minimizar en lo posible el uso de código PHP en las plantillas, ya que estos archivos son los que se utilizan para definir la interfaz de la aplicación, y muchas veces son diseñados y modificados por otros equipos de trabajo especializados en el diseño de la presentación y no de la lógica del programa. Además, incluir la lógica dentro de las acciones permite disponer de varias plantillas para una sola acción sin tener que duplicar el código.

Helpers

Los helpers son funciones de PHP que devuelven código HTML y que se utilizan en las plantillas. En el ejemplo, la función link_to() es un helper. A veces, los helpers solamente se utilizan para ahorrar tiempo, agrupando en una sola instrucción pequeños trozos de código utilizados habitualmente en las plantillas. Por ejemplo, es fácil imaginarse la definición de la función que representa a este helper:

<?php echo input_tag('nick') ?>
=> <input type="text" name="nick" id="nick" value="" />

function input_tag($name, $value = null)

En realidad, la función input_tag() que incluye Symfony es un poco más complicado que eso, ya que permite indicar un tercer parámetro que contiene otros atributos de la etiqueta <input>. Se puede consultar su sintaxis completa y sus opciones en la documentación de la API aqui

La mayoría de las veces los helpers incluyen cierta inteligencia que evita escribir bastante código:

<?php echo auto_link_text('Por favor, visita nuestro sitio web www.ejemplo.com') ?>
=> Por favor, visita nuestro sitio web <a
href="http://www.ejemplo.com">www.ejemplo.com</a>

Los helpers facilitan la creación de las plantillas y producen el mejor código HTML posible en lo que se refiere al rendimiento y a la accesibilidad. Aunque se puede usar HTML normal y corriente, los helpers normalmente son más rápidos de escribir.

Quizás se pregunte por qué motivo los helpers se nombran con la sintaxis de los guiones bajos en vez de utilizar el método camelCase que se utiliza en el resto de Symfony. El motivo es que los helpers son funciones, y todas las funciones de PHP utilizan la sintaxis de los guiones bajos.

Configuración de la vista

  • La presentación HTML del resultado de la acción (que se guarda en la plantilla, en el layout y en los fragmentos de plantilla)
  • El resto, que incluye entre otros los siguientes elementos:
  • Declaraciones : palabras clave (keywords), descripción (description), duración de la cache, etc.
  • El título de la página: no solo es útil para los usuarios que tienen abiertas varias ventanas del navegador, sino que también es muy importante para que los buscadores indexen bien la página.
  • Inclusión de archivos: de JavaScript y de hojas de estilos.
  • Layout: algunas acciones necesitan un layout personalizado (ventanas emergentes, anuncios, etc.) o puede que no necesiten cargar ningún layout (por ejemplo en las acciones relacionadas con Ajax).

En la vista, todo lo que no es HTML se considera configuración de la propia vista y Symfony permite dos formas de manipular esa configuración. La forma habitual es mediante el archivo de configuración view.yml. Se utiliza cuando los valores de configuración no dependen del contexto o de alguna consulta a la base de datos. Cuando se trabaja con valores dinámicos que cambian con cada acción, se recurre al segundo método para establecer la configuración de la vista: añadir los atributos directamente en el objeto sfResponse durante la acción.

El archivo view.yml

Cada módulo contiene un archivo view.yml que define las opciones de su propia vista. De esta forma, es posible definir en un único archivo las opciones de la vista para todo el módulo entero y las opciones para cada vista. Las claves de primer nivel en el archivo view.yml son el nombre de cada módulo que se configura. Semuestra un ejemplo de configuración de la vista.

Ejemplo de archivo view.yml de módulo
editSuccess:
metas:
title: Edita tu perfil
editError:
metas:
title: Error en la edición del perfil
all:
stylesheets: [mi_estilo]
metas:
title: Mi sitio web
{
return '<input type="text" name="'.$name.'" id="'.$name.'" value="'.$value.'" />';
}

Se debe tener en cuenta que las claves principales del archivo view.yml son los nombres de las vistas, no los nombres de las acciones. Recuerda que el nombre de una vista se compone de un nombre de acción y un resultado de acción. Si por ejemplo la acción edit devuelve un valor igual a sfView::SUCCESS (o no devuelve nada, ya que este es el valor devuelto por defecto), el nombre de la vista sería editSuccess.

Las opciones por defecto para el módulo entero se definen bajo la clave all: en el archivo view.yml del módulo. Las opciones por defecto para todas las vistas de la aplicación se definen en el archivo view.yml de la aplicación. Una vez más, se tiene la configuración en cascada:

  • En apps/frontend/modules/mimodulo/config/view.yml, las definiciones de cada vista solo se aplican a una vista y además sus valores tienen preferencia sobre las opciones generales del módulo.
  • En apps/frontend/modules/mimodulo/config/view.yml, las definiciones bajo all: se aplican a todas las acciones del módulo y tienen preferencia sobre las definiciones de la aplicación.
  • En apps/frontend/config/view.yml, las definiciones bajo default: se aplican a todos los módulos y todas las acciones de la aplicación.

Por defecto no existen los archivos view.yml de cada módulo. Por tanto la primera vez que se necesita configurar una opción a nivel de módulo, se debe crear un nuevo archivo llamado view.yml en el directorio config/.

El Modelo

Hasta ahora, la mayor parte de los contenidos se ha dedicado a la construcción de páginas y al procesado de peticiones y respuestas. Sin embargo, la lógica de negocio de las aplicaciones web depende casi siempre en su modelo de datos. El componente que se encarga por defecto de gestionar el modelo en Symfony es una capa de tipo ORM (object/relational mapping) realizada mediante el proyecto Propel. En las aplicaciones Symfony, el acceso y la modificación de los datos almacenados en la base de datos se realiza mediante objetos; de esta forma nunca se accede de forma explícita a la base de datos. Este comportamiento permite un alto nivel de abstracción y permite una fácil portabilidad. Se va a explicar como crear el modelo de objetos de datos, y la forma en la que se acceden y modifican los datos mediante Propel. Además, se muestra la integración de Propel en Symfony.

¿Por qué utilizar un ORM y una capa de abstracción?

Las bases de datos son relacionales. PHP 5 y Symfony están orientados a objetos. Para acceder de forma efectiva a la base de datos desde un contexto orientado a objetos, es necesaria una interfaz que traduzca la lógica de los objetos a la lógica relacional. Como se explicó , esta interfaz se llama ORM (object-relational mapping) o "mapeo de objetos a bases de datos", y está formada por objetos que permiten acceder a los datos y que contienen en sí mismos el código necesario para hacerlo.

La principal ventaja que aporta el ORM es la reutilización, permitiendo llamar a los métodos de un objeto de datos desde varias partes de la aplicación e incluso desde diferentes aplicaciones.

La capa ORM también encapsula la lógica de los datos; como por ejemplo, el cálculo de la puntuación de un usuario de un foro en función de las aportaciones que ha realizado al foro y en función del éxito de esas aportaciones. Cuando una página quiere mostrar esa puntuación de un usuario, simplemente invoca un método del modelo de datos, sin preocuparse de cómo se realiza el cálculo. Si el método de cálculo sufre alguna variación, solo es necesario modificar el método que calcula la puntuación en el modelo, sin necesidad de modificar el resto de la aplicación.

La utilización de objetos en vez de registros y de clases en vez de tablas, tiene otra ventaja: permite añadir métodos accesores en los objetos que no tienen relación directa con una tabla. Si se dispone por ejemplo de una tabla llamada cliente con dos campos llamados nombre y apellidos, puede que se necesite un dato llamado NombreCompleto que incluya y combine el nombre y los apellidos. En el mundo orientado a objetos, es tan fácil como añadir un método accesor a la clase Cliente . Desde el punto de vista de la aplicación, no existen diferencias entre los atributos Nombre, Apellidos, NombreCompleto de la clase Cliente. Solo la propia clase es capaz de determinar si un atributo determinado se corresponde con una columna de la base de datos. Los métodos accesores en la clase del modelo permiten ocultar la estructura real de la tabla de la base de datos

public function getNombreCompleto()
{
return $this->getNombre().' '.$this->getApellidos();
}

Todo el código repetitivo de acceso a los datos y toda la lógica de negocio de los propios datos se puede almacenar en esos objetos. Imagina que se ha definido la clase CarritoCompra en la que se almacena Productos (que son objetos). Para obtener el precio total del carrito de la compra antes de realizar el pago, se puede crear un método que encapsula el proceso de cálculo, tal y como se muestra en el siguiente ejemplo: Los métodos accesores ocultan la lógica de los datos

public function getTotal()
{
$total = 0;
foreach ($this->getProductos() as $producto)
{
$total += $producto->getPrecio() * $producto->getCantidad();
}
return $total;
}

Existe otra consideración importante que hay que tener en cuenta cuando se crean elementos de acceso a los datos: las empresas que crean las bases de datos utilizan variantes diferentes del lenguaje SQL. Si se cambia a otro sistema gestor de bases de datos, es necesario reescribir parte de las consultas SQL que se definieron para el sistema anterior. Si se crean las consultas mediante una sintaxis independiente de la base de datos y un componente externo se encarga de traducirlas al lenguaje SQL concreto de la base de datos, se puede cambiar fácilmente de una base de datos a otra. Este es precisamente el objetivo de las capas de abstracción de bases de datos. Esta capa obliga a utilizar una sintaxis específica para las consultas y a cambio realiza el trabajo sucio de optimizar y adaptar el lenguaje SQL a la base de datos concreta que se está utilizando.

La principal ventaja de la capa de abstracción es la portabilidad, porque hace posible el cambiar la aplicación a otra base de datos, incluso en mitad del desarrollo de un proyecto. Si se debe desarrollar rápidamente un prototipo de una aplicación y el cliente no ha decidido todavía la base de datos que mejor se ajusta a sus necesidades, se puede construir la aplicación utilizando SQLite y cuando el cliente haya tomado la decisión, cambiar fácilmente a MySQL, PostgreSQL o Oracle. Solamente es necesario cambiar una línea en un archivo de configuración y todo funciona correctamente.

Symfony utiliza Propel como ORM y Propel utiliza PDO (PHP Data Objects) como capa de abstracción de bases de datos. Estos dos componentes externos han sido desarrollados por el equipo de Propel, y están completamente integrados en Symfony, por lo que se pueden considerar una parte más del framework. Su sintaxis y sus convenciones, se han adaptado de forma que difieran lo menos posible de las de Symfony.

Uso de la cache

Una de las técnicas disponibles para mejorar el rendimiento de una aplicación consiste en almacenar trozos de código HTML o incluso páginas enteras para poder servirlas en futuras peticiones. Esta técnica se denomina "utilizar caches" y se pueden definir tanto en el lado del servidor como en el del cliente.

Symfony incluye un sistema de cache en el servidor muy flexible. Con este sistema es muy sencillo guardar en un archivo una página entera, el resultado de una acción, un elemento parcial o un trozo de plantilla. La configuración del sistema de cache se realiza de forma intuitiva mediante archivos de tipo YAML. Cuando los datos se modifican, se pueden borrar partes de la cache de forma selectiva mediante la línea de comandos o mediante algunos métodos especiales en las acciones. Symfony también permite controlar la cache en el lado del cliente mediante las cabeceras de HTTP 1.1. En este capítulo se presentan todas estas técnicas y se dan pistas para determinar las mejoras que las caches confieren a las aplicaciones.

Guardando la respuesta en la cache

El principio básico de las caches de HTML es muy sencillo: parte o todo el código HTML que se envía al usuario como respuesta a su petición se puede reutilizar en peticiones similares. El código HTML se almacena en un directorio especial (el directorio cache/) donde el controlador frontal lo busca antes de ejecutar la acción. Si se encuentra el código en la cache, se envía sin ejecutar la acción, por lo que se consigue un gran ahorro de tiempo de ejecución. Si no se encuentra el código, se ejecuta la acción y su respuesta (la vista) se guarda en el directorio de la cache para las futuras peticiones.

Como todas las páginas pueden contener información dinámica, la cache HTML está deshabilitada por defecto. El administrador del sitio web debe activarla para mejorar el rendimiento de la aplicación. Symfony permite gestionar tres tipos diferentes de cache HTML:

  • Cache de una acción (con o sin layout)
  • Cache de un elemento parcial, de un componente o de un slot de componentes
  • Cache de un trozo de plantilla

Los dos primeros tipos de cache se controlan mediante archivos YAML de configuración. La cache de trozos de plantillas se controla mediante llamadas a helpers dentro de las propias plantillas.

El sistema de cache permite mejorar el rendimiento de la aplicación de forma variable en función del tipo de cache utilizado. La siguiente lista muestra los tipos de cache disponibles en Symfony ordenados de mayor a menor mejora en el rendimiento de la aplicación:

  • Super cache
  • Cache de una acción con layout
  • Cache de una acción sin layout
  • Cache de fragmentos de plantillas

Además, tambien se pueden guardar en la cache los elementos parciales y los componentes. Si la modificación de los datos del modelo o de la sesión obliga a borrar la cache para mantener la coherencia de la información, se puede realizar un borrado muy selectivo para no penalizar el rendimiento, ya que es posible borrar solamente los elementos modificados manteniendo todos los demás.

Una recomendación muy importante es la de probar cuidadosamente todas las páginas para las que se ha habilitado la cache, ya que suele ser habitual que se produzcan errores por haber guardado en la cache elementos inadecuados o por no haber borrado de la cache los elementos modificados. Una buena técnica es la de crear un entorno intermedio llamado staging dedicado a probar la cache y las mejoras en el rendimiento de la aplicación.

Por último, es posible exprimir al máximo algunas características del protocolo HTTP 1.1 gracias a las opciones que proporciona Symfony para controlar la cache y que permite aprovechar las ventajas de la cache en el navegador de los clientes, de forma que se aumente aun más el rendimiento de la aplicación.

Características

Symfony, tiene muchas clases destinadas a tratar las funcionalidades mas comunes y redundantes de los desarrollos. A continuación vamos a realizar una breve descripción de las automatizaciones de los elementos comunes de los proyectos web, como por ejemplo:

  • Facilita la internacionalización de los contenidos ya incluye clases que permiten la traducción de los datos y de la interfaz, así como la adaptación local de los contenidos.
  • Realiza una separación de la capa de presentación efectiva, manteniendo las plantillas y layaouts que pueden desarrollarse de forma externa al framework e integrarse en el mismo. Se ofrecen una serie de helpers incluidos en el framework destinados a minimizar el código utilizado en la presentación, ya que encapsulan grandes bloques de código en llamadas simples a funciones.
  • Symfony valida los formularios así como permite el autorelleno de los mismos, facilitanto los mecanismo de seguridad asociados al formato de datos.
  • Se ofrecen mecanismos destinados a controlar las entradas de datos, permitiendo sanearlas y evitando ataques de datos corruptos.
  • Se ofrecen mecanismos para la gestión de cache
  • Existen métodos destinados a controlar la autenticación y la gestión de credenciales facilitnado la creación de secciones restringidas y la gestión de la seguridad de usuario.
  • El sistema de enrutamiento y las URL limpias permiten considerar a las direcciones de las páginas como parte de la interfaz, además de estar optimizadas para los buscadores.
  • Dado el uso de la paginación automatizada, el filtrado y la ordenación de datos son mas fáciles de realizar.
  • Se simplifican las interacciones con Ajax mediante el uso delos helpers que permiten encapsular los efectos JavaScript compatibles con todos los navegadores en una única línea de código.

Ejemplos

Introducidos dentro del recurso para reforzar la explicación de las funcionalidades.