Más con Symfony

6.7. Mostrando los formularios embebidos

La plantilla _form.php actual del módulo product contiene el siguiente código:

// apps/frontend/module/product/templates/_form.php
<!-- ... -->

<tbody>
  <?php echo $form ?>
</tbody>

<!-- ... -->

La instrucción <?php echo $form ?> es la forma más sencilla de mostrar un formulario, incluso para los formularios más complejos. Aunque se trata de algo muy útil cuando se prototipa una aplicación, se debe sustituir por tu propio código si quieres modificar la forma en la que se muestra el formulario. Borra esa línea de código porque se va a reemplazar en esta misma sección.

Lo más importante que hay que saber al mostrar formularios embebidos en la vista es la organización multidimensional del array widgetSchema que se explicó en la sección anterior. En este ejemplo se empieza mostrando los campos básicos name y price del formulario ProductForm:

// apps/frontend/module/product/templates/_form.php
<?php echo $form['name']->renderRow() ?>

<?php echo $form['price']->renderRow() ?>

<?php echo $form->renderHiddenFields() ?>

Como su propio nombre indica, renderHiddenFields() incluye todos los campos ocultos del formulario.

Nota El código de las acciones se ha omitido a propósito porque no requiere de ninguna atención especial. Puedes echar un vistazo al código del archivo apps/frontend/modules/product/actions/actions.class.php. Su aspecto es el de cualquier CRUD normal y se puede generar automáticamente mediante la tarea doctrine:generate-module.

Como se acaba de explicar, la clase sfForm incluye los arrays widgetSchema y validatorSchema que definen nuestros campos. Además, la clase sfForm implementa la interfaz nativa de PHP 5 ArrayAccess, lo que significa que se puede acceder directamente a los campos de un formulario utilizando la sintaxis de los arrays mostrada anteriormente.

Para mostrar los campos en la vista, se pueden acceder directamente invocando el método renderRow(). ¿Qué tipo de objeto es $form['name']? Aunque puede que pienses que la respuesta es el widget sfWidgetFormInputText del campo name, la respuesta correcta es ligeramente diferente.

6.7.1. Mostrando cada campo de formulario con sfFormField

La clase sfForm genera automáticamente un tercer array llamado sfFormFieldSchema utilizando los arrays widgetSchema y validatorSchema definidos en cada clase de formulario. Este array contiene un objeto especial para cada campo que actúa como una clase de tipo helper encargada de mostrar cada campo. El objeto, de tipo sfFormField, es una combinación del widget y el validador de cada campo y se crea de forma automática.

<?php echo $form['name']->renderRow() ?>

En el código anterior, $form['name'] es un objeto de tipo sfFormField, que incluye el método renderRow() junto con muchas otras funciones útiles para mostrar los campos.

6.7.2. Métodos de sfFormField

Cada objeto sfFormField se puede emplear para mostrar fácilmente cada aspecto del campo al que representa (por ejemplo el propio campo, su título, los mensajes de error, etc.) A continuación se muestran algunos de los métodos más útiles de sfFormField. El resto de métodos los puedes consultar en la API de Symfony 1.3.

  • sfFormField->render(): muestra el campo del formulario (es decir, la etiqueta <input>, <select>, etc.) con su valor correcto de acuerdo al objeto del widget del campo.
  • sfFormField->renderError(): muestra cualquier error de validación del campo utilizando el objeto del validador del campo.
  • sfFormField->renderRow(): todo en uno que muestra el título, el campo de formulario, los errores y los mensajes de ayuda dentro de un contenedor de código XHTML.

Nota En realidad, cada función de visualización de la clase sfFormField también utiliza información de la propiedad widgetSchema del formulario (el objeto sfWidgetFormSchema que incluye todos los widgets del formulario). Esta clase ayuda en la generación de los atributos name e id de cada campo, genera el título de cada campo y define el código XHTML utilizado por renderRow().

Otro aspecto importante es que el array formFieldSchema siempre es idéntico a la estructura de los arrays widgetSchema y validatorSchema del formulario. El array formFieldSchema por ejemplo del formulario ProductForm completo tendría la siguiente estructura, que es imprescindible para mostrar cada campo del formulario:

formFieldSchema    => array
(
  [id]          => sfFormField
  [name]        => sfFormField,
  [price]       => sfFormField,
  [newPhotos]   => array(
    [0]           => array(
      [id]          => sfFormField,
      [filename]    => sfFormField,
      [caption]     => sfFormField,
    ),
    [1]           => array(
      [id]          => sfFormField,
      [filename]    => sfFormField,
      [caption]     => sfFormField,
    ),
  ),
)

6.7.3. Mostrando el nuevo ProductForm

Utilizando el array superior como una especie de mapa, se pueden mostrar fácilmente los campos del formulario ProductPhotoForm embebido localizando y mostrando los objetos sfFormField adecuados:

// apps/frontend/module/product/templates/_form.php
<?php foreach ($form['newPhotos'] as $photo): ?>
  <?php echo $photo['caption']->renderRow() ?>
  <?php echo $photo['filename']->renderRow() ?>
<?php endforeach; ?>

El bloque de código anterior se ejecuta dos veces, una para el array de campos de formulario 0 y otra para el array de campos de formulario 1. Como se observa en el diagrama anterior, los objetos asociados con cada array son objetos de tipo sfFormField, que se pueden mostrar como cualquier otro campo.