Los formularios de Symfony 1.4

11.2. Generando las clases del formulario

El gestor de artículos permite modificar la información de las tablas article, author, category y tag. Para ello, es preciso crear formularios asociados a cada tabla y configurar los widgets y validadores necesarios para cumplir las restricciones del esquema de la base de datos. Aunque los formularios se pueden crear a mano, se trata de una tarea repetitiva y tediosa que requiere repetir la misma información una y otra vez en diferentes archivos (el nombre de las columnas y los campos, el tamaño máximo de las columnas y campos, etc.) Además, cada vez que se modifica el modelo, es necesario modificar la clase del formulario asociado. Afortunadamente, el plugin de Doctrine incluye una tarea llamada doctrine:build-forms que automatiza todo este proceso y genera los formularios relacionados con el modelo de objetos:

$ ./symfony doctrine:build-forms frontend

La tarea de generación automática de formularios crea una clase para cada tabla y añade los validadores y widgets necesarios para cada columna mediante la introspección del modelo y teniendo en cuenta las relaciones entre tablas.

Nota Las tareas doctrine:build-all y doctrine:build-all-load también actualizan las clases de los formularios porque invocan automáticamente la tarea doctrine:build-forms.

Después de ejecutar estas tareas se crea una estructura de archivos en el directorio lib/form/. El siguiente listado muestra los archivos creados para el esquema utilizado en los ejemplos anteriores:

lib/
  form/
    doctrine/
      BaseFormDoctrine.class.php
      ArticleForm.class.php
      ArticleTagForm.class.php
      AuthorForm.class.php
      CategoryForm.class.php
      TagForm.class.php
      base/
        BaseArticleForm.class.php
        BaseArticleTagForm.class.php
        BaseAuthorForm.class.php
        BaseCategoryForm.class.php
        BaseFormDoctrine.class.php
        BaseTagForm.class.php

La tarea doctrine:build-forms genera dos clases para cada tabla del esquema, una clase base en el directorio lib/form/base y otra clase en el directorio lib/form/. Si se considera por ejemplo la tabla author, se crean las clases BaseAuthorForm y AuthorForm que se guardan en los archivos lib/form/base/BaseAuthorForm.class.php y lib/form/AuthorForm.class.php.

La siguiente tabla muestra la jerarquía de las diferentes clases relacionadas con el formulario AuthorForm.

Clase Paquete package Quién utiliza la clase Descripción
AuthorForm project Programador Redefine el formulario generado
BaseAuthorForm project Symfony Se basa en el esquema y se genera cada vez que se ejecuta la tarea doctrine:build-forms
BaseFormDoctrine project Programador Permite personalizar los formularios de Doctrine de forma global
sfFormDoctrine Plugin Doctrine Symfony Base de los formularios de Doctrine
sfForm symfony Symfony Base de los formularios de Symfony

El listado 11-2 muestra el código de la clase AuthorForm, utilizada para crear y modificar los objetos de la clase Author. Como se puede observar, esta clase no contiene ningún método, ya que hereda de la clase BaseAuthorForm que se genera a partir de la configuración. La clase AuthorForm se utiliza para personalizar y redefinir la configuración del formulario.

Listado 11-2 - La clase AuthorForm

class AuthorForm extends BaseAuthorForm
{
  public function configure()
  {
  }
}

El listado 11-3 muestra el código de la clase BaseAuthorForm con los validadores y widgets generados automáticamente mediante la instrospección del modelo de la tabla author.

Listado 11-3 - Clase BaseAuthorForm que representa al formulario de la tabla author

class BaseAuthorForm extends BaseFormDoctrine
{
  public function setup()
  {
    $this->setWidgets(array(
      'id'         => new sfWidgetFormInputHidden(),
      'first_name' => new sfWidgetFormInput(),
      'last_name'  => new sfWidgetFormInput(),
      'email'      => new sfWidgetFormInput(),
    ));

    $this->setValidators(array(
      'id'         => new sfValidatorDoctrineChoice(array('model' => 'Author', 'column' => 'id', 'required' => false)),
      'first_name' => new sfValidatorString(array('max_length' => 20, 'required' => false)),
      'last_name'  => new sfValidatorString(array('max_length' => 20, 'required' => false)),
      'email'      => new sfValidatorString(array('max_length' => 255)),
    ));

    $this->widgetSchema->setNameFormat('author[%s]');

    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);

    parent::setup();
  }

  public function getModelName()
  {
    return 'Author';
  }
}

La clase generada es muy similar a la de los formularios creados en los capítulos anteriores, salvo por las siguientes excepciones:

  • La clase base es BaseFormDoctrine en vez de sfForm
  • La configuración de los validadores y widgets se realiza en el método setup(), en vez de en el método configure()
  • El método getModelName() devuelve la clase de Doctrine relacionada con el formulario

Nota Las clases base utilizan el método setup() para su configuración en vez del método configure(). De esta forma es posible redefinir la configuración de las clases vacías generadas automáticamente sin utilizar una llamada a parent::configure().

Los nombres de los campos del formulario son idénticos a los nombres de las columnas del esquema de datos: id, first_name, last_name y email.

La tarea doctrine:build-forms genera un widget y un validador para cada columna de la tabla author cumpliendo las restricciones del esquema de datos. Esta tarea siempre genera los validadores más seguros posible. Si se considera el campo id, se podría comprobar simplemente si es un número entero válido. Sin embargo, el validador generado también comprueba que ese identificador exista en la base de datos (para modificar un objeto existente) o sea vacío (para poder crear un nuevo objeto). La validación generada automáticamente es mucho más segura que comprobar simplemente que sea un número entero.

La mayor ventaja de los formularios generados es que se pueden utilizar inmediatamente. Si se añade la instrucción <?php echo $form ?> en la página, ya se dispone de un formulario completamente funcional sin haber escrito ni una sola línea de código.

Además de la posibilidad de crear prototipos rápidamente, los formularios generados se pueden modificar sin necesidad de cambiar las clases generadas automáticamente, gracias a la herencia entre las clases base y las clases de los formularios.

Por último, cada vez que se modifica el esquema de la base de datos, esta tarea genera de nuevo todos los formularios para tener en cuenta las modificaciones manteniendo las modificaciones realizadas en las otras clases.