Anda di halaman 1dari 102

Captulo 1.

Symfony2 y los fundamentos de


HTTP
Enhorabuena! Aprender a programar con Symfony2 es una de las mejores formas
de convertirse en un programador web ms productivo, completo y popular
(bueno, esto ltimo en realidad depende de t). Symfony2 est diseado para
volver a lo bsico: herramientas de desarrollo que te permiten programar ms
rpido y construir aplicaciones ms robustas, y que afectan lo mnimo a tu forma
de trabajar.
Symfony est basado en las mejores ideas de muchas tecnologas: las
herramientas y conceptos que ests a punto de aprender representan el esfuerzo
de miles de personas, durante muchos aos. En otras palabras, no ests
aprendiendo "Symfony", ests aprendiendo los fundamentos de la web, buenas
prcticas de desarrollo, y cmo utilizar algunas de las mejores libreras PHP
publicadas recientemente. Por lo tanto, preprate!
Fiel a la filosofa Symfony2, este captulo comienza explicando el concepto
fundamental comn para el desarrollo web: HTTP. No importa cul sea tu
experiencia previa o cules sean tus lenguajes de programacin favoritos, este
captulo es una lectura obligada para todo el mundo.
1.1. HTTP es simple
HTTP ("HyperText Transfer Protocol") es un lenguaje basado en texto que permite
a dos mquinas comunicarse entre s. Eso es todo! La siguiente conversacin es
la que por ejemplo tiene lugar cuando quieres acceder a la ltima tira cmica
publicada por el sitio xkcd:

Figura 1.1 Flujo HTTP para obtener la tira cmica ms reciente de Xkcd
Y aunque el lenguaje realmente utilizado es un poco ms formal, sigue siendo
bastante simple.
HTTP es el trmino utilizado para describir este lenguaje simple basado en texto.
Y no importa cmo desarrolles en la web, el objetivo de tu servidor siempre es
entender las peticiones de texto simple, y devolver respuestas en texto simple.
Symfony2 est diseado en base a esa realidad. Aunque a veces no te des
cuenta, HTTP es algo que usas todos los das. Con Symfony2, aprenders a
dominarlo.
1.1.1. Paso 1: El cliente enva una peticin
Todas las conversaciones en la web comienzan con una peticin. La peticin es
un mensaje de texto creado por un cliente (por ejemplo un navegador, una
aplicacin para el iPhone, etc.) en un formato especial conocido como HTTP. El
cliente enva la peticin a un servidor, y luego espera la respuesta.
Echa un vistazo a la primera parte de la interaccin (la peticin) entre un
navegador y el servidor web del sitio xkcd:

Figura 1.2 Peticin HTTP para obtener la tira cmica ms reciente de Xkcd
Utilizando el lenguaje HTTP, esta peticin en realidad sera algo parecido a lo
siguiente:
GET / HTTP/1.1
Host: xkcd.com
Accept: text/html
User-Agent: Mozilla/5.0 (Macintosh)
Este sencillo mensaje comunica todo lo necesario sobre qu recursos
exactamente solicita el cliente. La primera lnea de una peticin HTTP es la ms
importante y contiene dos cosas: la URI y el mtodo HTTP.
La URI (por ejemplo, /, /contacto, etc.) es la direccin o ubicacin que identifica
unvocamente al recurso que solicita el cliente. El mtodo HTTP (por ejemplo, GET)
define lo que quieres hacer con el recurso. Los mtodos HTTP son los verbos de
la peticin y definen las pocas formas en que puedes actuar sobre el recurso:
Mtodo Accin
GET Recupera el recurso desde el servidor
POST Crea un recurso en el servidor
Mtodo Accin
PUT Actualiza el recurso en el servidor
DELETE Elimina el recurso del servidor
Teniendo esto en cuenta, puedes imaginar cmo sera por ejemplo la peticin
HTTP necesaria para borar un artculo especfico de un blog:
DELETE /blog/15 HTTP/1.1
NOTA En realidad, hay nueve mtodos HTTP definidos por la especificacin HTTP,
pero muchos de ellos no se utilizan o no estn soportados. De hecho, muchos
navegadores modernos no soportan los mtodos PUT y DELETE.
Adems de la primera lnea, una peticin HTTP contiene tambin otras lneas de
informacin conocidas como cabeceras de peticin. Las cabeceras proporcionan
mucha informacin, como el servidor (o host) solicitado, los formatos de respuesta
que acepta el cliente (Accept) y la aplicacin que utiliza el cliente para realizar la
peticin (User-Agent). Existen muchas otras cabeceras y se pueden encontrar en
el artculo Lista de campos de las cabeceras HTTP en la Wikipedia.
1.1.2. Paso 2: El servidor devuelve una respuesta
Una vez que un servidor ha recibido la peticin, sabe exactamente qu recursos
necesita el cliente (a travs de la URI) y lo que el cliente quiere hacer con ese
recurso (a travs del mtodo). Por ejemplo, en el caso de una peticin GET, el
servidor prepara el recurso y lo devuelve en una respuesta HTTP. Considera la
respuesta del servidor web del sitio xkcd:

Figura 1.3 Respuesta HTTP para obtener la tira cmica ms reciente de Xkcd
Traducida a HTTP, la respuesta enviada de vuelta al navegador es similar a lo
siguiente:
HTTP/1.1 200 OK
Date: Sat, 02 Apr 2011 21:05:05 GMT
Server: lighttpd/1.4.19
Content-Type: text/html

<html>
<!-- HTML de la tira cmica de Xkcd -->
</html>
La respuesta HTTP contiene el recurso solicitado (en este caso, el contenido
HTML de una pgina web), as como otra informacin acerca de la respuesta. La
primera lnea es especialmente importante y contiene el cdigo de estado HTTP
(200 en este caso) de la respuesta. El cdigo de estado indica el resultado global
de la peticin devuelta al cliente. Tuvo xito la peticin? Hubo algn error?
Existen diferentes cdigos de estado que indican xito, error o qu ms se
necesita hacer con el cliente (por ejemplo, redirigirlo a otra pgina). La lista
completa se puede encontrar en el artculo Lista de cdigos de estado HTTP en la
Wikipedia.
Al igual que la peticin, una respuesta HTTP contiene datos adicionales conocidos
como cabeceras HTTP. Por ejemplo, una cabecera importante de la respuesta
HTTP es Content-Type. Un mismo recurso se puede devolver en varios formatos
diferentes (HTML, XML, JSON, etc.) y la cabeceraContent-Type dice al cliente qu
formato se ha utilizado (para ello utiliza valores estndar comotext/html que se
conocen como Internet Media Types). Puedes encontrar la lista completa de tipos
de contenido en el artculo Lista de tipos de contenido de Internet en la Wikipedia.
Existen muchas otras cabeceras, algunas de las cuales son muy importantes. Por
ejemplo, ciertas cabeceras se pueden usar para crear un sistema de memoria
cach bastante interesante.
1.1.3. Peticiones, respuestas y desarrollo web
Esta conversacin peticin-respuesta es el proceso fundamental en el que se basa
toda la comunicacin en la web. Y a pesar de ser tan importante y poderoso, al
mismo tiempo es muy sencillo.
El concepto ms importante es el siguiente: independientemente del lenguaje que
utilices, el tipo de aplicacin que construyas (web, mvil, API), o la filosofa de
desarrollo que sigas, el objetivo final de una aplicacin siempre es entender cada
peticin y crear y devolver la respuesta adecuada.
Symfony est diseado para adaptarse a esta realidad.
TRUCO Puedes obtener ms informacin acerca de la especificacin HTTP, en la
referencia originalHTTP 1.1 RFC. Tambin puedes leer la referencia HTTP Bis,
que es una versin actualizada y ms detallada de la referencia anterior. Una gran
herramienta para comprobar tanto la peticin como las cabeceras de la respuesta
mientras navegas es la extensin Live HTTP Headers de Firefox o elInspector
Web de los navegadores Chrome y Safari.
1.2. Peticiones y respuestas en PHP
Cmo interactas con la "peticin" y creas una "respuesta" utilizando PHP? En
realidad, PHP te abstrae un poco de todo el proceso:
<?php
$uri = $_SERVER['REQUEST_URI'];
$foo = $_GET['foo'];

header('Content-type: text/html');
echo 'La URI solicitada es: '.$uri;
echo 'El valor del parmetro "foo" es: '.$foo;
Por extrao que parezca, esta pequea aplicacin est obteniendo informacin de
la peticin HTTP y la utiliza para crear una respuesta HTTP. En lugar de analizar
el mensaje HTTP de la peticin, PHP crea variables
superglobales como $_SERVER y $_GET que contienen toda la informacin de la
peticin. Del mismo modo, en lugar de devolver la respuesta HTTP con formato de
texto, puedes usar la funcin header() para crear las cabeceras de la respuesta y
simplemente imprimir el contenido que se enviar en el mensaje de la respuesta.
Despus PHP crea la verdadera respuesta HTTP que se devuelve al cliente:
HTTP/1.1 200 OK
Date: Sat, 03 Apr 2011 02:14:33 GMT
Server: Apache/2.2.17 (Unix)
Content-Type: text/html

La URI solicitada es: /testing?foo=symfony
El valor del parmetro "foo" es: symfony
1.3. Peticiones y respuestas en Symfony
Symfony ofrece una alternativa al enfoque de PHP a travs de dos clases que te
permiten interactuar con la peticin HTTP y la respuesta de una manera ms fcil.
La clase Request representa la peticin HTTP siguiendo la filosofa de orientacin
a objetos. Con ella, tienes toda la informacin a tu alcance:
use Symfony\Component\HttpFoundation\Request;

$request = Request::createFromGlobals();

// la URI solicitada (p.e. /contacto) menos algunos parmetros de la consult
a
$request->getPathInfo();

// recupera las variables GET y POST respectivamente
$request->query->get('foo');
$request->request->get('bar', 'valor utilizado si "bar" no existe');

// recupera las variables de SERVER
$request->server->get('HTTP_HOST');

// recupera una instancia del archivo subido identificado por 'foo'
$request->files->get('foo');

// recupera un valor de una COOKIE
$request->cookies->get('PHPSESSID');

// recupera una cabecera HTTP de la peticin, normalizada, con ndices en mi
nscula
$request->headers->get('host');
$request->headers->get('content_type');

$request->getMethod(); // GET, POST, PUT, DELETE, HEAD
$request->getLanguages(); // un array de idiomas aceptados por el cliente
Una ventaja aadida es que la clase Request hace un montn de trabajo adicional
del que no tienes que preocuparte. Por ejemplo, el
mtodo isSecure() internamente comprueba tres valores PHP diferentes que
pueden indicar si el usuario est conectado a travs de una conexin segura (es
decir,https).
ParameterBags y atributos de la peticinComo vimos anteriormente, las
variables $_GET y $_POST son accesibles a travs de las
propiedadesquery y request de la clase Request, respectivamente. Cada uno de
estos objetos es un objeto de la clase ParameterBag, la cual cuenta con mtodos
cmo get(), has() y all() entre otros.
De hecho, todas las propiedades pblicas utilizadas en el cdigo del ejemplo
anterior son un ejemplo del ParameterBag.
La clase Request tambin tiene una propiedad pblica attributes, que almacena
informacin especial relacionada sobre el funcionamiento interno de la aplicacin.
En Symfony2, la propiedadattibutes guarda por ejemplo los valores relacionados
con el sistema de enrutamiento que se explicar ms adelante (como por
ejemplo, _controller y _route). El propsito de la propiedadattributes es el de
preparar y almacenar informacin del contexto especfico de la peticin.
Symfony tambin proporciona una clase Response, que simplifica la representacin
de la respuesta HTTP en PHP. Esto permite que tu aplicacin utilice una interfaz
orientada a objetos para construir la respuesta que ser devuelta al cliente:
use Symfony\Component\HttpFoundation\Response;

$response = new Response();

$response->setContent('<html><body><h1>Hello world!</h1></body></html>');
$response->setStatusCode(Response::HTTP_OK);
$response->headers->set('Content-Type', 'text/html');

// imprime las cabeceras HTTP seguidas por el contenido
$response->send();
NOTA Las constantes que definen los cdigos de estado de HTTP (como por
ejemploResponse::HTTP_OK) fueron aadidas en la versin 2.4 de Symfony.
Si Symfony no ofreciera nada ms, ya tendras un conjunto de herramientas para
acceder fcilmente a la informacin de la peticin y una interfaz orientada a
objetos para crear la respuesta. De hecho, a medida que aprendas muchas de las
caractersticas avanzadas de Symfony, nunca debes olvidar que el objetivo de tu
aplicacin es interpretar una peticin y crear la respuesta adecuada basada en la
lgica de tu aplicacin.
TRUCO Las clases Request y Response forman parte de un componente
independiente incluido en Symfony llamado HttpFoundation. Este componente se
puede utilizar en aplicaciones independientes de Symfony y tambin proporciona
clases para manejar sesiones y subir archivos.
1.4. El viaje desde la peticin hasta la
respuesta
Al igual que el mismo HTTP, los objetos Peticin y Response son bastante simples.
La parte difcil de la construccin de una aplicacin es escribir lo que viene en el
medio.
En otras palabras, el verdadero trabajo viene al escribir el cdigo que interpreta la
informacin de la peticin y crea la respuesta.
Tu aplicacin probablemente hace muchas cosas, como enviar correo electrnico,
manejar los formularios presentados, guardar cosas en una base de datos,
reproducir las pginas HTML y proteger el contenido con seguridad. Cmo
puedes manejar todo esto y al mismo tiempo conseguir que tu cdigo est
organizado y sea fcil de mantener?
Symfony fue creado precisamente para resolver estos problemas y para que no
tengas que hacerlo a mano.
1.4.1. El controlador frontal
Antiguamente, las aplicaciones web se construan de modo que cada pgina web
del sitio tena su propio archivo fsico:
index.php
contacto.php
blog.php
Esta filosofa de trabajo tiene varios problemas, como la falta de flexibilidad de
las URL (qu pasa si quieres cambiar blog.php a noticias.php sin romper todos
tus enlaces?) y el hecho de que cada archivo debe incluir a mano todos los
archivos necesarios para la seguridad, conexiones a base de datos y para aplicar
los estilos grficos del sitio.
Una solucin mucho mejor es usar un controlador frontal, que es un solo archivo
PHP que se encarga de servir todas las peticiones que llegan a tu aplicacin. Por
ejemplo:
Archivo solicitado Archivo realmente ejecutado
/index.php index.php
/index.php/contacto index.php
/index.php/blog index.php
TRUCO Usando el mdulo mod_rewrite de Apache (o el equivalente en otros
servidores web), lasURL se pueden limpiar fcilmente para que quiten la parte
del index.php y se queden simplemente en /, /contacto y /blog.
Ahora, todas las peticiones se manejan exactamente igual. En lugar de URL
individuales ejecutando diferentes archivos PHP, el controlador frontal siempre se
ejecuta, y la redireccin de cada URL a una parte diferente de la aplicacin se
realiza internamente. Esto resuelve los problemas comentados anteriormente.
Casi todas las aplicaciones web modernas siguen la filosofa del controlador
frontal, incluyendo aplicaciones como WordPress.
1.4.2. Mantente organizado
Una vez dentro del controlador frontal, cmo sabes qu pgina debes generar y
cmo puedes generar todas las pginas sin que la aplicacin se vuelva catica? El
truco consiste en comprobar la URI entrante y ejecutar diferentes partes de tu
cdigo en funcin de ese valor. Aunque es bastantechapucero, el siguiente cdigo
te podra servir para ello:
// Contenido del archivo index.php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();
$path = $request->getPathInfo(); // La ruta URI solicitada

if (in_array($path, array('', '/')) {
$response = new Response('Bienvenido a nuestra portada.');
} elseif ($path == '/contacto') {
$response = new Response('Contctanos');
} else {
$response = new Response('Pgina no encontrada.', Response::HTTP_NOT_FOU
ND);
}
$response->send();
Escalar el cdigo anterior para una aplicacin real es un problema difcil de
resolver. Afortunadamente esto es exactamente para lo que Symfony est
diseado.
1.4.3. El flujo de las aplicaciones Symfony
Cuando dejas que Symfony controle cada peticin, tu vida como programador es
mucho ms fcil. Symfony sigue el mismo patrn simple en cada peticin. Las
peticiones entrantes son interpretadas por el enrutador y pasadas a las funciones
controladoras, que devuelven objetos Response.

Figura 1.4 Flujo de la peticin en Symfony2
Cada pgina de tu sitio est definida en un archivo de configuracin de rutas que
asigna a cada URL una funcin PHP diferente. El trabajo de cada funcin PHP
(conocida como controlador), es utilizar la informacin de la peticin junto con
muchas otras herramientas que Symfony pone a tu disposicin para crear y
devolver un objeto Response. En otras palabras, el controlador es donde est tu
cdigo: ah es dnde se interpreta la peticin y se crea una respuesta. As de
fcil!
Repasemos:
Cada peticin ejecuta un archivo controlador frontal;
El sistema de enrutado determina qu funcin PHP se ejecuta en base a la
informacin de la peticin y la configuracin de enrutado que hemos creado;
Se ejecuta la funcin PHP adecuada, donde tu cdigo crea y devuelve el
objeto Response.
1.4.4. Una peticin Symfony en la prctica
Sin entrar demasiado en los detalles, veamos este proceso en la prctica.
Supongamos que deseas agregar una pgina /contacto a tu aplicacin Symfony.
En primer lugar, empezamos agregando una entrada /contacto a tu archivo de
configuracin de rutas:
YAML
XML
PHP
# app/config/routing.yml
contacto:
path: /contacto
defaults: { _controller: AcmeDemoBundle:Main:contacto }
NOTA En este ejemplo utilizamos YAML para definir la configuracin de enrutado,
pero tambin se pueden utilizar los formatos XML y PHP.
Cuando alguien visita la pgina /contacto, Symfony2 detecta que se trata de esta
ruta y se ejecuta el controlador especificado. Como veremos en el captulo de
enrutamiento, la cadenaAcmeDemoBundle:Main:contacto es un atajo que apunta al
mtodo contactoAction() de PHP dentro de una clase llamada MainController:
// src/Acme/DemoBundle/Controller/MainController.php
namespace Acme\DemoBundle\Controller;

use Symfony\Component\HttpFoundation\Response;

class MainController
{
public function contactoAction()
{
return new Response('<h1>Contctanos</h1>');
}
}
En este ejemplo sencillo, el controlador simplemente crea un objeto Response con
el cdigo HTML "<h1>Contctanos</h1>". En el captulo dedicado a los
controladores aprenders cmo hacer que los controladores utilicen plantillas para
generar el contenido HTML en vez de tener que escribirlo directamente en el
objeto Response. Esto hace que el controlador deba preocuparse slo de las cosas
difciles: la interaccin con la base de datos, la manipulacin de la informacin o el
envo de mensajes de correo electrnico.
1.5. Symfony2: construye tu aplicacin, no tus
herramientas
Ahora sabemos que el objetivo de cualquier aplicacin es interpretar cada peticin
entrante y crear una respuesta adecuada. Cuando una aplicacin crece, es ms
difcil organizar tu cdigo y que a la vez sea fcil de mantener. Adems, siempre te
vas a encontrar con las mismas tareas complejas: la persistencia de informacin a
la base de datos, procesar y reutilizar plantillas, manejar los formularios, enviar
mensajes de correo electrnico, validar los datos del usuario, administrar la
seguridad del sitio web, etc.
La buena noticia es que todos los programadores web se encuentran con esos
mismos problemas. As que Symfony proporciona una plataforma completa, con
herramientas que te permiten construir tu aplicacin, no tus herramientas. Con
Symfony2, nada se te impone: eres libre de usar la plataforma Symfony completa,
o simplemente aquellas partes de Symfony que quieras.
1.5.1. Herramientas independientes: los componentes de Symfony2
Con todo lo anterior, qu es exactamente Symfony2?. En primer lugar, Symfony2
es una coleccin de ms de veinte libreras independientes que se pueden utilizar
dentro de cualquier proyecto PHP. Estas libreras, llamadas componentes de
Symfony2, son bastante tiles prticamente para cualquier aplicacin,
independientemente de cmo desarrolles tu proyecto. Las siguientes son algunas
de las ms destacadas:
HttpFoundation: contiene las clases Request y Response, as como otras clases
para manejar sesiones y cargar archivos.
Routing: potente y rpido sistema de enrutado que te permite asignar una URI
especfica (por ejemplo /contacto) a cierta informacin acerca de cmo se
debe manejar dicha peticin (por ejemplo, ejecutar el
mtodo contactoAction()).
Form: una completa y flexible plataforma para crear formularios y procesar los
datos presentados en ellos.
Validator: un sistema para crear reglas sobre datos y as comprobar si los
datos que presenta el usuario son vlidos o no siguiendo esas reglas.
ClassLoader: una librera para cargar automticamente clases PHP sin
necesidad de aadir instrucciones require a mano en los archivos que
contienen esas clases.
Templating: juego de herramientas para utilizar plantillas, que soporta desde
la herencia de plantillas (es decir, una plantilla est decorada con un diseo) y
hasta otras tareas comunes de las plantillas.
Security: una poderosa librera para manejar todo tipo de seguridad dentro de
una aplicacin.
Translation: plataforma para traducir cadenas de texto en tu aplicacin.
Todos y cada uno de estos componentes estn desacoplados, lo que significa que
puedes utilizarlos en cualquier proyecto PHP, independientemente de si utilizas la
plataforma Symfony2.
Cada componente est diseado para utilizarlo si es conveniente o para sustituirlo
cuando sea necesario.
1.5.2. La solucin completa: la plataforma Symfony2
Qu es la plataforma Symfony2? La plataforma Symfony2 es una librera PHP
que realiza dos tareas diferentes:
Proporciona una seleccin de componentes Symfony2 y algunas libreras de
terceros (por ejemplo, SwiftMailer para enviar mensajes de correo
electrnico).
Define una configuracin adecuada e incluye una capa que integra todas las
diferentes partes (componentes, libreras, etc.)
El objetivo de la plataforma es integrar muchas herramientas independientes con
el fin de proporcionar una experiencia coherente al desarrollador.
Symfony2 proporciona un potente conjunto de herramientas para desarrollar
aplicaciones web rpidamente sin afectar excesivamente a tu forma de trabajar. Si
ests comenzando con Symfony2, lo mejor es que utilices una distribucin de
Symfony2, que proporciona un esqueleto de un proyecto Symfony2 de prueba
con varios parmetros ya preconfigurados. Si eres un usuario avanzado, puedes
crearte tu propia distribucin o incluso utilizar componentes individuales de
Symfony2
Captulo 2. De PHP a Symfony2
Por qu Symfony2 es mejor que escribir cdigo PHP a pelo? Si nunca has
usado una plataforma PHP, o no ests familiarizado con la filosofa MVC, o
simplemente te preguntas qu es todo ese ruidogenerado en torno a Symfony2,
este captulo es para ti. En vez de contarte que Symfony2 te permite desarrollar
software ms rpido y mejor que con PHP simple, vas a poder comprobarlo tu
mismo.
En este captulo, vamos a escribir una aplicacin sencilla en PHP simple, y luego
la reconstruiremos para que est mejor organizada. Podrs viajar a travs del
tiempo, viendo las decisiones de por qu el desarrollo web ha evolucionado en los
ltimos aos hasta donde est ahora.
Al final del captulo, vers cmo Symfony2 se encarga de todas las tareas
comunes (y aburridas) mientras que te permite recuperar el control de tu cdigo.
2.1. Un blog sencillo creado con PHP simple
En este captulo, crearemos la tpica aplicacin de blog utilizando slo PHP
simple.
Para empezar, crea una pgina que muestre las entradas del blog que se han
persistido en la base de datos. Escribirla en PHP simple es rpido, pero un
poco sucio:
<?php
// index.php

$link = mysql_connect('localhost', 'myuser', 'mypassword');
mysql_select_db('blog_db', $link);

$result = mysql_query('SELECT id, title FROM post', $link);
?>

<html>
<head>
<title>List of Posts</title>
</head>
<body>
<h1>List of Posts</h1>
<ul>
<?php while ($row = mysql_fetch_assoc($result)): ?>
<li>
<a href="/show.php?id=<?php echo $row['id'] ?>">
<?php echo $row['title'] ?>
</a>
</li>
<?php endwhile; ?>
</ul>
</body>
</html>

<?php
mysql_close($link);
El cdigo anterior es fcil de escribir y se ejecuta muy rpido, pero en cuanto la
aplicacin crece, es muy difcil de mantener. Sus principales problemas son los
siguientes:
No hay comprobacin de errores: qu sucede si falla la conexin a la base
de datos?
Organizacin deficiente: si la aplicacin crece, este nico archivo cada vez
ser ms difcil de mantener, hasta que finalmente sea imposible. Dnde se
debe colocar el cdigo para manejar los formularios? Cmo se pueden
validar los datos? Dnde debe ir el cdigo para enviar mensajes de correo
electrnico?
Es difcil reutilizar el cdigo: ya que todo est en un archivo, no hay manera
de volver a utilizar alguna parte de la aplicacin en otras pginas del blog.
NOTA Otro problema no mencionado aqu es el hecho de que la base de datos est
vinculada a MySQL. Aunque no se ha tratado aqu, Symfony2 integra Doctrine,
una librera que permite abstraer el acceso a la base de datos y el manejo de la
informacin.
Vamos a trabajar a continuacin en la solucin de estos y muchos otros problemas
ms.
2.1.1. Aislando la parte de la vista
El cdigo se puede mejorar fcilmente separando la lgica de la aplicacin (cdigo
PHP puro) y "la parte de la vista" o "presentacin", que est formada por todo lo
relacionado con el cdigo HTML:
<?php
// index.php

$link = mysql_connect('localhost', 'myuser', 'mypassword');
mysql_select_db('blog_db', $link);

$result = mysql_query('SELECT id, title FROM post', $link);

$posts = array();
while ($row = mysql_fetch_assoc($result)) {
$posts[] = $row;
}

mysql_close($link);

// incluye el cdigo HTML de la vista
require 'templates/list.php';
Ahora el cdigo HTML est guardado en un archivo separado
(templates/list.php). Este archivo contiene todo el cdigo HTML junto con
algunas pocas instrucciones PHP que utilizan la sintaxis alternativa recomendada
para las plantillas PHP:
<html>
<head>
<title>List of Posts</title>
</head>
<body>
<h1>List of Posts</h1>
<ul>
<?php foreach ($posts as $post): ?>
<li>
<a href="/read?id=<?php echo $post['id'] ?>">
<?php echo $post['title'] ?>
</a>
</li>
<?php endforeach; ?>
</ul>
</body>
</html>
Por convencin, el archivo que contiene toda la lgica de la aplicacin (index.php)
se conoce como"controlador". El trmino controlador es una palabra que se utiliza
mucho, independientemente del lenguaje o plataforma que utilices. Simplemente
se refiere a la zona de tu cdigo que procesa la peticin del usuario y prepara la
respuesta.
En este caso, nuestro controlador obtiene los datos de la base de datos y, luego
los incluye en una plantilla para presentarlos al usuario. Con el controlador aislado,
podramos cambiar fcilmente slo el archivo de la plantilla si queremos servir los
contenidos del blog en otro formato (por ejemplo,list.json.php para el
formato JSON).
2.1.2. Aislando la lgica de la aplicacin (el dominio)
Por ahora la aplicacin slo contiene una pgina. Pero qu pasa si una segunda
pgina necesita utilizar la misma conexin a la base de datos, e incluso el mismo
resultado de la bsqueda de las entradas del blog? La solucin consiste en
refactorizar el cdigo para que todas estas funciones bsicas de acceso a datos
de la aplicacin estn aisladas en un nuevo archivo llamado model.php:
<?php
// model.php

function open_database_connection()
{
$link = mysql_connect('localhost', 'myuser', 'mypassword');
mysql_select_db('blog_db', $link);

return $link;
}

function close_database_connection($link)
{
mysql_close($link);
}

function get_all_posts()
{
$link = open_database_connection();

$result = mysql_query('SELECT id, title FROM post', $link);
$posts = array();
while ($row = mysql_fetch_assoc($result)) {
$posts[] = $row;
}
close_database_connection($link);

return $posts;
}
TRUCO Se utiliza el nombre model.php para el archivo porque el acceso a la lgica y
los datos de una aplicacin se conoce tradicionalmente como la capa
del "modelo". En una aplicacin bien organizada, la mayora del cdigo que
representa tu "lgica de negocio" debe estar en el modelo (en lugar del
controlador). Y, a diferencia de este ejemplo, slo una parte (o ninguna) del
modelo realmente est interesada en acceder a la base de datos.
El controlador (index.php) ahora es muy sencillo:
<?php
require_once 'model.php';

$posts = get_all_posts();

require 'templates/list.php';
Ahora, la nica tarea del controlador es conseguir los datos de la capa del modelo
de la aplicacin (el modelo) y utilizar una plantilla para mostrar los datos.
Este es un ejemplo muy simple del patrn modelo - vista - controlador.
2.1.3. Aislando el diseo
La aplicacin ahora est dividida en tres partes distintas, lo que nos ofrece varias
ventajas y la oportunidad de volver a utilizar casi todo en diferentes pginas.
La nica parte del cdigo que no se puede reutilizar es el diseo HTML + CSS de
la pgina. Vamos a solucionar este problema creando un nuevo archivo
llamado base.php:
<!-- templates/base.php -->
<html>
<head>
<title><?php echo $title ?></title>
</head>
<body>
<?php echo $content ?>
</body>
</html>
La plantilla original (templates/list.php) ahora se puede simplificar para que
utilice el archivobase.php anterior como base:
<?php $title = 'List of Posts' ?>

<?php ob_start() ?>
<h1>List of Posts</h1>
<ul>
<?php foreach ($posts as $post): ?>
<li>
<a href="/read?id=<?php echo $post['id'] ?>">
<?php echo $post['title'] ?>
</a>
</li>
<?php endforeach; ?>
</ul>
<?php $content = ob_get_clean() ?>

<?php include 'base.php' ?>
El cdigo anterior introducido una metodologa que nos permite reutilizar el diseo.
Desafortunadamente, para conseguirlo estamos obligados a utilizar en la plantilla
algunas funciones de PHP poco recomendables (ob_start(), ob_get_clean()).
Symfony2 utiliza un componente de plantillas (Templating) que nos permite realizar
esto de una manera ms limpia y sencilla. En breve lo
2.2. Agregando una pgina show al blog
La pgina list del blog se ha rediseado para que el cdigo est mejor
organizado y sea reutilizable. Para probar que esto es as, aade una
pgina show al blog, que muestre una entrada individual del blog identificada por
un parmetro de consulta id.
Para empezar, crea una nueva funcin en el archivo model.php que recupere un
resultado individual del blog basndose en un identificador dado:
// model.php
function get_post_by_id($id)
{
$link = open_database_connection();

$id = mysql_real_escape_string($id);
$query = 'SELECT date, title, body FROM post WHERE id = '.$id;
$result = mysql_query($query);
$row = mysql_fetch_assoc($result);

close_database_connection($link);

return $row;
}
A continuacin, crea un nuevo archivo llamado show.php, que ser el controlador
para esta nueva pgina:
<?php
require_once 'model.php';

$post = get_post_by_id($_GET['id']);

require 'templates/show.php';
Por ltimo, crea el nuevo archivo de plantilla (templates/show.php) para mostrar
una entrada individual del blog:
<?php $title = $post['title'] ?>

<?php ob_start() ?>
<h1><?php echo $post['title'] ?></h1>

<div class="date"><?php echo $post['date'] ?></div>
<div class="body">
<?php echo $post['body'] ?>
</div>
<?php $content = ob_get_clean() ?>

<?php include 'base.php' ?>
Como has visto, es muy fcil crear la segunda pgina sin duplicar cdigo. Sin
embargo, esta nueva pgina introduce algunos problemas adicionales que una
plataforma web puede resolver por ti. Por ejemplo, si el usuario proporciona un
valor ilegal para el parmetro id o un valor vaco, la consulta har que la pgina se
bloquee. En este caso, sera mejor que la aplicacin generara una pgina de error
de tipo 404 (algo que no es fcil con el cdigo actual de la aplicacin). Peor an, si
no te acuerdas de limpiar con la funcin mysql_real_escape_string() el
parmetro id que te pasa el usuario, tu base de datos sera vulnerable a los
ataques de tipo inyeccin SQL.
Otro problema importante es que cada archivo de tipo controlador debe incluir el
archivo model.php. Qu pasara si cada archivo de controlador de repente tuviera
que incluir un archivo adicional o realizar alguna tarea global (por ejemplo, reforzar
la seguridad)?
Tal como est ahora, el cdigo tendra que incluir a mano todos los archivos de los
controladores. Si olvidas incluir algo en un solo archivo, esperamos que no sea
alguno relacionado con la seguridad.
2.3. El controlador frontal al rescate
Una solucin mucho mejor es usar un controlador frontal: un nico archivo PHP a
travs del cual se procesen todas las peticiones del usuario. Con un controlador
frontal, la URI de la aplicacin cambia un poco, pero se vuelve mucho ms flexible:
Sin controlador frontal:
/index.php => (ejecuta index.php) la pgina que lista los artculos.
/show.php => (ejecuta show.php) la pgina que muestra un artculo es
pecfico.

Con index.php como controlador frontal
/index.php => (ejecuta index.php) la pgina que lista los artculos.
/index.php/show => (ejecuta index.php) la pgina que muestra un artculo es
pecfico.
TRUCO El nombre del archivo index.php se puede eliminar en las URLs si utilizas
las reglas de reescritura del servidor web Apache (o las equivalentes de los dems
servidores web). En ese caso, la URI resultante de la pgina show del blog sera
simplemente /show.
Cuando se usa un controlador frontal, un solo archivo PHP (index.php en este
caso) procesa todas las peticiones. Para la pgina show del
blog, /index.php/show realmente ejecuta el archivo index.php, que ahora es el
responsable de dirigir internamente las peticiones basndose en la URI completa.
Como puedes ver, un controlador frontal es una herramienta muy poderosa.
2.3.1. Creando el controlador frontal
Ests a punto de dar un gran paso en la aplicacin. Con un archivo manejando
todas las peticiones, puedes centralizar cosas como el manejo de la seguridad, la
carga de la configuracin y el enrutamiento. En nuestra
aplicacin, index.php ahora debe ser lo suficientemente inteligente como para
mostrar la lista de entradas del blog o mostrar la pgina de una entrada particular
basndose en la URI solicitada:
<?php
// index.php

// carga e inicia algunas libreras globales
require_once 'model.php';
require_once 'controllers.php';

// encamina la peticin internamente
$uri = $_SERVER['REQUEST_URI'];
if ($uri == '/index.php') {
list_action();
} elseif ($uri == '/index.php/show' && isset($_GET['id'])) {
show_action($_GET['id']);
} else {
header('Status: 404 Not Found');
echo '<html><body><h1>Page Not Found</h1></body></html>';
}
Para organizar mejor el cdigo, los dos controladores anteriores
(archivos index.php y show.php) se han convertido en funciones PHP del nuevo
archivo controllers.php:
function list_action()
{
$posts = get_all_posts();
require 'templates/list.php';
}

function show_action($id)
{
$post = get_post_by_id($id);
require 'templates/show.php';
}
Como controlador frontal, index.php ha asumido un papel completamente nuevo,
que incluye la carga de los archivos principales de la aplicacin
(model.php y controllers.php) y la decisin de ejecutar uno de los dos
controladores (las funciones list_action() y show_action()). En realidad, el
controlador frontal est empezando a parecerse y actuar como el mecanismo que
define Symfony2 para la manipulacin y enrutado de peticiones.
TRUCO Otra ventaja del controlador frontal es la flexibilidad de las URL. Ten en
cuenta que la URL de la pgina show del blog se puede cambiar
de /show a /read cambiando el cdigo en un nico lugar. Antes, era necesario
cambiar todo un archivo para cambiar el nombre. En Symfony2, las URL son
incluso ms flexibles.
Por ahora, la aplicacin ha evolucionado de un nico archivo PHP, a una
estructura organizada que permite la reutilizacin de cdigo. Debes estar contento,
pero an lejos de estar satisfecho. Por ejemplo, el sistema de enrutamiento es
muy mejorable, ya que no reconoce por ejemplo que la pginalist (/index.php)
tambin debe ser accesible a travs de / (si has agregado las reglas de
reescritura de Apache). Adems, en lugar de programar el blog, has perdido tu
tiempo en preparar la "arquitectura" del cdigo (por ejemplo, el enrutamiento, los
controladores, las plantillas, etc.) Y pronto tendrs que perder ms tiempo en la
gestin de los formularios, la validacin de la informacin, crear un archivo de log,
la gestin de la seguridad, etc.
Por qu tienes que dedicarte a solucionar estos problemas que se repiten una y
otra vez en todos los proyectos?
2.3.2. Aadiendo un toque de Symfony2
Symfony2 al rescate! Antes de utilizar Symfony2, debes descargar sus archivos.
Para ello se utiliza la herramienta llamada Composer, que se encarga de
descargar la versin correcta de los archivos de Symfony, todas sus dependencias
y tambin proporciona un cargador automtico de clases (llamadoclass loader en
ingls). Un cargador automtico es una herramienta que permite empezar a utilizar
clases PHP sin incluir explcitamente el archivo que contiene la clase.
Dentro del directorio raz del proyecto crea un archivo llamado composer.json con
el siguiente contenido:
{
"require": {
"symfony/symfony": "2.4.*"
},
"autoload": {
"files": ["model.php","controllers.php"]
}
}
A continuacin, descarga Composer y ejecuta despus el siguiente cdigo para
descargar Symfony dentro del directorio vendor/ del proyecto:
$ php composer.phar install
Adems de descargar todas las dependencias, Composer genera un archivo
llamadovendor/autoload.php, que se encarga de cargar automticamente todas las
clases del frameworkSymfony y de todas las libreras que aadas en la
seccin autoload del archivo composer.json.
La esencia de la filosofa Symfony es que el trabajo principal de una aplicacin es
interpretar cada peticin y devolver una respuesta. Con este fin, Symfony2
proporciona las clases Request y Response. Estas clases son representaciones
orientadas a objetos de la peticin HTTP que se est procesando y la respuesta
HTTP que se devolver. salas para mejorar el blog:
<?php
// index.php
require_once 'vendor/autoload.php';

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

$request = Request::createFromGlobals();

$uri = $request->getPathInfo();
if ($uri == '/') {
$response = list_action();
} elseif ($uri == '/show' && $request->query->has('id')) {
$response = show_action($request->query->get('id'));
} else {
$html = '<html><body><h1>Page Not Found</h1></body></html>';
$response = new Response($html, Response::HTTP_NOT_FOUND);
}

// enva las cabeceras y la respuesta
$response->send();
Los controladores se encargan de devolver un objeto Response. Para simplificar la
generacin del cdigo HTML de la respuesta, crea una nueva funcin
llamada render_template(), la cual, por cierto, acta un poco como el motor de
plantillas de Symfony2:
// controllers.php
use Symfony\Component\HttpFoundation\Response;

function list_action()
{
$posts = get_all_posts();
$html = render_template('templates/list.php', array('posts' => $posts));

return new Response($html);
}

function show_action($id)
{
$post = get_post_by_id($id);
$html = render_template('templates/show.php', array('post' => $post));

return new Response($html);
}

// funcin ayudante para reproducir plantillas
function render_template($path, array $args)
{
extract($args);
ob_start();
require $path;
$html = ob_get_clean();

return $html;
}
Aunque solo ha aadido una pequesima parte de las ideas de Symfony2, la
aplicacin ahora es ms flexible y fiable. El objeto Request proporciona una
manera segura para acceder a la informacin de la peticin HTTP. El
mtodo getPathInfo() por ejemplo devuelve una URI limpia (siempre
devolviendo/show y nunca /index.php/show).
Por lo tanto, incluso si el usuario va a /index.php/show, la aplicacin es lo
suficientemente inteligente para encaminar la peticin hacia show_action().
El objeto Response proporciona flexibilidad al construir la respuesta HTTP,
permitiendo que las cabeceras HTTP y el contenido se definan a travs de una
interfaz orientada a objetos.
Y aunque las respuestas en esta aplicacin son simples, esta flexibilidad ser muy
til en cuanto tu aplicacin crezca.
2.3.3. Aplicacin de ejemplo en Symfony2
El blog ha mejorado bastante, pero todava contiene una gran cantidad de cdigo
para ser una aplicacin tan simple. Durante las mejoras de la aplicacin, se ha
creado un sistema de enrutamiento muy sencillo y otro mtodo que
utiliza ob_start() y ob_get_clean() para procesar plantillas. Si vas a continuar
desarrollando este blog, lo mejor es que utilices los
componentes Routing y Templating de Symfony para mejorar esa parte sin
esfuerzo.
En lugar de resolver de nuevo los mismos problemas de siempre, deja que
Symfony2 se encargue de ellos por ti. Aqu est la misma aplicacin de ejemplo,
pero construida ahora con Symfony2:
<?php
// src/Acme/BlogBundle/Controller/BlogController.php

namespace Acme\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class BlogController extends Controller
{
public function listAction()
{
$posts = $this->get('doctrine')
->getManager()
->createQuery('SELECT p FROM AcmeBlogBundle:Post p')
->execute();

return $this->render('AcmeBlogBundle:Blog:list.html.php', array('pos
ts' => $posts));
}

public function showAction($id)
{
$post = $this->get('doctrine')
->getManager()
->getRepository('AcmeBlogBundle:Post')
->find($id);

if (!$post) {
// hace que se muestre la pgina de error 404
throw $this->createNotFoundException();
}

return $this->render('AcmeBlogBundle:Blog:show.html.php', array('pos
t' => $post));
}
}
Los dos controladores siguen siendo ms o menos pequeos. Cada uno utiliza la
librera ORM de Doctrine para recuperar objetos de la base de datos y el
componente Templating para generar el cdigo HTML con una plantilla y devolver
un objeto Response. La plantilla list ahora es un poco ms simple:
<!-- src/Acme/BlogBundle/Resources/views/Blog/lista.html.php -->
<?php $view->extend('::base.html.php') ?>

<?php $view['slots']->set('title', 'List of Posts') ?>

<h1>List of Posts</h1>
<ul>
<?php foreach ($posts as $post): ?>
<li>
<a href="<?php echo $view['router']->generate('blog_show', array('id
' => $post->getId())) ?>">
<?php echo $post->getTitle() ?>
</a>
</li>
<?php endforeach; ?>
</ul>
Y el diseo de la plantilla base tambin es muy parecido al de antes:
<!-- app/Resources/views/base.html.php -->
<html>
<head>
<title><?php echo $view['slots']->output('title', 'Default title') ?></t
itle>
</head>
<body>
<?php echo $view['slots']->output('_content') ?>
</body>
</html>
NOTA Te vamos a dejar como ejercicio la plantilla show, porque debera ser trivial
crearla basndote en la plantilla list.
Cuando arranca el motor de Symfony2 (llamado kernel), necesita un mapa para
saber qu controladores ejecutar en base a la informacin solicitada por los
usuarios. Este mapa se crea con la configuracin de enrutamiento, que
proporciona esta informacin en formato legible:
# app/config/routing.yml
blog_list:
path: /blog
defaults: { _controller: AcmeBlogBundle:Blog:list }

blog_show:
path: /blog/show/{id}
defaults: { _controller: AcmeBlogBundle:Blog:show }
Ahora que Symfony2 se encarga de todas las tareas repetitivas, el controlador
frontal es muy simple. Y ya que hace tan poco, nunca tienes que volver a tocarlo
una vez creado (y si utilizas una distribucin Symfony2, ni siquiera tendrs que
crearlo!):
<?php
// web/app.php
require_once __DIR__.'/../app/bootstrap.php';
require_once __DIR__.'/../app/AppKernel.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new AppKernel('prod', false);
$kernel->handle(Request::createFromGlobals())->send();
El nico trabajo del controlador frontal es iniciar el motor de Symfony2 (Kernel) y
pasarle un objetoRequest para que lo manipule. Despus, el ncleo de Symfony2
utiliza la informacin de enrutamiento para determinar qu controlador se ejecuta.
Al igual que antes, el mtodo controlador es el responsable de devolver el
objeto Response final. Y eso es todo lo que hace el controlador frontal.
2.3.4. Qu ms ofrece Symfony2
En los siguientes captulos, aprenders ms acerca de cmo funciona cada parte
de Symfony y la organizacin recomendada de un proyecto. Ahora vamos a ver
cmo nos ha facilitado nuestro trabajo de programadores el migrar el blog de PHP
simple a Symfony2:
Tu aplicacin cuenta con cdigo claro y bien organizado (aunque Symfony
no te obliga a ello). Esto facilita la reutilizacin de cdigo y permite a los
nuevos desarrolladores ser productivos en el proyecto con mayor rapidez.
El 100% del cdigo que escribes es para tu aplicacin. No necesitas
desarrollar o mantener herramientas de bajo nivel como la carga
automtica de clases, el enrutamiento o los controladores.
Symfony2 te proporciona acceso a herramientas de software libre tales
como Doctrine, plantillas, seguridad, formularios, validacin y traduccin (por
nombrar algunas).
La aplicacin ahora dispone de URLs totalmente flexibles gracias al
componente Routing.
La arquitectura centrada en HTTP de Symfony2 te da acceso a herramientas
muy potentes, como por ejemplo la cach HTTP (mediante la cach HTTP
interna de Symfony2 o mediante herramientas ms avanzadas
como Varnish). Esto se explica ms adelante en el captulo sobre la cach.
Y lo mejor de todo, utilizando Symfony2, ahora tienes acceso a un conjunto de
herramientas desoftware libre de alta calidad desarrolladas por la comunidad
Symfony2!
Puedes encontrar una buena coleccin de herramientas comunitarias de
Symfony2 enKnpBundles.com.
2.4. Mejorando las plantillas
Si quieres utilizarlo, Symfony2 incluye de serie un motor de plantillas
llamado Twig que hace que las plantillas se escriban ms rpido y sean ms
fciles de leer.
En otras palabras, la aplicacin de ejemplo desarrollada anteriormente podra
incluso tener menos cdigo. Considera por ejemplo la siguiente
plantilla list reescrita con Twig:
{# src/Acme/BlogBundle/Resources/views/Blog/list.html.twig #}

{% extends "::base.html.twig" %}
{% block title %}List of Posts{% endblock %}

{% block body %}
<h1>List of Posts</h1>
<ul>
{% for post in posts %}
<li>
<a href="{{ path('blog_show', { 'id': post.id }) }}">
{{ post.title }}
</a>
</li>
{% endfor %}
</ul>
{% endblock %}
Tambin es muy fcil escribir la plantilla base.html.twig correspondiente:
{# app/Resources/views/base.html.twig #}

<html>
<head>
<title>{% block title %}Default title{% endblock %}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
Twig est completamente integrado en Symfony2. Aunque Symfony2 siempre
soportar las plantillas PHP, en los siguientes captulos se van a seguir
presentando algunas de las muchas ventajas de Twig respecto a las plantillas
PHP. Para ms informacin, consulta el captulo sobre las plantillas.
Captulo 4. Creando pginas en Symfony2
Crear una nueva pgina en Symfony2 es un proceso muy sencillo de dos pasos:
Crear una ruta: una ruta define la URL de tu pgina (por ejemplo /sobre) y
especifica el controlador (que en realidad es una funcin PHP) que Symfony2
ejecuta cuando la URL de la peticin del usuario coincida con el patrn de la
ruta.
Crear un controlador: un controlador es una funcin PHP que obtiene la
peticin del usuario y la transforma en el objeto Response con el que Symfony2
crea la respuesta que se enva al usuario .
Nos encanta este enfoque simple porque coincide con la forma en que funciona la
Web. Cada interaccin en la Web se inicia con una peticin HTTP. El trabajo de la
aplicacin simplemente es interpretar la peticin y devolver la respuesta HTTP
adecuada.
Symfony2 sigue esta filosofa y te proporciona las herramientas y convenciones
para mantener organizada tu aplicacin a medida que crece en usuarios y
complejidad.
4.1. La pgina Hola Symfony!
Vamos a empezar con una aplicacin derivada del clsico "Hola Mundo!". Cuando
hayamos terminado, el usuario podr recibir un saludo personal (por
ejemplo, "Hola Symfony") al ir a la siguiente URL:
http://localhost/app_dev.php/hello/Symfony
Ms adelante podrs sustituir la palabra Symfony con cualquier otro nombre al que
darle la bienvenida. Para crear la pgina, sigue el proceso simple de dos pasos.
NOTA Este captulo supone que ya has descargado Symfony2 y configurado tu
servidor web. En la URL del ejemplo anterior se supone que localhost apunta al
directorio web de tu nuevo proyecto Symfony2. Para obtener una informacin ms
detallada sobre cmo hacerlo, consulta la documentacin del servidor Web que
ests usando.
Estos son los enlaces a las pginas de documentacin adecuadas para los dos
servidores web ms populares:
Para el servidor Apache, consulta la documentacin de Apache sobre
DirectoryIndex.
Para Nginx, consulta la documentacin de ubicacin HttpCoreModule de
Nginx.
4.2. Antes de empezar, crea el bundle
Antes de empezar, tendrs que crear un bundle (que se podra traducir
como "paquete"). En Symfony2, un bundle es como un plugin, con la salvedad de
que todo el cdigo de tu aplicacin se almacena dentro de bundles.
Un bundle no es ms que un directorio que almacena todo lo relacionado con una
funcin especfica, incluyendo clases PHP, configuracin, e incluso hojas de estilo
y archivos de Javascript.
Para crear un bundle llamado AcmeHelloBundle (el bundle de ejemplo que vamos a
construir en este captulo), ejecuta el siguiente comando y sigue las instrucciones
en pantalla (acepta todas las opciones predeterminadas):
$ php app/console generate:bundle --namespace=Acme/HelloBundle --format=yml
Sin que te des cuenta, se ha creado un directorio para el bundle
en src/Acme/HelloBundle. Adems se ha aadido automticamente una lnea en el
archivo app/AppKernel.php para registrar el bundle en el ncleo de Symfony:
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
...,
new Acme\HelloBundle\AcmeHelloBundle(),
);
// ...

return $bundles;
}
Ahora que ya est configurado el bundle, puedes comenzar a construir tu
aplicacin dentro del bundle.
4.2.1. Paso 1: Creando la ruta
Por defecto, el archivo de configuracin de enrutamiento en una aplicacin
Symfony2 se encuentra enapp/config/routing.yml. Si lo prefieres, y al igual que
en el resto de la configuracin en Symfony2, puedes utilizar el formato XML o PHP
para configurar tus rutas.
Si te fijas en el archivo de enrutamiento principal, vers que Symfony ya ha
agregado una entrada al generar el bundle AcmeHelloBundle:
YAML
XML
PHP
# app/config/routing.yml
acme_hello:
resource: "@AcmeHelloBundle/Resources/config/routing.yml"
prefix: /
Esta directiva de configuracin le dice a Symfony que cargue la configuracin de
enrutamiento del archivo Resources/config/routing.yml que se encuentra en el
interior del bundle AcmeHelloBundle.
En otras palabras, puedes configurar tus rutas directamente en el
archivo app/config/routing.yml o puedes definirlas en varias partes de la
aplicacin y despus las importas desde ese archivo.
Ahora que el archivo routing.yml del bundle se importa desde el archivo de
enrutamiento principal de la aplicacin, aade la nueva ruta que define la URL de
la pgina que ests a punto de crear:
YAML
XML
PHP
# src/Acme/HelloBundle/Resources/config/routing.yml
hello:
path: /hello/{name}
defaults: { _controller: AcmeHelloBundle:Hello:index }
La ruta se compone bsicamente de dos partes: el path, que es la URL con la que
debe coincidir la peticin del usuario para activar la ruta, y un array
llamado defaults, que especifica el controlador que se ejecuta. Las partes de la
URL encerradas entre comillas indican que su valor puede variar. De esta
forma, {name} significa que las URL /hello/Ryan, /hello/Fabien o cualquier otra
URI similar coincidir con esta ruta. El valor de las partes variables tambin se
pasa al controlador, que puede acceder a ellos a travs del nombre asignado en la
propia ruta (name en este caso).
NOTA El sistema de enrutamiento tiene muchas ms caractersticas para crear URI
flexibles y avanzadas en tu aplicacin. Para ms detalles, consulta el captulo de
enrutamiento.
4.2.2. Paso 2: Creando el controlador
Cuando el usuario solicita la URL /hello/Ryan, se activa la ruta hello, a la que
corresponde el controlador AcmeHelloBundle:Hello:index, que es realmente el
cdigo que se ejecuta. El segundo paso del proceso de creacin de pginas
consiste precisamente en crear ese controlador.
La cadena AcmeHelloBundle:Hello:index es el nombre lgico del controlador, que
se traduce como el mtodo indexAction() de una clase PHP
llamada Acme\HelloBundle\Controller\Hello. Crea en primer lugar este archivo
dentro de tu bundle AcmeHelloBundle:
// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;

use Symfony\Component\HttpFoundation\Response;

class HelloController
{
}
En realidad, el controlador no es ms que un mtodo PHP que t creas y Symfony
ejecuta. Aqu es donde el cdigo utiliza la informacin de la peticin para construir
y preparar el recurso solicitado. Salvo en algunos casos avanzados, el resultado
final de un controlador siempre es el mismo: un objeto Response de Symfony2.
Crea el mtodo indexAction que Symfony ejecutar cuando se sirva la ruta hello:
// src/Acme/HelloBundle/Controller/HelloController.php

// ...
class HelloController
{
public function indexAction($name)
{
return new Response('<html><body>Hello '.$name.'!</body></html>');
}
}
El controlador es muy sencillo: crea un nuevo objeto de tipo Response y cuyo
primer argumento es el contenido que se utiliza para crear la respuesta enviada al
usuario (en este caso, una pgina HTML muy simple).
Enhorabuena! Despus de crear solamente una ruta y un controlador ya tienes
una pgina completamente funcional! Si todo lo has configurado correctamente, la
aplicacin debe darte la bienvenida al acceder a la siguiente URL:
http://localhost/app_dev.php/hello/Ryan
TRUCO Tambin puedes ver tu aplicacin en el entorno prod o de produccin
visitando:
http://localhost/app.php/hello/Ryan
Si se produce un error, probablemente sea porque necesitas vaciar la cach de
produccin ejecutando el siguiente comando:
php app/console cache:clear --env=prod --no-debug
El tercer y ltimo paso para crear una pgina es opcional pero casi todas las
aplicaciones lo hacen: crear una plantilla.
NOTA Los controladores son el punto de entrada principal a tu cdigo y la clave en
la creacin de pginas. Puedes encontrar mucha ms informacin en el captulo
dedicado a los controladores.
4.2.3. Paso 3 opcional: Creando la plantilla
Las plantillas te permiten mover toda la parte de la vista (es decir, el cdigo HTML)
a un archivo separado y reutilizar diferentes partes del diseo de la pgina. En vez
de escribir el cdigo HTML dentro del controlador, genera el cdigo HTML a partir
de una plantilla:
// src/Acme/HelloBundle/Controller/HelloController.php
namespace Acme\HelloBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class HelloController extends Controller
{
public function indexAction($name)
{
return $this->render('AcmeHelloBundle:Hello:index.html.twig', array(
'name' => $name));

// si utilizas PHP en vez de Twig
// return $this->render('AcmeHelloBundle:Hello:index.html.php', arra
y('name' => $name));
}
}
NOTA Para poder usar el mtodo render(), tu controlador debe extender de la
claseSymfony\Bundle\FrameworkBundle\Controller\Controller, la cual aade atajos
para las tareas ms comunes de los controladores. Esto se hace en el ejemplo
anterior aadiendo la declaracin usedebajo del namespace y luego aadiendo
el extends Controller a la clase.
El mtodo render() crea un objeto Response y le aade el contenido resultante de
renderizar la plantilla. As que como cualquier otro controlador, el cdigo anterior
realmente est devolviendo un objeto de tipo Response.
Ten en cuenta que puedes procesar las plantillas de dos formas diferentes. Por
defecto Symfony2 admite dos lenguajes de plantillas: las clsicas plantillas
creadas con PHP y las nuevas y concisas plantillas creadas con Twig. No te
asustes porque puedes elegir libremente cul utilizar o incluso mezclar las dos en
el mismo proyecto.
Al procesar la plantilla AcmeHelloBundle:Hello:index.html.twig, el controlador
utiliza la siguiente convencin de nomenclatura:
NombreBundle:NombreControlador:NombrePlantilla
Este es el nombre lgico de la plantilla, que se traduce a un archivo fsico
utilizando la siguiente convencin:
</ruta/a/Nombrebundle>/Resources/views/<NombreControlador>/<NombrePlantilla>
En este caso, AcmeHelloBundle es el nombre del bundle, Hello es el controlador
e index.html.twig la plantilla:
{# src/Acme/HelloBundle/Resources/views/Hello/index.html.twig #}
{% extends '::base.html.twig' %}

{% block body %}
Hello {{ name }}!
{% endblock %}
<!-- src/Acme/HelloBundle/Resources/views/Hello/index.html.php -->
<?php $view->extend('::base.html.php') ?>

Hello <?php echo $view->escape($name) ?>!
Veamos la situacin a travs de la plantilla Twig lnea por lnea:
La etiqueta extends indica que se utiliza una plantilla padre donde se define el
diseo del sitio web.
La etiqueta block indica que todo su contenido se debe colocar dentro de un
bloque llamado body. Como se explicar ms adelante, la plantilla padre
(base.html.twig) es la responsable de definir ese bloque y de mostrarlo en la
pgina HTML adecuadamente.
La plantilla padre se indica como ::base.html.twig, por lo que no incluye ni la
parte del nombre del bundle ni la del nombre del controlador (de ah los dos
puntos dobles (::) al principio). Esto significa que la plantilla no se encuentra
dentro de ningn bundle, sino en el directorio app del proyecto:
{# app/Resources/views/base.html.twig #}
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{% block title %}Welcome!{% endblock %}</title>
{% block stylesheets %}{% endblock %}
<link rel="shortcut icon" href="{{ asset('favicon.ico') }}" />
</head>
<body>
{% block body %}{% endblock %}
{% block javascripts %}{% endblock %}
</body>
</html>
<!-- app/Resources/views/base.html.php -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><?php $view['slots']->output('title', 'Welcome!') ?></title>
<?php $view['slots']->output('stylesheets') ?>
<link rel="shortcut icon" href="<?php echo $view['assets']->getUrl('favi
con.ico') ?>" />
</head>
<body>
<?php $view['slots']->output('_content') ?>
<?php $view['slots']->output('stylesheets') ?>
</body>
</html>
El archivo de la plantilla base define el diseo HTML y muestra el contenido del
bloque body que se defini en la plantilla index.html.twig. Tambin muestra el
contenido de un bloque llamado title, que si quieres puedes definir en la
plantilla index.html.twig. Como no has definido ese bloque en la plantilla, se
utiliza el valor predeterminado "Welcome!".
Las plantillas son realmente tiles para generar y organizar el contenido de las
pginas de la aplicacin. Una plantilla puede generar cualquier cosa, desde el
cdigo HTML o CSS hasta cualquier otra cosa que el controlador tenga que
devolver.
Dentro del ciclo peticin/respuesta, el motor de plantillas simplemente es una
herramienta opcional. Recuerda que el objetivo de cada controlador es devolver
un objeto Response. As que por muy potentes que sean, las plantillas son solo una
forma opcional de generar ese objeto Response.
4.3. La estructura de directorios
Las secciones anteriores explican la filosofa en la que se basa la creacin y
procesamiento de pginas en Symfony2. Tambin se ha mencionado cmo estn
estructurados y organizados los proyectos Symfony2. Al final de esta seccin,
sabrs dnde encontrar y colocar diferentes tipos de archivos y por qu.
Aunque se puede cambiar, por defecto todas las aplicaciones Symfony tienen la
misma estructura de directorios sencilla (y recomendada):
app/: contiene la configuracin de la aplicacin.
src/: aqu se encuentra todo el cdigo PHP de la aplicacin.
vendor/: por convencin aqu se guardan todas las libreras creadas por
terceros.
web/: este es el directorio web raz y contiene todos los archivos que se
pueden acceder pblicamente.
4.3.1. El directorio web
El directorio web raz es el lugar donde se encuentran todos los archivos pblicos
y estticos tales como imgenes, hojas de estilo y archivos JavaScript. Tambin
es el lugar donde se definen todos los controladores frontales, como por ejemplo
el siguiente:
// web/app.php
require_once __DIR__.'/../app/bootstrap.php.cache';
require_once __DIR__.'/../app/AppKernel.php';

use Symfony\Component\HttpFoundation\Request;

$kernel = new AppKernel('prod', false);
$kernel->loadClassCache();
$kernel->handle(Request::createFromGlobals())->send();
El archivo del controlador frontal (app.php en este ejemplo) es el archivo PHP que
realmente se ejecuta cuando utilizas una aplicacin Symfony2 y su trabajo
consiste en arrancar la aplicacinutilizando una clase del ncleo (AppKernel).
TRUCO Tener un controlador frontal significa que se utilizan URL diferentes y ms
flexibles que las de una aplicacin PHP tpica. Cuando se dispone de un
controlador frontal, las URL se formatean de la siguiente manera:
http://localhost/app.php/hello/Ryan
El controlador frontal, app.php, se ejecuta y la URL interna: /hello/Ryan se dirige
internamente segn la configuracin de enrutamiento.
Si adems utilizas el mdulo mod_rewrite de Apache, puedes forzar la ejecucin
del archivo app.phpsin necesidad de incluirlo en la URL, por lo que as las URL son
todava ms limpias:
http://localhost/hello/Ryan
Aunque los controladores frontales son esenciales para servir cada peticin, rara
vez los tendrs que modificar o incluso pensar en ellos. Los mencionaremos
brevemente de nuevo en la seccin dedicada a los entornos de ejecucin.
4.3.2. El directorio de la aplicacin (app)
Como vimos en el controlador frontal, la clase AppKernel es el punto de entrada
principal de la aplicacin y es la responsable de toda la configuracin. Como tal,
se almacena en el directorio app/.
Esta clase debe implementar dos mtodos que definen todo lo que Symfony
necesita saber acerca de tu aplicacin. Ni siquiera tienes que preocuparte de
estos mtodos durante el arranque Symfony los rellena por ti con parmetros
predeterminados.
registerBundles(): devuelve un array con todos los bundles necesarios para
ejecutar la aplicacin.
registerContainerConfiguration(): carga el archivo de configuracin de
recursos de la aplicacin (consulta la seccin Configurando la aplicacin).
Durante el desarrollo de una aplicacin, normalmente el directorio app/ solo los
utilizas para modificar la configuracin y los archivos de enrutamiento en el
directorio app/config/ (consulta la seccinConfigurando la aplicacin).
Este directorio tambin contiene el directorio cach de la aplicacin (app/cache), un
directorio de logs(app/logs) y un directorio para archivos de recursos globales,
tales como plantillas (app/Resources). Aprenders ms sobre cada uno de estos
directorios en captulos posteriores.
Carga automticaAl arrancar Symfony, se incluye un archivo especial
llamado vendor/autoload.php. Este archivo, creado por Composer, se encarga de
configurar el cargador automtico de clases, que a su vez carga automticamente
todos los archivos de tu aplicacin que se encuentren en el directorio src/ y todas
las libreras externas configuradas en el archivo composer.json.
Gracias al cargador automtico, nunca tendrs que preocuparte de usar
declaraciones include orequire. Esto es posible porque Composer
utiliza namespace o espacio de nombres de una clase para determinar su
ubicacin y as incluye automticamente el archivo en el instante en que necesitas
una clase.
El cargador automtico ya est configurado para buscar cualquiera de tus clases
PHP en el directorio src/. Para que funcione la carga automtica, el nombre de la
clase y la ruta del archivo deben seguir el mismo patrn:
Nombre de la clase: Acme\HelloBundle\Controller\HelloController
Ruta fsica del
archivo: src/Acme/HelloBundle/Controller/HelloController.php
4.3.3. El directorio fuente (src)
En pocas palabras, el directorio src/ contiene todo el cdigo real (cdigo PHP,
plantillas, archivos de configuracin, estilos, etc.) que pertenece a tu aplicacin.
De hecho, al programar una aplicacin Symfony, la mayor parte de tu trabajo se
llevar a cabo dentro de uno o ms bundles creados en este directorio.
Pero, qu es exactamente un bundle?
4.4. El sistema de bundles
Un bundle es un concepto similar al de los plugins en otras aplicaciones, pero
todava mejor. La diferencia clave es que en Symfony2 todo es un bundle,
incluyendo tanto la funcionalidad bsica de la plataforma como el cdigo escrito
para tu aplicacin.
Los bundles son la parte ms importante de Symfony2. Permiten utilizar
funcionalidades construidas por terceros o empaquetar tus propias funcionalidades
para distribuirlas y reutilizarlas en otros proyectos. Adems, facilitan mucho la
activacin o desactivacin de determinadas caractersticas dentro de una
aplicacin.
NOTA En esta seccin solo se va a explicar lo bsico, pero hay un captulo
dedicado completamente al tema de los bundles.
Un bundle simplemente es un conjunto estructurado de archivos que se
encuentran en un directorio y que implementan una sola caracterstica. Puedes
crear por ejemplo un BlogBundle, un ForoBundle o un bundle para gestionar
usuarios (muchos de ellos ya existen como bundles de software libre). Cada
directorio contiene todo lo relacionado con esa caracterstica, incluyendo archivos
PHP, plantillas, hojas de estilo, archivos Javascript, tests y cualquier otra cosa
necesaria.
Las aplicaciones Symfony se componen de bundles, tal como se define en el
mtodoregisterBundles() de la clase AppKernel:
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Symfony\Bundle\SwiftmailerBundle\SwiftmailerBundle(),
new Symfony\Bundle\DoctrineBundle\DoctrineBundle(),
new Symfony\Bundle\AsseticBundle\AsseticBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
);

if (in_array($this->getEnvironment(), array('dev', 'test'))) {
$bundles[] = new Acme\DemoBundle\AcmeDemoBundle();
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(
);
$bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistribution
Bundle();
$bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle
();
}

return $bundles;
}
Con el mtodo registerBundles(), puedes controlar completamente los bundles
que utiliza tu aplicacin, incluso aquellos bundles que forman el ncleo del
framework.
TRUCO Un bundle se puede encontrar en cualquier directorio, siempre y cuando
Symfony2 lo pueda cargar automticamente (con el autocargador configurado
en app/autoload.php).
4.4.1. Creando un bundle
La edicin estndar de Symfony incluye un comando para crear bundles
totalmente funcionales de una manera muy sencilla. Por supuesto, tambin
puedes crear los bundles a mano si lo prefieres.
Para mostrarte lo sencillo que es el sistema de bundles, vamos a crear a mano y
activar un nuevo bundle llamado AcmeTestBundle.
TRUCO La parte Acme es slo un nombre ficticio que debes sustituir por el nombre
del proveedor del bundle, es decir, el nombre o siglas de tu empresa (por
ejemplo, ABCTestBundle si la empresa se llama ABC). Si es un bundle personal,
puedes utilizar tu nombre completo o las iniciales.
En primer lugar, crea un directorio src/Acme/TestBundle/ y aade un nuevo archivo
llamadoAcmeTestBundle.php::
// src/Acme/TestBundle/AcmeTestBundle.php
namespace Acme\TestBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class AcmeTestBundle extends Bundle
{
}
TRUCO El nombre AcmeTestBundle sigue las convenciones estndar de
nomenclatura de bundles. Tambin puedes optar por acortar el nombre del bundle
simplemente a TestBundle al nombrar esta clase TestBundle (y el nombre del
archivo TestBundle.php).
Esta clase vaca es lo nico que necesitamos para crear nuestro nuevo bundle.
Aunque normalmente est vaca, esta clase te permite personalizar el
comportamiento del bundle.
Ahora que hemos creado nuestro bundle, tenemos que activarlo a travs de la
clase AppKernel:
// app/AppKernel.php
public function registerBundles()
{
$bundles = array(
...,

// registra tus bundles
new Acme\TestBundle\AcmeTestBundle(),
);
// ...

return $bundles;
}
Aunque todava no hace nada, el bundle AcmeTestBundle ya est listo para
utilizarlo.
Generar un bundle a mano es bastante sencillo, pero Symfony tambin
proporciona un comando para generar la estructura bsica del bundle:
php app/console generate:bundle --namespace=Acme/TestBundle
Como resultado este comando genera el esqueleto del bundle formado por un
controlador bsico, la plantilla y la configuracin del enrutamiento. Ms adelante
se explica en detalle la consola de comandos de Symfony2.
TRUCO Cuando crees un nuevo bundle o uses un bundle de terceros, asegrate
siempre de habilitar el bundle en el mtodo registerBundles(). El
comando generate:bundle se encarga de hacerlo automticamente.
4.4.2. Estructura de directorios de un bundle
La estructura de directorios de un bundle es simple y flexible. Por defecto el
sistema de bundles sigue una serie de convenciones que ayudan a mantener el
cdigo consistente entre todos los bundles Symfony2. Echa un vistazo
a AcmeHelloBundle, ya que contiene algunos de los elementos ms comunes de un
bundle:
Controller/: contiene los controladores del bundle (por
ejemplo, HelloController.php).
DependencyInjection/: contiene elementos relacionados con el contenedor de
inyeccin de dependencias, un concepto muy avanzado que se explicar ms
adelante. Entre otras, contiene las extensiones para las clases de inyeccin
de dependencias, la configuracin que importan los servicios y registra uno o
ms pases del compilador (este directorio no es obligatorio).
Resources/config/: contiene la configuracin, incluyendo la configuracin de
enrutamiento (por ejemplo, routing.yml).
Resources/views/: contiene las plantillas organizadas segn el nombre del
controlador (por ejemplo, Hello/index.html.twig).
Resources/public/: contiene recursos web (imgenes, hojas de estilo, etc.) y
es copiado o enlazado simblicamente al directorio web/ del proyecto con el
comando assets:install.
Tests/: tiene los tests unitarios y funcionales del bundle.
Un bundle puede ser tan pequeo o tan grande como sea necesario.
A medida que avances en el libro, aprenders cmo persistir objetos a una base
de datos, crear y validar formularios, crear traducciones para tu aplicacin, escribir
tests y mucho ms. Cada uno de estos tiene su propio lugar y rol dentro del
bundle.
4.5. Configurando la aplicacin
La aplicacin est formada por una coleccin de bundles que representan todas
las caractersticas y capacidades de tu aplicacin. Cada bundle se puede
personalizar a travs de archivos de configuracin escritos en YAML, XML o PHP.
De forma predeterminada, el archivo de configuracin principal se encuentra en el
directorio app/config/ y se llama config.yml, config.xml o config.php en funcin
del formato que prefieras:
YAML
XML
PHP
# app/config/config.yml
imports:
- { resource: parameters.yml }
- { resource: security.yml }

framework:
secret: "%secret%"
router: { resource: "%kernel.root_dir%/config/routing.yml" }
# ...

# Twig Configuration
twig:
debug: "%kernel.debug%"
strict_variables: "%kernel.debug%"

# ...
NOTA Aprenders cmo cargar cada archivo y formato en la siguiente seccin
dedicada a los entornos de ejecucin.
Cada opcin de nivel superior como framework o twig define la configuracin de un
bundle especfico. Por ejemplo, la clave framework define la configuracin para el
ncleo de Symfony FrameworkBundle e incluye la configuracin de enrutamiento,
plantillas, y otros elementos del ncleo.
No te preocupes por el momento de las opciones de configuracin especficas de
cada seccin, ya que el archivo de configuracin viene con parmetros
predeterminados. A medida que leas y explores ms cada parte de Symfony2,
aprenders sobre las opciones de configuracin especficas de cada
caracterstica.
Formatos de configuracinA lo largo de los captulos, todos los ejemplos de
configuracin muestran los tres formatos (YAML, XML y PHP). Cada uno tiene sus
propias ventajas y desventajas. T eliges cual utilizar:
YAML: sencillo, limpio y fcil de leer.
XML: ms poderoso que YAML y permite el autocompletado del IDE.
PHP: el ms potente, pero menos fcil de leer que los formatos de
configuracin estndar.
4.5.1. Obteniendo la configuracin por defecto
El nuevo comando config:dump-reference te permite volcar a la consola toda la
configuracin por defecto de un bundle en formato YAML. El siguiente ejemplo
muestra cmo volcar la configuracin delbundle FrameworkBundle:
$ app/console config:dump-reference FrameworkBundle
En vez de el nombre completo del bundle, tambin puedes utilizar el nombre de su
opcin de configuracin principal:
$ app/console config:dump-reference framework
4.6. Entornos
Una aplicacin puede funcionar en diversos entornos. Los diferentes entornos
comparten el mismo cdigo PHP (solo es diferente el controlador frontal), pero
usan una configuracin diferente. Por ejemplo, un entorno de
desarrollo dev guarda las advertencias y errores, mientras que un entorno de
produccin prod slo registra los errores. Algunos archivos se vuelven a generar
en cada peticin en el entorno dev (para mayor comodidad de los desarrolladores),
pero se cachean en el entorno prod. Todos los entornos se encuentran en la
misma mquina y ejecutan la misma aplicacin.
Un proyecto Symfony2 normalmente comienza con tres entornos
(dev, test y prod), aunque resulta sencillo crear nuevos entornos. Puedes ver tu
aplicacin en diferentes entornos con slo cambiar el controlador frontal en tu
navegador. Para ver la aplicacin en el entorno dev, accede a la aplicacin a
travs del controlador frontal de desarrollo:
http://localhost/app_dev.php/hello/Ryan
Si deseas ver cmo se comportar tu aplicacin en el entorno de produccin,
utiliza en su lugar el controlador frontal prod:
http://localhost/app.php/hello/Ryan
Como el entorno prod est optimizado para ser muy rpido, la configuracin, el
enrutamiento y las plantillas Twig se compilan en clases PHP simples y se
guardan en cach.
Si haces cualquier cambio en las plantillas, no lo vers en el entorno prod a menos
que borres la cache de la aplicacin y as fuerces a Symfony a volver a compilar
las plantillas. Para borrar la cache del entorno de produccin, ejecuta el siguiente
comando de consola:
php app/console cache:clear --env=prod --no-debug
NOTA Si abres el archivo web/app.php, vers que est configurado explcitamente
para usar el entorno prod:
$kernel = new AppKernel('prod', false);
Puedes crear un nuevo controlador frontal para un nuevo entorno copiando el
archivo y cambiandoprod por algn otro valor.
NOTA El entorno test se utiliza cuando se ejecutan tests automticas y no se
puede acceder directamente a travs del navegador. Consulta el captulo dedicado
a los tests para obtener ms informacin.
4.6.1. Configurando entornos
La clase AppKernel es realmente la responsable de cargar el archivo de
configuracin segn el controlador que utilices:
// app/AppKernel.php
public function registerContainerConfiguration(LoaderInterface $loader)
{
$loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml');
}
Ya sabes que la extensin .yml se puede cambiar a .xml o .php si prefieres usar
XML o PHP para escribir tu configuracin. Adems, observa que cada entorno
carga su propio archivo de configuracin. Considera el archivo de configuracin
para el entorno dev.
YAML
XML
PHP
# app/config/config_dev.yml
imports:
- { resource: config.yml }

framework:
router: { resource: "%kernel.root_dir%/config/routing_dev.yml" }
profiler: { only_exceptions: false }

# ...
La clave imports es similar a una declaracin include de PHP y garantiza que en
primer lugar se carga el archivo de configuracin principal (config.yml). El resto
del archivo de configuracin predeterminado simplemente aumenta el nmero de
eventos que se registran en el log y realiza otros ajustes tiles para un entorno de
desarrollo.
Ambos entornos (prod y test) siguen el mismo modelo: cada uno importa el
archivo de configuracin bsico y luego modifica sus valores de configuracin para
adaptarlos a las necesidades especficas del entorno. Esto es slo una
convencin, pero te permite reutilizar la mayor parte de tu configuracin y
personalizar slo algunas opciones especficas.
4.7. Resumen
Enhorabuena! Ahora ya conoces todos los aspectos fundamentales de Symfony2
y has descubierto lo fcil y flexible que puede ser. Aunque todava faltan muchas
caractersticas por explicar, asegrate de haber entendido bien los siguientes
puntos bsicos:
La creacin de una pgina es un proceso de tres pasos que requiere de
una ruta, uncontrolador y (opcionalmente) una plantilla.
Cada proyecto contiene slo unos cuantos directorios
principales: web/ (recursos web y controladores
frontales), app/ (configuracin), src/ (tus bundles), y vendor/ (cdigo de
terceros). Tambin existe un directorio bin/ que se utiliza para ayudarte a
actualizar las libreras de terceros.
Cada caracterstica de Symfony2 (incluyendo su propio ncleo) est
desarrollada con un bundle, que es un conjunto estructurado de archivos para
esa caracterstica.
La configuracin de cada bundle se encuentra en el directorio app/config y
se puede escribir en YAML, XML o PHP.
Cada entorno es accesible a travs de un controlador frontal diferente (por
ejemplo, app.php yapp_dev.php) el cual a su vez carga un archivo de
configuracin diferente.
A partir de aqu, cada captulo explica conceptos ms avanzados de Symfony y
algunas de sus herramientas ms poderosas. Cuanto ms sepas sobre Symfony2,
ms apreciars la flexibilidad de su arquitectura y el poder que te proporciona para
desarrollar aplicaciones rpidamente.
Captulo 5. El controlador
Un controlador es una funcin PHP creada por ti y que se encarga de obtener la
informacin de la peticin HTTP y de generar y devolver la respuesta HTTP (en
forma de objeto de tipo Response de Symfony2). La respuesta puede ser una
pgina HTML, un documento XML, un array JSON serializado, una imagen, una
redireccin a otra pgina, un error de tipo 404 o cualquier otra cosa que se te
ocurra. El controlador contiene toda la lgica que tu aplicacin necesita para
generar el contenido de la pgina.
Para ver lo sencillo que es esto, echemos un vistazo a un controlador real de
Symfony2. El siguiente controlador genera una pgina que simplemente
imprime Hello world!:
use Symfony\Component\HttpFoundation\Response;

public function helloAction()
{
return new Response('Hello world!');
}
El objetivo de un controlador siempre es el mismo: crear y devolver un
objeto Response. Para ello, a veces obtiene informacin de la peticin, o busca un
recurso en la base de datos, enva un correo electrnico, o guarda informacin en
la sesin del usuario. Independientemente de lo que haga, el controlador siempre
devuelve un objeto Response que se utiliza para generar la respuesta que se enva
al usuario.
Como ves ni Symfony se comporta de forma automgica ni existe ms requisitos
de los cuales preocuparse. Estos son algunos ejemplos de casos comunes:
Controlador A prepara un objeto Response que genera el contenido HTML de
la portada del sitio.
Controlador B lee el parmetro slug de la peticin para cargar una entrada del
blog desde la base de datos y crea un objeto Response para mostrar ese blog.
Si el slug no se puede encontrar en la base de datos, crea y devuelve un
objeto Response con un cdigo de estado de error 404.
Controlador C procesa la informacin enviada en un formulario de contacto:
lee la informacin del formulario desde la peticin, guarda la informacin del
contacto en la base de datos y enva mensajes de correo electrnico con la
informacin de contacto al administrador del sitio web. Por ltimo, crea un
objeto Response que redirige el navegador del cliente desde el formulario de
contacto a la pgina de agradecimiento.
5.1. Ciclo de vida de la peticin, controlador,
respuesta
Cada peticin manejada por un proyecto Symfony2 pasa por el mismo ciclo de
vida bsico. La plataforma se encarga de todas las tareas repetitivas iniciales y
despus, pasa la ejecucin al controlador, que contiene el cdigo personalizado
de tu aplicacin:
1. Cada peticin es manejada por un nico archivo controlador frontal (por
ejemplo, app.php oapp_dev.php) el cual es responsable de iniciar la aplicacin.
2. El sistema de enrutamiento (clase Routing) lee la informacin de la peticin
(por ejemplo, la URI), encuentra una ruta que coincida con esa informacin, y
lee el parmetro _controller de la ruta.
3. Se ejecuta el controlador asignado a la ruta y este controlador crea y devuelve
un objetoResponse.
4. Las cabeceras HTTP y el contenido del objeto Response se envan de vuelta al
cliente.
Crear una pgina es tan fcil como definir un controlador (paso 3) y hacer una ruta
que asocie una URI con ese controlador (paso 2).
NOTA Aunque tienen nombres parecidos, un "controlador frontal" es muy diferente
de los"controladores" que se explican en este captulo. Un controlador frontal es
un archivo PHP, normalmente pequeo, que se encuentra en el directorio web raz
del proyecto y a travs del cual se atienden todas las peticiones del usuario. Una
aplicacin tpica tiene un controlador frontal de produccin (por ejemplo, app.php) y
un controlador frontal de desarrollo (por ejemplo, app_dev.php). Probablemente
nunca necesites editar, ver o preocuparte por los controladores frontales en tu
aplicacin.
5.2. Un controlador sencillo
A pesar de que un controlador puede ser cualquier cdigo ejecutable PHP (una
funcin, un mtodo en un objeto o un Closure), en Symfony2 un controlador suele
ser un mtodo dentro de un objeto de tipo controlador. Los controladores tambin
se conocen como acciones.
// src/Acme/HelloBundle/Controller/HelloController.php

namespace Acme\HelloBundle\Controller;
use Symfony\Component\HttpFoundation\Response;

class HelloController
{
public function indexAction($name)
{
return new Response('<html><body>Hello '.$name.'!</body></html>');
}
}
TRUCO Ten en cuenta que el controlador es el mtodo indexAction, que se
encuentra dentro de una "clase controlador" (HelloController). No te dejes
confundir por la nomenclatura: una clase controlador simplemente es una forma
cmoda de agrupar varios controladores/acciones relacionados. Generalmente, la
clase controlador contiene varios controladores (por
ejemplo,updateAction, deleteAction, etc.).
Este controlador es bastante sencillo, pero vamos a analizarlo lnea por lnea:
Lnea 3: Symfony2 utiliza los namespaces de PHP 5.3 para asignar
un "espacio de nombres"completo a la clase del controlador. La palabra
clave use importa la clase Response, que la misma que nuestro controlador
debe devolver.
Lnea 6: el nombre de clase es la concatenacin del nombre de tu clase
controlador (es decirHello) y la palabra Controller. Esta es una convencin
que proporciona consistencia a los controladores y permite hacer referencia
slo a la primera parte del nombre (es decir, Hello) en la configuracin del
enrutador.
Lnea 8: cada accin en una clase controlador se sufija con Action, pero en la
configuracin de enrutado se utiliza solo el nombre corto de la accin (index).
En la siguiente seccin, se crea una ruta asociada a esta accin. As se ver
cmo las partes variables de la ruta (por ejemplo, {name}) se convierten en
argumentos para el mtodo de la accin (por ejemplo, $name).
Lnea 10: el controlador crea y devuelve un objeto Response.
5.3. Asociando una URI a un controlador
El nuevo controlador devuelve una pgina HTML simple. Para poder probar
realmente esta pgina en tu navegador, debes crear una ruta cuyo path sea la URI
que quieres asociar al controlador:
YAML
XML
PHP
# app/config/routing.yml
hello:
path: /hello/{name}
defaults: { _controller: AcmeHelloBundle:Hello:index }
Ahora, al acceder a la URI /hello/ryan se ejecuta el
controlador HelloController::indexAction() y se pasa el valor ryan como una
variable llamada $name. De nuevo, crear una pgina significa simplemente que
debes crear un mtodo controlador y una ruta asociada.
Observa la sintaxis utilizada para referirse al
controlador: AcmeHelloBundle:Hello:index. Symfony2 utiliza esta notacin corta
para referirse a los controladores. Se trata de la sintaxis recomendada y le dice a
Symfony2 que busque una clase controlador llamada HelloController dentro de
un paquete llamado AcmeHelloBundle y que despus ejecute el
mtodo indexAction().
NOTA Este ejemplo define la configuracin de enrutamiento directamente en el
directorioapp/config/. Una mejor manera de organizar tus rutas es colocar cada
una en el bundle al que pertenece.
TRUCO Puedes aprender mucho ms sobre el sistema de enrutado en el captulo
de enrutamiento.
5.3.1. Parmetros de la ruta como argumentos del controlador
Como ya se explic anteriormente, el valor AcmeHelloBundle:Hello:index del
parmetro _controllerse refiere al mtodo HelloController::indexAction() del
bundle AcmeHelloBundle. Lo ms interesante son los argumentos que se pasan a
ese mtodo:
<?php
// src/Acme/HelloBundle/Controller/HelloController.php

namespace Acme\HelloBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class HelloController extends Controller
{
public function indexAction($name)
{
// ...
}
}
El controlador anterior tiene un solo argumento, llamado $name, cuyo valor
corresponde al parmetro{name} de la ruta asociada (este valor es ryan en nuestro
ejemplo). De hecho, cuando ejecutas tu controlador, Symfony2 asocia cada
argumento del controlador con un parmetro de la ruta. Considera el siguiente
ejemplo:
YAML
XML
PHP
# app/config/routing.yml
hello:
path: /hello/{firstName}/{lastName}
defaults: { _controller: AcmeHelloBundle:Hello:index, color: green }
Ahora el controlador admite varios argumentos:
public function indexAction($firstName, $lastName, $color)
{
// ...
}
Las variables {firstName} y {lastName} de la ruta se llaman placeholders, ya
que "guardan el sitio"para que cualquier valor sustituya esa variable. Por otra
parte, la variable color es una variable de tipo default, ya que su valor siempre
est definido para todas las rutas.
Independientemente del tipo de variable, los valores
de {first_name}, {last_name} y color estn disponibles en el controlador. Cuando
se ejecuta una ruta, tanto los placeholders como las variables por defecto se
fusionan en un nico array que se pasa al controlador.
Asociar parmetros de la ruta a los argumentos del controlador es bastante fcil y
flexible. Pero debes tener en cuenta las siguientes pautas mientras desarrollas.
1. El orden de los argumentos del controlador no importa:
Symfony2 es capaz de asociar los nombres de los parmetros de la ruta con los
nombres de las variables en la declaracin del mtodo controlador. En otras
palabras, se da cuenta de que el parmetro {lastName} coincide con el
argumento $lastName.
As que puedes cambiar el orden de los argumentos como quieras y todo seguir
funcionando bien:
public function indexAction($lastName, $color, $firstName)
{
// ...
}
2. Cada argumento obligatorio del controlador debe tener asociado un
parmetro en la ruta
El siguiente cdigo producir una excepcin de tipo RuntimeException porque no
hay ningn parmetro foo definido en la ruta:
public function indexAction($firstName, $lastName, $color, $foo)
{
// ...
}
Sin embargo, es perfectamente vlido hacer que el argumento sea opcional. El
siguiente ejemplo no lanzar una excepcin:
public function indexAction($firstName, $lastName, $color, $foo = 'bar')
{
// ...
}
3. No todos los parmetros de la ruta deben ser argumentos en tu
controlador
Si por ejemplo, lastName no es tan importante para tu controlador, lo puedes omitir
por completo:
public function indexAction($firstName, $color)
{
// ...
}
TRUCO Todas las rutas incluyen adems un parmetro especial llamado _route,
que guarda el nombre de la propia ruta (en este ejemplo, hello). Normalmente no
se utiliza, pero tambin est disponible como argumento del controlador.
5.3.2. El objeto Request como argumento del controlador
Suele ser muy til disponer en el controlador del objeto Request asociado a la
peticin del usuario, especialmente cuando trabajas con formularios. Para hacer
que Symfony pase este objeto automticamente como argumento del controlador,
utiliza el siguiente cdigo:
use Symfony\Component\HttpFoundation\Request;

public function updateAction(Request $request)
{
$form = $this->createForm(...);

$form->handleRequest($request);

// ...
}
5.4. La clase base del controlador
Symfony2 proporciona una clase Controller base, que contiene varias utilidades
para las tareas ms comunes de los controladores y tambin incluye un acceso a
cualquier otro recurso que necesite la clase del controlador. Para acceder a todos
estos mtodos tiles, haz que la clase que contiene tus acciones herede de la
clase Controller.
Para ello, aade la siguiente instruccin use al principio de tu clase controlador y
luego modifica la declaracin de HelloController para extenderla:
// src/Acme/HelloBundle/Controller/HelloController.php

namespace Acme\HelloBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Response;

class HelloController extends Controller
{
public function indexAction($name)
{
return new Response('<html><body>Hello '.$name.'!</body></html>');
}
}
Este cambio no afecta al funcionamiento del controlador. En la siguiente seccin,
se explican loshelpers o mtodos tiles que la clase base del controlador pone a tu
disposicin. Estos mtodos slo son atajos para utilizar ms fcilmente las
funcionalidades del ncleo de Symfony2 (que tambin se pueden utilizar sin esta
clase base, pero no de forma tan cmoda). Una buena manera de aprender en la
prctica esas funcionalidades del ncleo es ver el cdigo fuente de esa clase base
en el archivoSymfony\Bundle\FrameworkBundle\Controller\Controller.
TRUCO Extender la clase base Controller en Symfony es opcional. Aunque
muchos programadores lo hacen para utilizar los atajos, no es obligatorio su uso.
Si lo prefieres, puedes extender la
claseSymfony\Component\DependencyInjection\ContainerAware o utilizar
el trait ContainerAwareTrait si tu versin de PHP es 5.4 o superior. En ambos
casos, el contenedor de servicios de Symfony estar disponible a travs de la
propiedad container.
NOTA Tambin puedes definir los controladores como servicios. Definirlos as es
opcional, pero si lo haces, tendrs un mayor control de las dependencias que se
inyectan en tus controladores.
5.5. Tareas comunes del controlador
Aunque un controlador puede hacer prcticamente cualquier cosa, la mayora de
los controladores siempre se encargan de las mismas tareas bsicas. Estas
tareas, tales como redirigir a otra pgina, procesar plantillas y acceder a servicios
bsicos, son muy fciles de manejar en Symfony2.
5.5.1. Redirigiendo
Si deseas redirigir al usuario a otra pgina, utiliza el mtodo redirect():
public function indexAction()
{
return $this->redirect($this->generateUrl('homepage'));
}
El mtodo generateUrl() es slo una funcin auxiliar que genera la URL de una
determinada ruta. Para ms informacin, consulta el captulo de enrutamiento.
Por defecto, el mtodo redirect() produce una redireccin temporal de tipo 302.
Para realizar una redireccin permanente de tipo 301, modifica el segundo
argumento:
public function indexAction()
{
return $this->redirect($this->generateUrl('homepage'), 301);
}
TRUCO El mtodo redirect() simplemente es un atajo que crea un
objeto Response especial que redirige a los usuarios. Su cdigo es equivalente a:
use Symfony\Component\HttpFoundation\RedirectResponse;

return new RedirectResponse($this->generateUrl('homepage'));
5.5.2. Reenviando
Tambin resulta sencillo realizar redirecciones internas hacia otro controlador de la
aplicacin mediante e, mtodo forward(). En lugar de redirigir el navegador del
usuario, se hace una nueva peticin interna (en realidad, sub-peticin) y se ejecuta
el controlador especificado. El mtodoforward() devuelve el
objeto Response generado por el segundo controlador:
public function indexAction($name)
{
$response = $this->forward('AcmeHelloBundle:Hello:fancy', array(
'name' => $name,
'color' => 'green'
));

// puedes seguir modificando la respuesta o
// devolverla directamente

return $response;
}
Ten en cuenta que el mtodo forward() utiliza la notacin corta habitual para
indicar el controlador que se ejecuta. En este caso, la clase controlador de destino
ser HelloController dentro del bundleAcmeHelloBundle. El array que se pasa
como segundo parmetro del mtodo se convierte en los argumentos utilizados en
el controlador resultante.
Esta misma sintaxis se utiliza para ejecutar controladores directamente desde las
plantillas, tal y como se explicar ms adelante. El mtodo del controlador destino
debe tener un aspecto como el siguiente:
public function fancyAction($name, $color)
{
// ... crea y devuelve un objeto Response
}
Como sucede con los argumentos de los controladores y las rutas, el orden de los
argumentos parafancyAction no tiene la menor importancia. Symfony2 asocia las
claves del array (por ejemplo, name) con el nombre del argumento del mtodo (por
ejemplo, $name). Si cambias el orden de los argumentos, Symfony2 contina
pasando el valor correcto a cada variable.
TRUCO Al igual que otros mtodos de la clase base Controller, el
mtodo forward slo es un atajo de la funcionalidad del ncleo de Symfony2.
Puedes realizar un forward duplicando la peticin actual y ejecutndola mediante
el servicio http_kernel, que devuelve un objeto de tipo Response:
use Symfony\Component\HttpKernel\HttpKernelInterface;

$path = array(
'_controller' => 'AcmeHelloBundle:Hello:fancy',
'name' => $name,
'color' => 'green',
);
$request = $this->container->get('request');
$subRequest = $request->duplicate(array(), null, $path);

$httpKernel = $this->container->get('http_kernel');
$response = $httpKernel->handle(
$subRequest,
HttpKernelInterface::SUB_REQUEST
);
5.5.3. Procesando plantillas
Aunque no es obligatorio, la mayora de los controladores acaban su ejecucin
renderizando una plantilla para generar el cdigo HTML que se devuelve al
usuario.
El mtodo renderView() procesa una plantilla y devuelve su contenido
renderizado. As que puedes usar fcilmente una plantilla para generar el
contenido del objeto Response:
use Symfony\Component\HttpFoundation\Response;

$content = $this->renderView(
'AcmeHelloBundle:Hello:index.html.twig',
array('name' => $name)
);

return new Response($content);
Si lo prefieres, tambin dispones del mtodo render() para hacer lo anterior en un
solo paso, ya que crea un objeto Response y le aade como contenido el resultado
de renderizar la plantilla:
return $this->render(
'AcmeHelloBundle:Hello:index.html.twig',
array('name' => $name)
);
En ambos casos, la notacin utilizada indica que se renderizar la plantilla que se
encuentra en el archivo Resources/views/Hello/index.html.twig del
bundle AcmeHelloBundle.
El motor de plantillas de Symfony se explica con gran detalle en el captulo
dedicado a las plantillas.
TRUCO Si lo prefieres, tambin puedes evitar el uso del mtodo render() utilizando
la anotacin@Template. Lee la documentacin del FrameworkExtraBundle para
obtener ms detalles.
TRUCO El mtodo renderView es un atajo para usar el servicio templating, que
tambin puedes utilizar directamente con el siguiente cdigo:
$templating = $this->get('templating');
$content = $templating->render('AcmeHelloBundle:Hello:index.html.twig', arra
y('name' => $name));
5.5.4. Accediendo a otros servicios
Al extender la clase base del controlador, puedes acceder a cualquier servicio de
Symfony2 a travs del mtodo get(). Estos son algunos de los servicios comunes
que puedes necesitar:
$templating = $this->get('templating');

$router = $this->get('router');

$mailer = $this->get('mailer');
Symfony dispones de infinidad de servicios ya creados, pero tambin puedes
definir tus propios servicios. Para listar todos los servicios disponibles, utiliza el
comando container:debug en la consola:
$ php app/console container:debug
Para ms informacin, consulta el captulo dedicado al contenedor de servicios.
5.6. Gestionando errores y pginas 404
Cuando no se encuentra un recurso, el protocolo HTTP indica que debes devolver
un error con cdigo de estado 404. Para ello, debes lanzar en tu cdigo una
excepcin especial. Si ests extendiendo la clase base del controlador, haz lo
siguiente:
public function indexAction()
{
$product = // recupera el objeto desde la base de datos

if (!$product) {
throw $this->createNotFoundException('El producto solicitado no exis
te.');
}

return $this->render(...);
}
El mtodo createNotFoundException() crea un objeto especial de
tipo NotFoundHttpException, que a su vez genera una respuesta de tipo 404 en el
interior de Symfony.
Obviamente puedes lanzar cualquier tipo de excepcin en tu controlador.
Symfony2 convierte automticamente las excepciones en respuestas HTTP con
cdigo de error 500.
throw new \Exception('Algo no ha salido bien.');
En ambos casos, el usuario final ve una pgina de error normal y a los
desarrolladores se les muestra una pgina de error con mucha informacin
de debug o depuracin (siempre que utilices el entorno de ejecucin de
desarrollo).
5.7. Gestionando la sesin
Symfony2 incluye un objeto de sesin que permite almacenar informacin
persistente sobre el usuario, es decir, informacin que se guarda de una peticin a
otra. Por defecto Symfony2 almacena la informacin en una cookie usando las
sesiones nativas de PHP.
Desde cualquier controlador resulta sencillo almacenar y recuperar informacin de
la sesin:
use Symfony\Component\HttpFoundation\Request;

public function indexAction(Request $request)
{
$session = $request->getSession();

// guarda un atributo para reutilizarlo durante una
// peticin posterior del usuario
$session->set('foo', 'bar');

// obtener el valor de un atributo de la sesin
$foo = $session->get('foo');

// utilizar un valor por defecto si el atributo no existe
$filters = $session->get('filters', array());
}
Esta informacin se mantendr asociada al usuario mientras no caduque su
sesin.
5.7.1. Mensajes flash
Este tipo de mensajes se utilizan para almacenar una pequea cantidad de
informacin que solo est disponible durante la siguiente peticin (despus se
borran automticamente). Estos mensajes son muy tiles cuando procesas por
ejemplo un formulario (por el momento no te fijes en los detalles del formulario,
solo en cmo crear el mensaje flash):
use Symfony\Component\HttpFoundation\Request;

public function updateAction(Request $request)
{
$form = $this->createForm(...);

$form->handleRequest($request);
if ($form->isValid()) {

// cdigo que procesa el formulario ...

$this->get('session')->getFlashBag()->add(
'notice',
'Se han guardado los cambios.'
);

return $this->redirect($this->generateUrl(...));
}

return $this->render(...);
}
Despus de procesar la peticin, el controlador crea un mensaje flash
llamado notice y luego redirige al usuario a otra pgina. El nombre del propio
mensaje (notice en este caso) no tiene importancia, ya que solo es un
identificador nico que utilizas en tu cdigo.
En la plantilla asociada a la siguiente peticin, puedes mostrar (si quieres) el
contenido de ese mensaje utilizando el siguiente cdigo:
TWIG
PHP
{% for flashMessage in app.session.flashbag.get('notice') %}
<div class="flash-notice">
{{ flashMessage }}
</div>
{% endfor %}
Recuerda que los mensajes flash solo estn disponibles durante la siguiente
peticin despus de haber sido creados. Tanto si muestras su contenido como si
lo ignoras, el mensaje flash se borra automticamente despus de esa peticin. El
objetivo de estos mensajes es mostrar algn aviso despus de una redireccin, tal
y como se ha mostrado en el ejemplo anterior.
5.8. El objeto Response
El nico requisito para un controlador es que devuelva un objeto de tipo Response.
La claseSymfony\Component\HttpFoundation\Response es una abstraccin en PHP
de la verdadera respuesta HTTP (que est formada por el contenido que se enva
al usuario y las cabeceras HTTP adecuadas):
// crea una respuesta simple con un cdigo de estado
// igual a 200 (el predeterminado)
$response = new Response('Hello '.$name, Response::HTTP_OK);

// crea una respuesta JSON con cdigo de estado 200
$response = new Response(json_encode(array('name' => $name)));
$response->headers->set('Content-Type', 'application/json');
TRUCO La propiedad headers es un objeto de
tipo Symfony\Component\HttpFoundation\HeaderBag, que contiene varios mtodos
tiles para lectura y modificacin de las cabeceras del objetoResponse. Los
nombres de las cabeceras se normalizan, para que no importe si utilizas Content-
Type, content-type o incluso content_type.
[tip] Tambin existen varias clases especiales para simplificar algunos tipos de
respuesta comunes:
Para devolver respuestas en formato JSON, utiliza la clase JsonResponse.
Para servir archivos binarios, utiliza la clase BinaryFileResponse. [/tip]
5.9. El objeto Request
Adems de las variables definidas por la ruta, el controlador tiene acceso
directo al objeto Request. El motivo es que Symfony inyecta
automticamente el objeto Request si el controlador define un argumento de
tipo Symfony\Component\HttpFoundation\Request (no importa ni el nombre
del argumento ni su posicin):
use Symfony\Component\HttpFoundation\Request;

public function indexAction(Request $request)
{
// es una peticin Ajax?
$request->isXmlHttpRequest();

$request->getPreferredLanguage(array('en', 'fr'));

// obtiene el valor de un parmetro $_GET
$request->query->get('page');

// obtiene el valor de un parmetro $_POST
$request->request->get('page');
}
Al igual que el objeto Response, las cabeceras de la peticin se almacenan
en un objeto HeaderBag y son fcilmente accesibles.
5.10. Resumen
Siempre que creas una pgina, tienes que escribir el cdigo PHP que
contiene la lgica asociada a esa pgina. En Symfony, a esto se le
llama controlador, y es una funcin PHP que puede hacer cualquier cosa
que necesites siempre que al final devuelvas un objeto de tipo Response con
el que Symfony2 construye la respuesta enviada al usuario.
Para que tu trabajo de programador sea ms sencillo, puedes optar por
extender la clase baseController, que contiene atajos para muchas de las
tareas ms comunes de los controladores. Uno de los ms utilizados es el
mtodo render(), que renderiza las plantillas que generan el cdigo HTML
devuelto al usuario.
En los prximos captulos se explicar cmo utilizar el controlador para
guardar y recuperar objetos desde una base de datos, procesar formularios,
manejar la cach y mucho ms.
Captulo 6. El enrutamiento
Las URL limpias son absolutamente imprescindibles en cualquier aplicacin web
que se precie. Deberas olvidarte para siempre de las
URL feas como index.php?article_id=57 y utilizar en su lugar URL
como /leer/intro-a-symfony.
Tambin es importante contar con cierta flexibilidad para cambiar las URL. Qu
pasa si necesitas cambiar la URL de una pgina de /blog a /noticias? Cunto
tiempo te costara buscar los enlaces que apuntan a /blog y modificarlos por la
nueva URL? Si utilizas el enrutador de Symfony, el cambio sera instantneo y
muy sencillo.
El enrutador de Symfony2 te permite asociar URL a diferentes reas de la
aplicacin. Despus de leer este captulo, sers capaz de:
Crear rutas complejas y asociarlas a controladores.
Generar URL dentro de las plantillas y los controladores.
Cargar rutas desde otros bundles o archivos externos.
Depurar las rutas de la aplicacin.
6.1. El enrutamiento en la prctica
Una ruta es una asociacin entre un patrn de URL y un controlador. Supongamos
por ejemplo que deseas asociar URL de tipo /blog/mi-post o /blog/todo-sobre-
symfony con un controlador que sea capaz de buscar y mostrar el artculo
solicitado.
La ruta necesaria para ello es muy simple:
YAML
XML
PHP
# app/config/routing.yml
blog_show:
path: /blog/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:show }
NOTA La opcin path solamente est definida desde la versin 2.2 de Symfony. En
las versiones anteriores esta opcin se llamaba pattern.
El path definido por la ruta blog_show se interpreta realmente como /blog/*, es
decir, la cadena de texto /blog/ seguida de cualquier otro contenido. El valor de
ese contenido se guarda en una variable llamada slug. Para la URL /blog/mi-
post, la variable slug vale mi-post. Esta variable est disponible directamente en el
controlador, tal y como se explicar ms adelante.
El parmetro _controller es una opcin especial que le dice a Symfony qu
controlador se debe ejecutar cuando la URL solicitada por el usuario coincide con
el patrn de la ruta. El controlador se indica a travs de su nombre lgico, que es
una notacin especial para hacer referencia a un mtodo concreto de una clase
concreta de PHP:
// src/Acme/BlogBundle/Controller/BlogController.php

namespace Acme\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class BlogController extends Controller
{
public function showAction($slug)
{
$blog = // usa la variable $slug para consultar la base de datos

return $this->render('AcmeBlogBundle:Blog:show.html.twig', array(
'blog' => $blog,
));
}
}
Enhorabuena! Acabas de crear tu primera ruta y la has asociado a un controlador.
Ahora, cuando visites /blog/mi-post, se ejecutar el controlador showAction y se le
pasar una variable llamada$slug cuyo valor ser mi-post.
Este es el objetivo del enrutador de Symfony2: asociar la URL de una peticin a un
controlador. En el resto del captulo vas a aprender todo tipo de trucos que te
facilitarn el trabajo incluso con las URL ms complejas.
6.2. Funcionamiento interno del enrutamiento
Cuando el usuario realiza una peticin a tu aplicacin, esta contiene la direccin
exacta del recurso que solicita el usuario. Esta direccin se conoce como URL (o
URI), y podra ser /contacto,/blog/read-me, o cualquier otra cosa. Considera la
siguiente peticin HTTP de ejemplo:
GET /blog/my-blog-post
El objetivo del sistema de enrutado de Symfony2 es analizar esta URL y
determinar qu controlador se debe ejecutar. El proceso completo consta de los
siguientes pasos:
1. La peticin se procesa en el controlador frontal de Symfony2 (por ejemplo, en
el archivo app.php).
2. El ncleo de Symfony2 (conocido como kernel) solicita al enrutador que
examine la peticin.
3. El enrutador busca qu patrn de las rutas de la aplicacin coincide con la
URL entrante y devuelve informacin sobre la ruta, incluyendo el controlador
que se debe ejecutar.
4. El ncleo de Symfony2 ejecuta el controlador, que en ltima instancia,
devuelve un objetoResponse.

Figura 6.1 Flujo de la peticin en Symfony2
6.3. Creando rutas
Symfony carga todas las rutas de tu aplicacin desde un archivo de configuracin
de enrutamiento. Normalmente este archivo es app/config/routing.yml, pero
puedes utilizar cualquier otro archivo e incluso otros formatos de configuracin
como XML o PHP. Para ello, cambiar el valor de la siguiente opcin de
configuracin:
YAML
XML
PHP
# app/config/config.yml
framework:
# ...
router: { resource: "%kernel.root_dir%/config/routing.yml" }
TRUCO Aunque todas las rutas se cargan desde un solo archivo, es muy comn
importar otros archivos desde ese archivo principal de configuracin de
enrutamiento. Ms adelante en este mismo captulo se explica cmo importar
otros archivos.
6.3.1. Configuracin bsica de rutas
Las aplicaciones tpicas definen decenas de rutas. Afortunadamente, definir una
ruta es bastante fcil. Una ruta bsica consta de dos partes: el path o patrn que
debe cumplir la URL y un array de opciones llamado defaults:
YAML
XML
PHP
_welcome:
path: /
defaults: { _controller: AcmeDemoBundle:Main:homepage }
Esta ruta corresponde a la portada del sitio (por eso el valor / en el patrn) y est
asociada con el controlador AcmeDemoBundle:Main:homepage. Symfony2 utiliza el
valor de la opcin _controller para determinar la funcin PHP que se ejecuta para
responder a la peticin. La transformacin de_controller en una funcin PHP se
explica ms adelante.
6.3.2. Rutas con variables
El sistema de enrutamiento ofrece unas posibilidades mucho ms interesantes que
las de la seccin anterior. Muchas rutas contienen una o ms variables, tambin
llamados placeholders:
YAML
XML
PHP
blog_show:
path: /blog/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:show }
El patrn de esta ruta se cumple para cualquier URL que empiece por /blog/ y
despus contenga cualquier valor. Ese valor variable se almacena en una variable
llamada slug (sin las llaves { y }) y se pasa al controlador. En otras palabras, si la
URL es /blog/hello-world, el controlador dispone de una variable $slug cuyo valor
es hello-world. Esta variable es la que utilizar por ejemplo el controlador para
buscar en la base de datos el artculo solicitado.
Si pruebas a acceder a la URL /blog, vers que Symfony2 no ejecuta el
controlador de esta ruta. El motivo es que por defecto todas las variables de las
rutas deben tener un valor. La solucin consiste en asignar un valor por defecto a
determinadas variables de la ruta mediante el array defaults.
6.3.3. Variables obligatorias y opcionales
Vamos a complicar un poco el ejemplo de la seccin anterior y para ello, se va a
aadir una nueva ruta llamada blog que muestra un listado de todos los artculos
del blog
YAML
XML
PHP
blog:
path: /blog
defaults: { _controller: AcmeBlogBundle:Blog:index }
Por el momento esta ruta es muy simple, ya que no incluye ninguna variable y por
tanto, solo se activar cuando el usuario solicite exactamente la URL /blog. Pero,
qu sucede si necesitamos que esta ruta sea compatible con la paginacin,
donde la URL /blog/2 muestra la segunda pgina de los artculos del blog?
Modifica la ruta anterior para que incluya una nueva variable llamada {page}:
YAML
XML
PHP
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index }
Al igual que la variable {slug} del ejemplo anterior, el valor asociado
a {page} ahora estar disponible dentro del controlador. As que ya puedes utilizar
su valor para saber qu artculos debes mostrar en una determinada pgina.
El problema es que, como por defecto las variables de las rutas son obligatorias,
esta ruta ya no funciona cuando un usuario solicita la URL /blog. As que para ver
la portada del blog, el usuario tendrs que utilizar la URL /blog/1. Obligar al
usuario a recordar que siempre debe entrar en la primera pgina es simplemente
ridculo. As que vamos a modificar la ruta para que la variable {page}sea opcional.
Para ello, asigna un valor por defecto a la variable dentro del array defaults:
YAML
XML
PHP
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
Como la variable page ya dispone de un valor por defecto dentro de defaults, ya
no es necesario indicarla siempre en la URL. As que cuando el usuario solicite la
URL /blog, esta ruta s que se ejecutar y se asignar automticamente el
valor 1 a la variable page. Si se solicita la URL /blog/2, la ruta tambin se ejecuta y
el valor de la variable page ser 2, tal y como se indica en la propia ruta.
Resumiendo:
URL Ruta Parmetros
/blog blog {page} = 1
/blog/1 blog {page} = 1
URL Ruta Parmetros
/blog/2 blog {page} = 2
ADVERTENCIA Tambin es posible definir ms de una variable opcional en la ruta
(por ejemplo:/blog/{slug}/{page}). La nica restriccin es que todo lo que va
despus de una variable opcional tambin tiene que ser opcional. As, para la
ruta /{page}/blog la variable page siempre ser obligatoria (/blog no es una URL
vlida para esta ruta).
TRUCO Las rutas con variables opcionales al final no son vlidas cuando la URL
solicitada por el usuario tiene una barra / al final. As que la URL /blog/ no ser
vlida para esta ruta, pero s lo ser la URL /blog).
6.3.4. Agregando requisitos
Observa las rutas definidas en los ejemplos de las secciones anteriores:
YAML
XML
PHP
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }

blog_show:
path: /blog/{slug}
defaults: { _controller: AcmeBlogBundle:Blog:show }
Has visto cul es el problema? Las dos rutas tienen el mismo patrn, por lo que
las dos podran responder a las URL que empiecen por /blog/ y continuen con
cualquier cosa. En estas situaciones, el sistema de enrutamiento de Symfony
siempre elige la ruta que se ha definido primero. As que la ruta blog_show jams
se ejecutar. Adems, URL como /blog/mi-post harn que se ejecute la primera
ruta (blog), lo que provocar un error, ya que no tiene sentido que la
variable page valga mi-post.
URL Ruta Parmetros
/blog/2 blog {page} = 2
/blog/mi-post blog {page} = mi-post
La solucin a este problema consiste en aadir requisitos o condiciones a la ruta.
En este caso, si el patrn /blog/{page} slo funcionara cuando {page} es un
nmero entero, las dos rutas funcionaran sin problemas. Afortunadamente, es
posible aadir requisitos a cada variable de la ruta mediante expresiones
regulares:
YAML
XML
PHP
blog:
path: /blog/{page}
defaults: { _controller: AcmeBlogBundle:Blog:index, page: 1 }
requirements:
page: \d+
El requisito \d+ es una expresin regular que obliga a que el valor del
parmetro {page} est formado exclusivamente por dgitos (es decir, que sea un
nmero entero y positivo). Despus de este cambio, la ruta blog seguir
funcionando para URL como /blog/2 (ya que 2 es un nmero), pero ya no se
ejecutar para URL como /blog/mi-post (porque mi-post no es un nmero). Por
tanto, ahora la URL/blog/mi-post se procesa mediante la ruta blog_show.
URL Ruta Parmetros
/blog/2 blog {page} = 2
/blog/mi-post blog_show {slug} = mi-post
/blog/2-mi-post blog_show {slug} = 2-mi-post
Las primeras rutas siempre gananTodo lo anterior significa que el orden en el
que se definen las rutas es muy importante.
Si la ruta blog_show se coloca por encima de la ruta blog, la
URL /blog/2 ejecutara la rutablog_show en lugar de blog ya que el
parmetro {slug} de blog_show no tiene ningn requisito. Usando un orden
adecuado para las rutas y los requisitos necesarios, puedes dominar
completamente el sistema de enrutamiento.
Como el parmetro requirements es una serie de expresiones regulares, puedes
hacer que los requisitos sean tan complejos y flexibles como necesites. Imagina
que la portada de tu aplicacin est disponible en dos idiomas en funcin de la
URL accedida:
YAML
XML
PHP
homepage:
path: /{_locale}
defaults: { _controller: AcmeDemoBundle:Main:homepage, _locale: en }
requirements:
_locale: en|fr
Cuando llegue una peticin de algn usuario, el valor indicado en la
variable {_locale} se compara con la expresin regular (en|fr).
Ruta Valor de la variable {_locale}
/ en
/en en
/fr fr
/es Ninguno, ya que la ruta no se ejecuta
6.3.5. Agregando requisitos sobre el mtodo HTTP
Adems de los requisitos de la URL, es posible restringir la ejecucin de las rutas
a un determinado mtodo HTTP (es decir, GET, HEAD, POST, PUT, DELETE). Imagina
que dispones de un formulario de contacto con dos controladores: uno para
mostrar el formulario (en una peticin GET) y otro para procesar el formulario
enviado (en una peticin POST*). La siguiente configuracin permite definir estas
dos rutas:
YAML
XML
PHP
contact:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contact }
methods: [GET]

contact_process:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contactProcess }
methods: [POST]
NOTA La opcin methods solamente est definida desde la versin 2.2 de Symfony.
En las versiones anteriores esta opcin se llamaba _method y se defina bajo la
opcin requirements.
A pesar de que estas dos rutas tienen el mismo patrn (/contact), la primera ruta
slo se activa con las peticiones GET y la segunda slo con las peticiones POST.
Esto significa que puedes mostrar y enviar el formulario a travs de la misma URL
y usar dos controladores distintos para las dos acciones.
NOTA Si no especificas la opcin methods, la ruta se ejecuta para todos los mtodos
HTTP.
6.3.6. Agregando el host a las rutas
A partir de la versin 2.2 de Symfony, tambin puedes hacer que una ruta slo se
ejecute si coincide con el host configurado. Para obtener ms informacin,
consulta el artculo How to match a route based on the Host.
6.3.7. Definiendo condiciones personalizadas mediante expresiones
Hasta ahora, se ha explicado cmo restringir las rutas para que slo se ejecuten
cuando se cumplen determinadas condiciones en sus variables, mtodos HTTP o
nombres de host. Sin embargo, a partir de la versin 2.4 de Symfony, las rutas
disponen de una flexibilidad casi ilimitada gracias a las condiciones definidas
mediante la propiedad condition:
YAML
XML
PHP
contact:
path: /contact
defaults: { _controller: AcmeDemoBundle:Main:contact }
condition: "context.getMethod() in ['GET', 'HEAD'] and request.headers.g
et('User-Agent') matches '/firefox/i'"
El valor de la propiedad condition es una expresin cuya sintaxis se define en
la documentacin del componente ExpressionLanguage. En este ejemplo, la ruta
no se ejecutar a menos que el mtodo HTTP sea GET o HEAD y el navegador
sea Firefox (ya que la cabecera User-Agent debe contener la palabra firefox).
La lgica de la expresin puede ser tan compleja como sea necesaria. Dentro de
la expresin puedes utilizar las dos siguientes variables:
context: es una instancia de la
clase Symfony\Component\Routing\RequestContext, y contiene toda la
informacin bsica de la ruta que est siendo comprobada.
request: el objeto de tipo Symfony\Component\HttpFoundation\Request que
representa a la peticin del usuario.
ADVERTENCIA Las condiciones no se tienen en cuenta al generar las URL a partir de
las rutas.
Las expresiones se compilan a cdigo PHPLas expresiones siempre se
compilan a cdigo PHP antes de ejecutarlas. En el caso del ejemplo mostrado
anteriormente, este sera el cdigo PHP generado en el directorio cache de la
aplicacin:
if (rtrim($pathinfo, '/contact') === '' && (
in_array($context->getMethod(), array(0 => "GET", 1 => "HEAD"))
&& preg_match("/firefox/i", $request->headers->get("User-Agent"))
)) {
// ...
}
Por todo ello, el uso de la propiedad condition no supone ninguna penalizacin en
el rendimiento, ms all de lo que cueste ejecutar el cdigo PHP compilado de la
expresin.
6.3.8. Ejemplo de enrutado avanzado
Con todo lo explicado hasta ahora, ya puedes definir rutas realmente avanzadas
para tu aplicacin Symfony. El siguiente ejemplo muestra lo flexible que puede
llegar a ser el sistema de enrutamiento:
YAML
XML
PHP
article_show:
path: /articles/{_locale}/{year}/{title}.{_format}
defaults: { _controller: AcmeDemoBundle:Article:show, _format: html }
requirements:
_locale: en|fr
_format: html|rss
year: \d+
Esta ruta slo se ejecutar cuando el valor de la variable {_locale} sea o en o fr y
cuando la variable{year} sea un nmero. Adems, esta ruta tambin muestra
cmo utilizar un punto (.) para separar dos variables entre s, en vez de la habitual
barra inclinada (/). En resumen, cualquiera de las siguientes URL haran que esta
ruta se ejecutara:
/articles/en/2010/my-post
/articles/fr/2010/my-post.rss
/articles/en/2013/my-latest-post.html
El parmetro especial de enrutado _formatEl ejemplo anterior utiliza un
parmetro especial de enrutamiento llamado _format.
Cuando una ruta incluye esta variable, su valor se considera como el formato de la
peticin y as se aade en el objeto Request correspondiente. Este valor es
importante porque se utiliza, entre otros, para indicar el Content-Type de la
respuesta enviada al usuario (por ejemplo, un formato de peticinjson se traduce
en un Content-Type igual a application/json).
Este valor tambin se puede utilizar en el controlador para renderizar una plantilla
diferente en funcin de cada formato. De hecho, la variable _format es una de las
formas ms prcticas de mostrar los mismos contenidos con diferentes formatos.
NOTA En ocasiones es conveniente hacer que algunas partes de las rutas se
puedan configurar globalmente en la aplicacin. A partir de la versin 2.1 de
Symfony es posible hacerlo gracias a los parmetros del contenedor de servicios.
Para ms informacin, lee el artculo How to use Service Container Parameters in
your Routes.
6.3.9. Variables de enrutamiento especiales
Como hemos visto, cada variable de enrutamiento y cada valor aadido al
array defaults est disponible como argumento del controlador. Symfony tambin
define tres variables especiales de enrutamiento:
_controller: determina el controlador asociado a la ruta que se ejecuta.
_format: establece el formato de la peticin del usuario.
_locale: establece el idioma en la peticin del usuario.
6.4. El nombre lgico de los controladores
Todas las rutas definen una variable llamada _controller que indica el
controlador que se debe ejecutar. El valor de esta variable es una cadena
de texto que indica el controlador utilizando una notacin especial
llamada nombre lgico del controlador. Este nombre se divide en tres
partes, cada una separada por dos puntos:
bundle:controlador:accin
As que por ejemplo, el valor AcmeBlogBundle:Blog:show hara referencia al
bundle + AcmeBlogBundle, la claseBlogControllery el
mtodoshowAction`. El cdigo del controlador podra ser algo como lo
siguiente:
// src/Acme/BlogBundle/Controller/BlogController.php

namespace Acme\BlogBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;

class BlogController extends Controller
{
public function showAction($slug)
{
// ...
}
}
Ten en cuenta que Symfony sufija automticamente la
cadena Controller al nombre de la clase (Blogse transforma
en BlogController) y Action al nombre del mtodo (show se transforma
en showAction).
Tambin es posible hacer referencia al controlador utilizando
el namespace completo de su
clase:Acme\BlogBundle\Controller\BlogController::showAction. Pero si lo
piensas un poco, es mucho mejor utilizar el nombre lgico, poruqe adems
permite una mayor flexibilidad.
NOTA Adems de utilizar el nombre lgico o el namespace completo de la
clase, Symfony define una tercera forma de referirse al controlador. Este
mtodo utiliza un solo separador de dos puntos (por
ejemplo, service_name:indexAction) y puedes emplearlo cuando defines tus
controladores como servicios, tal y como se ver ms adelante.
6.5. Variables de la ruta y argumentos del
controlador
Las variables o parmetros de la ruta (por ejemplo, {slug}) son muy importantes
porque estn disponibles como argumentos del mtodo del controlador:
public function showAction($slug)
{
// ...
}
En realidad, todas las variables del array defaults se combinan con las variables
de la ruta para formar un solo array. Cada clave de ese array conjunto est
disponible como un argumento del controlador.
En otras palabras, por cada argumento de tu mtodo controlador, Symfony busca
una variable de ruta con ese nombre y asigna su valor a ese argumento.
En el ejemplo avanzado anterior, cualquier combinacin de las siguientes
variables (y en cualquier orden) se podra utilizar como argumentos para el
mtodo showAction():
$_locale
$year
$title
$_format
$_controller
Como se combinan las variables con los valores definidos en defaults, el
controlador tiene a su disposicin incluso variables como $_controller.
TRUCO Una variable especial adicional que siempre est disponible es $_route, que
indica el nombre de la ruta que se est ejecutando.
6.6. Importando recursos de enrutamiento
externos
Todas las rutas de la aplicacin se cargan a travs de un nico archivo de
configuracin normalmente app/config/routing.yml. Sin embargo, resulta
habitual tener que cargar rutas definidas en otros archivos, almacenados por
ejemplo dentro de algn bundle. Para cargarlas, debes importar esos ficheros
externos utilizando las siguientes instrucciones:
YAML
XML
PHP
# app/config/routing.yml
acme_hello:
resource: "@AcmeHelloBundle/Resources/config/routing.yml"
NOTA Cuando importas recursos desde archivos YAML, el valor que asignes como
clave de la opcin resource es indiferente, ya que no se utiliza para nada (en el
ejemplo anterior, se utiliza el valor acme_hello). En cualquier caso, asegrate de
que utilizas un valor nico para cada importacin.
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 @AcmeHelloBundle es un atajo muy til que Symfony interpreta como la ruta
hasta el directorio donde se encuentra ese bundle. El contenido del archivo
importado podra ser por ejemplo el siguiente:
YAML
XML
PHP
# src/Acme/HelloBundle/Resources/config/routing.yml
acme_hello:
path: /hello/{name}
defaults: { _controller: AcmeHelloBundle:Hello:index }
Las rutas de este archivo se analizan y cargan en la misma forma que las del
archivo de enrutamiento principal.
6.6.1. Prefijando las rutas importadas
Resulta habitual tener que aadir un prefijo a todas las rutas importadas desde un
archivo externo. Si quieres por ejemplo que el patrn de la
ruta acme_hello sea /admin/hello/{name} en vez de/hello/{name}, aade la
opcin prefix al importar las rutas:
YAML
XML
PHP
# app/config/routing.yml
acme_hello:
resource: "@AcmeHelloBundle/Resources/config/routing.yml"
prefix: /admin
El valor indicado en la opcin prefix (en este caso /admin) se aade por delante
de todos los patrones de las rutas importadas desde el archivo externo.
6.6.2. Agregando un host a las rutas importadas
A partir de la versin 2.2 de Symfony, tambin puedes aadir un host a las rutas
importadas. Para obtener ms informacin, consulta el artculo Adding a Host
Regex to Imported Routes.
6.7. Visualizando y depurando rutas
A medida que aades y configuras rutas puede venir bien obtener informacin
detallada sobre todas o alguna ruta especfica. La mejor manera de ver todas las
rutas definidas para la aplicacin consiste en ejecutar el
comando router:debug desde el directorio raz de tu proyecto:
php app/console router:debug
Como resultado, este comando imprime la lista de todas las rutas existentes en tu
aplicacin:
homepage ANY /
contact GET /contact
contact_process POST /contact
article_show ANY /articles/{_locale}/{year}/{title}.{_format}
blog ANY /blog/{page}
blog_show ANY /blog/{slug}
Para obtener toda la informacin sobre una nica ruta, aade el nombre de esa
ruta como argumento del comando anterior:
php app/console router:debug article_show
De la misma forma, para comprobar si una determinada URL cumple con las
condiciones de una ruta, puedes utilizar el comando router_match:
$ php app/console router:match /blog/my-latest-post
El resultado del comando muestra la ruta que se ejecutar para la URL indicada:
Route "blog_show" matches
6.8. Generando URL
El sistema de enrutamiento no solo se utiliza para asociar rutas a controladores
sino que tambin se emplea para generar URL. De hecho, el enrutamiento
siempre es un sistema bidireccional: convierte una URL + variables en un
controlador y despus, convierte una ruta y varias variables en una URL. Este
sistema bidireccional se basa en los mtodos match() y generate(). El siguiente
cdigo emplea la ruta blog_show definida anteriormente:
$params = $router->match('/blog/my-blog-post');
// array(
// 'slug' => 'my-blog-post',
// '_controller' => 'AcmeBlogBundle:Blog:show'
// )

$uri = $router->generate('blog_show', array('slug' => 'my-blog-post'));
// /blog/my-blog-post
Para generar una URL, especifica el nombre de la ruta (por ejemplo, blog_show) y
el valor de todas las variables de la ruta (por ejemplo, slug = my-blog-post). Con
esta informacin, puedes generar fcilmente cualquier URL:
class MainController extends Controller
{
public function showAction($slug)
{
// ...

$url = $this->generateUrl(
'blog_show',
array('slug' => 'my-blog-post')
);
}
}
Ms adelante se explicar tambin cmo generar URL desde las propias plantillas
de la aplicacin.
TRUCO Si tu aplicacin realiza peticiones AJAX, seguramente necesitars generar
URL de Symfony desde el propio cdigo JavaScript. Para ello debes utilizar un
bundle desarrollado por terceros y llamado FOSJsRoutingBundle:
var url = Routing.generate('blog_show', { "slug": 'my-blog-post'});
6.8.1. Generando URL con parmetros
El array que se pasa al mtodo generate contiene los valores de las variables de la
ruta, pero tambin puede contener variables adicionales que se aaden a la URL
generada en forma de query string:
$router->generate('blog', array('page' => 2, 'category' => 'Symfony'));
// /blog/2?category=Symfony
6.8.2. Generando URL desde una plantilla
La mayora de URL se generan en las propias plantillas para poder enlazar entre
s las pginas de la aplicacin. El formato es muy parecido al explicado
anteriormente, pero en el caso de las plantillas Twig, se utiliza una funcin
especial llamada path():
TWIG
PHP
<a href="{{ path('blog_show', { 'slug': 'my-blog-post' }) }}">
Read this blog post.
</a>
6.8.3. Generando URL absolutas
El sistema de enrutamiento genera por defecto URL relativas (por ejemplo /blog).
Para generar URL absolutas, pasa el valor true como tercer argumento del
mtodo generate():
$router->generate('blog_show', array('slug' => 'my-blog-post'), true);
// http://www.example.com/blog/my-blog-post
En una plantilla, las URL absolutas se generan de la siguiente manera:
TWIG
PHP
<a href="{{ url('blog_show', { 'slug': 'my-blog-post' }) }}">
Read this blog post.
</a>
NOTA El host que se utiliza en las URL absolutas es el mismo host de la peticin
actual y su valor se detecta automticamente en funcin de la informacin
proporcionada por PHP.
Si ests generando URL absolutas en un script de consola, este mecanismo no
funciona. Consultaeste artculo para saber cmo generar las URL absolutas en un
comando de consola.
6.9. Resumen
El enrutamiento es un sistema que permite asociar las URL de las peticiones de
los usuarios a los controladores de tu aplicacin. Gracias a este sistema puedes
generar URL limpias y adems, mantiene desacoplado el funcionamiento de tu
aplicacin respecto de esas URL. Por ltimo, el enrutamiento es un sistema
bidireccional, por lo que tambin se utiliza para generar URL a partir de la
configuracin de las rutas.

Anda mungkin juga menyukai