Symfony 1.2, la guía definitiva

10.1. Helpers de formularios

En las plantillas, es común mezclar las etiquetas HTML con código PHP. Los helpers de formularios que incluye Symfony intentan simplificar esta tarea para evitar tener que incluir continuamente etiquetas <?php echo en medio de las etiquetas <input>.

10.1.1. Etiqueta principal de los formularios

Como se explicó en el capítulo anterior, para crear un formulario se emplea el helper form_tag(), ya que se encarga de transformar la acción que se pasa como parámetro a una URL válida para el sistema de enrutamiento. El segundo argumento se emplea para indicar opciones adicionales, como por ejemplo, cambiar el valor del method por defecto, establecer el valor de enctype o especificar otros atributos. El listado 10-1 muestra algunos ejemplos.

Listado 10-1 - El helper form_tag()

<?php echo form_tag('prueba/guardar') ?>
 => <form method="post" action="/ruta/a/guardar">

<?php echo form_tag('prueba/guardar', 'method=get multipart=true class=formularioSimple') ?>
 => <form method="get" enctype="multipart/form-data" class="formularioSimple" action="/ruta/a/guardar">

Como no se utiliza un helper para cerrar el formulario, siempre debe incluirse la etiqueta HTML </form>, aunque no quede bien en el código fuente de la plantilla.

10.1.2. Elementos comunes de formulario

Los helpers de formulario asignan por defecto a cada elemento un atributo id cuyo valor coincide con su atributo name, aunque esta no es la única convención útil. El listado 10-2 muestra una lista completa de los helpers disponibles para los elementos comunes de formularios y sus opciones.

Listado 10-2 - Sintaxis de los helpers para los elementos comunes de formulario

// Cuadro de texto (input)
<?php echo input_tag('nombre', 'valor inicial') ?>
 => <input type="text" name="nombre" id="nombre" value="valor inicial" />

// Todos los helpers de formularios aceptan un parámetro con opciones adicionales
// De esta forma es posible añadir atributos propios a la etiqueta que se genera
<?php echo input_tag('nombre', 'valor inicial', 'maxlength=20') ?>
 => <input type="text" name="nombre" id="nombre" value="valor inicial" maxlength="20" />

// Cuadro de texto grande (área de texto)
<?php echo textarea_tag('nombre', 'valor inicial', 'size=10x20') ?>
 => <textarea name="nombre" id="nombre" cols="10" rows="20">
      valor inicial
    </textarea>

// Checkbox
<?php echo checkbox_tag('soltero', 1, true) ?>
<?php echo checkbox_tag('carnet_conducir', 'B', false) ?>
 => <input type="checkbox" name="soltero" id="soltero" value="1" checked="checked" />
    <input type="checkbox" name="carnet_conducir" id="carnet_conducir" value="B" />

// Radio button
<?php echo radiobutton_tag('estado[]', 'valor1', true) ?>
<?php echo radiobutton_tag('estado[]', 'valor2', false) ?>
 => <input type="radio" name="estado[]" id="estado_valor1" value="valor1" checked="checked" />
    <input type="radio" name="estado[]" id="estado_valor2" value="valor2" />

// Lista desplegable (select)
<?php echo select_tag('pago',
  '<option selected="selected">Visa</option>
   <option>Eurocard</option>
   <option>Mastercard</option>')
?>
 => <select name="pago" id="pago">
      <option selected="selected">Visa</option>
      <option>Eurocard</option>
      <option>Mastercard</option>
    </select>

// Lista de opciones para una etiqueta select
<?php echo options_for_select(array('Visa', 'Eurocard', 'Mastercard'), 0) ?>
 => <option value="0" selected="selected">Visa</option>
    <option value="1">Eurocard</option>
    <option value="2">Mastercard</option>

// Helper de lista desplegable con una lista de opciones
<?php echo select_tag('pago', options_for_select(array(
  'Visa',
  'Eurocard',
  'Mastercard'
), 0)) ?>
 => <select name="pago" id="pago">
      <option value="0" selected="selected">Visa</option>
      <option value="1">Eurocard</option>
      <option value="2">Mastercard</option>
    </select>

// Para indicar el nombre de las opciones, se utiliza un array asociativo
<?php echo select_tag('nombre', options_for_select(array(
  'Steve'  => 'Steve',
  'Bob'    => 'Bob',
  'Albert' => 'Albert',
  'Ian'    => 'Ian',
  'Buck'   => 'Buck'
), 'Ian')) ?>
 => <select name="nombre" id="nombre">
      <option value="Steve">Steve</option>
      <option value="Bob">Bob</option>
      <option value="Albert">Albert</option>
      <option value="Ian" selected="selected">Ian</option>
      <option value="Buck">Buck</option>
    </select>

// Lista desplegable que permite una selección múltiple
// (los valores seleccionados se pueden indicar en forma de array)
<?php echo select_tag('pago', options_for_select(
  array('Visa' => 'Visa', 'Eurocard' => 'Eurocard', 'Mastercard' => 'Mastercard'),
  array('Visa', 'Mastercard'),
), array('multiple' => true))) ?>
 => <select name="pago[]" id="pago" multiple="multiple">
      <option value="Visa" selected="selected">Visa</option>
      <option value="Eurocard">Eurocard</option>
      <option value="Mastercard">Mastercard</option>
    </select>

// Lista desplegable que permite una selección múltiple
// (los valores seleccionados se pueden indicar en forma de array)
<?php echo select_tag('pago', options_for_select(
  array('Visa' => 'Visa', 'Eurocard' => 'Eurocard', 'Mastercard' => 'Mastercard'),
  array('Visa', 'Mastercard')
), 'multiple=multiple') ?>
 => <select name="pago[]" id="pago" multiple="multiple">
      <option value="Visa" selected="selected">Visa</option>
      <option value="Eurocard">Eurocard</option>
      <option value="Mastercard" selected="selected">Mastercard</option>
    </select>

// Campo para adjuntar archivos
<?php echo input_file_tag('nombre') ?>
 => <input type="file" name="nombre" id="nombre" value="" />

// Cuadro de texto de contraseña
<?php echo input_password_tag('nombre', 'valor') ?>
 => <input type="password" name="nombre" id="nombre" value="valor" />

// Campo oculto
<?php echo input_hidden_tag('nombre', 'valor') ?>
 => <input type="hidden" name="nombre" id="nombre" value="valor" />

// Botón de envío de formulario (botón normal de texto)
<?php echo submit_tag('Guardar') ?>
 => <input type="submit" name="submit" value="Guardar" />

// Botón de envío de formulario (botón creado con la imagen indicada)
<?php echo submit_image_tag('imagen_envio') ?>
 => <input type="image" name="submit" src="/images/imagen_envio.png" />

El helper submit_image_tag() utiliza la misma sintaxis y tiene las mismas características que image_tag().

Nota En los radio button, el valor del atributo id no se copia directamente del atributo de name, sino que se construye mediante una combinación del nombre y de cada valor. El motivo es que el atributo name debe tener el mismo valor para todos los radio button que se quieren definir como mutuamente excluyentes, al mismo tiempo que en una página HTML dos o más elementos no pueden disponer del mismo valor para su atributo id.

Symfony también incluye helpers de formularios para realizar peticiones asíncronas en segundo plano. El siguiente capítulo se centra en Ajax y proporciona todos los detalles.

10.1.3. Campos para introducir fechas

Muchos formularios permiten al usuario introducir fechas. Uno de los principales fallos en los datos de los formularios suele ser el formato incorrecto de las fechas. El helper input_date_tag() simplifica la introducción de fechas mostrando un calendario interactivo creado con JavaScript, tal y como muestra la figura 10-1. Para ello, se indica la opción rich con un valor de true.

Etiqueta para introducir la fecha mediante un calendario

Figura 10.1 Etiqueta para introducir la fecha mediante un calendario

Si no se utiliza la opción rich, el helper muestra 3 listas desplegables (<select>) cargadas con una serie de meses, días y años. También es posible mostrar por separado cada una de estas listas utilizando sus propios helpers (select_day_tag(), select_month_tag() y select_year_tag()). Los valores iniciales de estos elementos son el día, mes y año actuales. El listado 10-3 muestra los helpers disponibles para introducir fechas.

Listado 10-3 - Helpers para introducir datos

<?php echo input_date_tag('fechanacimiento', '2005-05-03', 'rich=true') ?>
 => Muestra un cuadro de texto y un calendario dinámico

// Los siguientes helpers requieren incluir el grupo de helpers llamado DateForm
<?php use_helper('DateForm') ?>

<?php echo select_day_tag('dia', 1, 'include_custom=Seleccione un día') ?>
=> <select name="dia" id="dia">
      <option value="">Seleccione un día</option>
      <option value="1" selected="selected">01</option>
      <option value="2">02</option>
      ...
      <option value="31">31</option>
    </select>

<?php echo select_month_tag('mes', 1, 'include_custom=Seleccione un mes use_short_month=true') ?>
=> <select name="mes" id="mes">
      <option value="">Seleccione un mes</option>
      <option value="1" selected="selected">Jan</option>
      <option value="2">Feb</option>
      ...
      <option value="12">Dec</option>
    </select>

<?php echo select_year_tag('ano', 2007, 'include_custom=Seleccione un año year_end=2010') ?>
 => <select name="ano" id="ano">
      <option value="">Seleccione un año</option>
      <option value="2006">2006</option>
      <option value="2007" selected="selected">2007</option>
      ...
    </select>

Los valores permitidos por el helper input_date_tag() son los mismos que admite la función strtotime() de PHP. El listado 10-4 muestra algunos de los listados que se pueden utilizar y el listado 10-5 muestra los que no se pueden emplear.

Listado 10-4 - Formatos de fecha válidos para los helpers de fecha

// Funcionan bien
<?php echo input_date_tag('prueba', '2006-04-01', 'rich=true') ?>
<?php echo input_date_tag('prueba', 1143884373, 'rich=true') ?>
<?php echo input_date_tag('prueba', 'now', 'rich=true') ?>
<?php echo input_date_tag('prueba', '23 October 2005', 'rich=true') ?>
<?php echo input_date_tag('prueba', 'next tuesday', 'rich=true') ?>
<?php echo input_date_tag('prueba', '1 week 2 days 4 hours 2 seconds', 'rich=true') ?>

// Devuelven un valor null
<?php echo input_date_tag('prueba', null, 'rich=true') ?>
<?php echo input_date_tag('prueba', '', 'rich=true') ?>

Listado 10-5 - Formatos de fecha incorrectos para los helpers de fecha

// Fecha de referencia = 01/01/1970
<?php echo input_date_tag('prueba', 0, 'rich=true') ?>

// Los formatos que no son válidos en inglés no funcionan
<?php echo input_date_tag('prueba', '01/04/2006', 'rich=true') ?>

10.1.4. Editor de textos avanzado

Las áreas de texto definidas mediante <textarea> se pueden utilizar como editor de textos avanzado gracias a la integración con las herramientas TinyMCE y FCKEditor. Estos editores muestran una interfaz similar a la de un procesador de textos, incluyendo botones para formatear el texto en negrita, cursiva y otros estilos, tal y como muestra la figura 10-2.

Editor de textos avanzado

Figura 10.2 Editor de textos avanzado

Los dos editores se tienen que instalar manualmente. Como el proceso es el mismo para los dos, sólo se explica cómo instalar el editor TinyMCE. En primer lugar, se descarga el editor desde la página web del proyecto (http://tinymce.moxiecode.com/) y se descomprime en una carpeta temporal. A continuación, se copia el directorio tinymce/jscripts/tiny_mce/ en la carpeta web/js/ del proyecto y se define la ruta a la librería en el archivo settings.yml, como se muestra en el listado 10-6.

Listado 10-6 - Definiendo la ruta de la librería TinyMCE

all:
  .settings:
    rich_text_js_dir:  js/tiny_mce

Una vez instalado, se puede activar el editor avanzado mediante la opción rich=true. También es posible definir opciones propias para el editor JavaScript mediante la opción tinymce_options. El listado 10-7 muestra algunos ejemplos.

**Listado 10-7 - Editores de texto avanzado **

<?php echo textarea_tag('nombre', 'valor inicial', 'rich=true size=10x20') ?>
 => se muestra un editor de textos avanzado creado con TinyMCE
<?php echo textarea_tag('nombre', 'valor inicial', 'rich=true size=10x20 tinymce_options=language:"fr",theme_advanced_buttons2:"separator"') ?>
=> se muestra un editor de textos avanzado creado con TinyMCE y personalizado con opciones propias

10.1.5. Selección de idioma, país y moneda

En ocasiones es necesario mostrar un campo de formulario para seleccionar un país. Como el nombre de los países varía en función del idioma en el que se muestran, las opciones de una lista desplegable de países deberían cambiar en función de la cultura del usuario (el Capítulo 13 incluye más información sobre el concepto de culturas). Como se muestra en el listado 10-8, el helper select_country_tag() automatiza este proceso: traduce el nombre de todos los países y utiliza como valor los códigos estándar definidos por el ISO.

Listado 10-8 - Helper para seleccionar un país

<?php echo select_country_tag('pais', 'AL') ?>
 => <select name="pais" id="pais">
      <option value="AF">Afghanistan</option>
      <option value="AL" selected="selected">Albania</option>
      <option value="DZ">Algeria</option>
      <option value="AS">American Samoa</option>
  ...

De forma similar a select_country_tag(), el helper select_language_tag() muestra una lista de idiomas, tal y como indica el listado 10-9.

Listado 10-9 - Helper para seleccionar un idioma

<?php echo select_language_tag('idioma', 'en') ?>
 => <select name="idioma" id="idioma">
      ...
      <option value="elx">Elamite</option>
      <option value="en" selected="selected">English</option>
      <option value="enm">English, Middle (1100-1500)</option>
      <option value="ang">English, Old (ca.450-1100)</option>
      <option value="myv">Erzya</option>
      <option value="eo">Esperanto</option>
      ...

El tercer helper es select_currency_tag(), que muestra una lista de monedas similar a la del listado 10-10.

Listado 10-10 - Helper para seleccionar una moneda

<?php echo select_currency_tag('moneda', 'EUR') ?>
 => <select name="moneda" id="moneda">
      ...
      <option value="ETB">Ethiopian Birr</option>
      <option value="ETD">Ethiopian Dollar</option>
      <option value="EUR" selected="selected">Euro</option>
      <option value="XBA">European Composite Unit</option>
      <option value="XEU">European Currency Unit</option>
      ...

Nota Los tres helpers anteriores aceptan un tercer parámetro opcional que corresponde a un array de opciones. Este parámetro se puede utilizar para restringir la lista de opciones que se muestran. En el helper de países la opción se llama countries y se indica de la siguiente forma: array('countries' => array ('FR', 'DE')). En el helper de los idiomas la opción se llama languages y en el de las monedas la opción se llama currencies.

Restringir la lista completa de opciones a un grupo de valores determinados es muy recomendable porque las listas pueden contener algunos elementos desfasados.

Por último, el helper select_currency_tag() dispone de otro parámetro opcional llamado display que permite controlar la forma en la que se muestran las monedas. Los valores que admite son symbol, code y name.