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

Listado 7-1 - Plantilla de ejemplo indexSuccess.php

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

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

7.1.1. Helpers

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

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

La función debería ser como la que se muestra en el listado 7-2.

Listado 7-2 - Ejemplo de definición de helper

function input_tag($name, $value = null)
{
  return '<input type="text" name="'.$name.'" id="'.$name.'" value="'.$value.'" />';
}

En realidad, la función input_tag() que incluye Symfony es un poco más complicada que eso, ya que permite indicar un tercer parámetro que contiene otros atributos de la etiqueta <input>. Se puede consultar su sintaxis completa y sus opciones en la documentación de la API: http://www.symfony-project.org/api/1_0/

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

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

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

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

7.1.1.1. Declarando los Helpers

Los archivos de Symfony que contienen los helpers no se cargan automáticamente (ya que contienen funciones, no clases). Los helpers se agrupan según su propósito. Por ejemplo el archivo llamado TextHelper.php contiene todas las funciones de los helpers relacionados con el texto, que se llaman "grupo de helpers de Text". De esta forma, si una plantilla va a utilizar un helper, se debe cargar previamente el grupo al que pertenece el helper mediante la función use_helper(). El listado 7-3 muestra una plantilla que hace uso del helper auto_link_text(), que forma parte del grupo Text.

Listado 7-3 - Declarando el uso de un helper

// Esta plantilla utiliza un grupo de helpers específicos
<?php use_helper('Text') ?>
...
<h1>Descripción</h1>
<p><?php echo auto_link_text($descripcion) ?></p>

Nota Si se necesita declarar más de un grupo de helpers, se deben añadir más argumentos a la llamada de la función use_helper(). Si por ejemplo se necesitan cargar los helpers Text y Javascript, la llamada a la función debe ser <?php use_helper('Text', 'Javascript') ?>.

Por defecto algunos de los helpers están disponibles en las plantillas sin necesidad de ser declarados. Estos helpers pertenecen a los siguientes grupos:

  • Helper: se necesita para incluir otros helpers (de hecho, la función use_helper() también es un helper)
  • Tag: helper básico para etiquetas y que utilizan casi todos los helpers
  • Url: helpers para la gestión de enlaces y URL
  • Asset: helpers que añaden elementos a la sección <head> del código HTML y que proporcionan enlaces sencillos a elementos externos (imágenes, archivos JavaScript, hojas de estilo, etc.)
  • Partial: helpers que permiten incluir trozos de plantillas
  • Cache: manipulación de los trozos de código que se han añadido a la cache
  • Form: helpers para los formularios

El archivo settings.yml permite configurar la lista de helpers que se cargan por defecto en todas las plantillas. De esta forma, se puede modificar su configuración si se sabe por ejemplo que no se van a usar los helpers relacionados con la cache o si se sabe que siempre se van a necesitar los helpers relacionados con el grupo Text. Este cambio puede aumentar ligeramente la velocidad de ejecución de la aplicación. Los 4 primeros helpers de la lista anterior (Helper, Tag, Url y Asset) no se pueden eliminar, ya que son obligatorios para que funcione correctamente el mecanismo de las plantillas. Por este motivo ni siquiera aparecen en la lista de helpers estándares.

Truco Si se quiere utilizar un helper fuera de una plantilla, se puede cargar un grupo de helpers desde cualquier punto de la aplicación mediante la función sfLoader::loadHelpers($helpers), donde la variable $helpers es el nombre de un grupo de helpers o un array con los nombres de varios grupos de helpers. Por tanto, si se quiere utilizar auto_link_text() dentro de una acción, es necesario llamar primero a sfLoader::loadHelpers('Text').

7.1.1.2. Los helpers habituales

Algunos helpers se explican en detalle en los siguientes capítulos, en función de la característica para la que han sido creados. El listado 7-4 incluye un pequeña lista de los helpers que más se utilizan y muestra también el código HTML que generan.

Listado 7-4 - Los helpers por defecto más utilizados

// Grupo Helper
<?php use_helper('NombreHelper') ?>
<?php use_helper('NombreHelper1', 'NombreHelper2', 'NombreHelper3') ?>

// Grupo Tag
<?php echo tag('input', array('name' => 'parametro', 'type' => 'text')) ?>
<?php echo tag('input', 'name=parametro type=text') ?>  // Sintaxis alternativa para las opciones
=> <input name="parametro" type="text" />
<?php echo content_tag('textarea', 'contenido de prueba', 'name=parametro') ?>
=> <textarea name="parametro">contenido de prueba</textarea>

// Grupo Url
<?php echo link_to('Pínchame', 'mimodulo/miaccion') ?>
=> <a href="/ruta/a/miaccion">Pínchame</a>  // Depende del sistema de enrutamiento

// Grupo Asset
<?php echo image_tag('miimagen', 'alt=imagen size=200x100') ?>
=> <img src="/images/miimagen.png" alt="imagen" width="200" height="100"/>
<?php echo javascript_include_tag('miscript') ?>
=> <script language="JavaScript" type="text/javascript" src="/js/miscript.js"></script>
<?php echo stylesheet_tag('estilo') ?>
=> <link href="/stylesheets/estilo.css" media="screen" rel="stylesheet" type="text/css" />

Symfony incluye muchos otros helpers y describirlos todos requeriría de un libro entero. La mejor referencia para estudiar los helpers es la documentación de la API, que se puede consultar en http://www.symfony-project.org/api/1_0/, donde todos los helpers incluyen documentación sobre su sintaxis, opciones y ejemplos.

7.1.1.3. Crea tus propios helpers

Symfony incluye numerosos helpers que realizan distintas funcionalidades, pero si no se encuentra lo que se necesita, es probable que tengas que crear un nuevo helper. Crear un helper es muy sencillo.

Las funciones del helper (funciones normales de PHP que devuelven código HTML) se deben guardar en un archivo llamado NombreHelper.php, donde Nombre es el nombre del nuevo grupo de helpers. El archivo se debe guardar en el directorio apps/miaplicacion/lib/helper/ (o en cualquier directorio helper/ que esté dentro de cualquier directorio lib/ del proyecto) para que la función use_helper('Nombre') pueda encontrarlo de forma automática y así poder incluirlo en la plantilla.

Truco Este mecanismo permite incluso redefinir los helpers de Symfony. Para redefinir por ejemplo todos los helpers del grupo Text, se puede crear un archivo llamado TextHelper.php y guardarlo en el directorio apps/miaplicacion/lib/helper/. Cada vez que se llame a la función use_helper('Text'), Symfony carga el nuevo grupo de helpers en vez del grupo por defecto. Hay que ser cuidadoso con este método, ya que como el archivo original no se carga, el nuevo grupo de helpers debe redefinir todas y cada una de las funciones del grupo original, ya que de otra forma no estarán disponibles las funciones no definidas.

7.1.2. Layout de las páginas

La plantilla del listado 7-1 no es un documento XHTML válido. Le faltan la definición del DOCTYPE y las etiquetas <html> y <body>. El motivo es que estos elementos se encuentran en otro lugar de la aplicación, un archivo llamado layout.php que contiene el layout de la página. Este archivo, que también se denomina plantilla global, almacena el código HTML que es común a todas las páginas de la aplicación, para no tener que repetirlo en cada página. El contenido de la plantilla se integra en el layout, o si se mira desde el otro punto de vista, el layout decora la plantilla. Este comportamiento es una implementación del patrón de diseño llamado "decorator" y que se muestra en la figura 7-1.

Truco Para obtener más información sobre el patrón "decorator" y sobre otros patrones de diseño, se puede consultar el libro "Patterns of Enterprise Application Architecture" escrito por Martin Fowler (Addison-Wesley, ISBN: 0-32112-742-0).

Plantilla decorada con un layout

Figura 7.1 Plantilla decorada con un layout

El listado 7-5 muestra el layout por defecto, que se encuentra en el directorio templates/.

Listado 7-5 - Layout por defecto, en miproyecto/apps/miaplicacion/templates/layout.php

<!DOCTYPE html PUBLIC "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/2000/rec-xhtml1-20000126/dtd/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <?php echo include_http_metas() ?>
  <?php echo include_metas() ?>
  <?php echo include_title() ?>
  <link rel="shortcut icon" href="/favicon.ico" />
</head>
<body>

<?php echo $sf_data->getRaw('sf_content') ?>

</body>
</html>

Los helpers utilizados en la sección <head> obtienen información del objeto respuesta y en la configuración de la vista. La etiqueta <body> muestra el resultado de la plantilla. Utilizando este layout, la configuración por defecto y la plantilla de ejemplo del listado 7-1, la vista generada sería la del listado 7-6.

Listado 7-6 - Unión del layout, la configuración de la vista y la plantilla

<!DOCTYPE html PUBLIC "-//w3c//dtd xhtml 1.0 transitional//en" "http://www.w3.org/tr/2000/rec-xhtml1-20000126/dtd/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="content-type" content="text/html; charset=utf-8" />
  <meta name="title" content="symfony project" />
  <meta name="robots" content="index, follow" />
  <meta name="description" content="symfony project" />
  <meta name="keywords" content="symfony, project" />
  <title>symfony project</title>
  <link rel="stylesheet" type="text/css" href="/css/main.css" />
  <link rel="shortcut icon" href="/favicon.ico">
</head>
<body>

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

</body>
</html>

La plantilla global puede ser adaptada completamente para cada aplicación. Se puede añadir todo el código HTML que sea necesario. Normalmente se utiliza el layout para mostrar la navegación, el logotipo del sitio, etc. Incluso es posible definir más de un layout y decidir en cada acción el layout a utilizar. No te preocupes ahora por la forma de incluir archivos de JavaScript y hojas de estilos, ya que se explica en la sección "Configuración de la Vista" más adelante en este capítulo.

7.1.3. Atajos de plantilla

Symfony incluye una serie de variables propias en todas las plantillas. Estas variables se pueden considerar atajos que permiten el acceso directo a la información más utilizada en las plantillas, mediante los siguientes objetos internos de Symfony:

  • $sf_context: el objeto que representa a todo el contexto (es una instancia de sfContext)
  • $sf_request: el objeto petición (es una instancia de sfRequest)
  • $sf_params: los parámetros de la petición
  • $sf_user: el objeto de sesión del usuario actual (es una instancia de sfUser)

En el capítulo anterior se detallaban algunos métodos útiles de los objetos sfRequest y sfUser. En las plantillas se pueden invocar todos esos métodos mediante las variables $sf_request y $sf_user. Por ejemplo, si la petición incluye un parámetro llamado total, desde la plantilla se puede acceder a su valor de la siguiente manera:

// Método largo
<?php echo $sf_request->getParameter('total'); ?>

// Método corto (atajo)
<?php echo $sf_params->get('total'); ?>

// Son equivalentes al siguiente código de la acción
echo $this->getRequestParameter('total');