Los formularios de Symfony 1.4

4.3. El generador CRUD

Después de generar todas las clases del formulario, ahora se muestra cómo crear un módulo de Symfony que permita trabajar con todos los objetos a través del navegador web. En los siguientes ejemplos se muestra cómo crear, modificar y borrar objetos de las clases Articulo, Autor, Categoria y Etiqueta.

En primer lugar se crea el modelo de la clase Autor. Aunque el módulo se puede crear a mano, el plugin de Propel incluye una tarea llamada propel:generate-crud que genera un módulo de tipo CRUD basado en una clase del modelo de objetos de Propel:

$ ./symfony propel:generate-crud frontend autor Autor

La tarea propel:generate-crud requiere tres argumentos:

  • frontend: nombre de la aplicación en la que se va a crear el módulo
  • autor: nombre del módulo que se va a crear
  • Autor: nombre de la clase del modelo en la que se basa el módulo

Nota El acrónimo CRUD significa Creation / Retrieval / Update / Deletion (Crear / Obtener / Modificar / Borrar) que son las cuatro operaciones básicas que se realizan sobre la información del modelo de datos.

En el listado 4-4 se muestran las cinco acciones que genera la tarea sobre la clase Autor: listar la información (index), crear nuevos objetos (create), modificar los objetos existentes (edit), guardar los cambios realizados (update) y borrar los objetos (delete).

Listado 4-4 - La clase autorActions generada por la tarea

// apps/frontend/modules/autor/actions/actions.class.php
class autorActions extends sfActions
{
  public function executeIndex()
  {
    $this->autorList = AutorPeer::doSelect(new Criteria());
  }

  public function executeCreate()
  {
    $this->form = new AutorForm();

    $this->setTemplate('edit');
  }

  public function executeEdit($request)
  {
    $this->form = new AutorForm(AutorPeer::retrieveByPk($request->getParameter('id')));
  }

  public function executeUpdate($request)
  {
    $this->forward404Unless($request->isMethod('post'));

    $this->form = new AutorForm(AutorPeer::retrieveByPk($request->getParameter('id')));

    $this->form->bind($request->getParameter('autor'));
    if ($this->form->isValid())
    {
      $autor = $this->form->save();

      $this->redirect('autor/edit?id='.$autor->getId());
    }

    $this->setTemplate('edit');
  }

  public function executeDelete($request)
  {
    $this->forward404Unless($autor = AutorPeer::retrieveByPk($request->getParameter('id')));

    $autor->delete();

    $this->redirect('autor/index');
  }
}

En este módulo, el flujo de trabajo del formulario está definido por los métodos create, edit y update. También es posible indicar a la tarea propel:generate-crud que genere sólo un método que incluya las tres funcionalidades anteriores, mediante la opción --non-atomic-actions:

$ ./symfony propel:generate-crud frontend autor Autor --non-atomic-actions

El código generado mediante la opción --non-atomic-actions (ver listado 4-5) es mucho más conciso.

Listado 4-5 - La clase autorActions generada con la opción --non-atomic-actions

class autorActions extends sfActions
{
  public function executeIndex()
  {
    $this->autorList = AutorPeer::doSelect(new Criteria());
  }

  public function executeEdit($request)
  {
    $this->form = new AutorForm(AutorPeer::retrieveByPk($request->getParameter('id')));

    if ($request->isMethod('post'))
    {
      $this->form->bind($request->getParameter('autor'));
      if ($this->form->isValid())
      {
        $autor = $this->form->save();

        $this->redirect('autor/edit?id='.$autor->getId());
      }
    }
  }

  public function executeDelete($request)
  {
    $this->forward404Unless($autor = AutorPeer::retrieveByPk($request->getParameter('id')));

    $autor->delete();

    $this->redirect('autor/index');
  }
}

Esta tarea también genera dos plantillas, indexSuccess y editSuccess. La plantilla editSuccess generada no utiliza la instrucción <?php echo $form ?>. Para modificar este comportamiento, se utiliza la opción --non-verbose-templates:

$ ./symfony propel:generate-crud frontend autor Autor --non-verbose-templates

Esta opción es muy útil mientras se construye el prototipo de la aplicación, tal y como muestra el listado 4-6.

Listado 4-6 - La plantilla editSuccess

// apps/frontend/modules/autor/templates/editSuccess.php
<?php $autor = $form->getObject() ?>
<h1><?php echo $autor->isNew() ? 'New' : 'Edit' ?> Autor</h1>

<form action="<?php echo url_for('autor/edit'.(!$autor->isNew() ? '?id='.$autor->getId() : '')) ?>" method="post" <?php $form->isMultipart() and print 'enctype="multipart/form-data" ' ?>>
  <table>
    <tfoot>
      <tr>
        <td colspan="2">
          &nbsp;<a href="<?php echo url_for('autor/index') ?>">Cancel</a>
          <?php if (!$autor->isNew()): ?>
            &nbsp;<?php echo link_to('Delete', 'autor/delete?id='.$autor->getId(), array('post' => true, 'confirm' => 'Are you sure?')) ?>
          <?php endif; ?>
          <input type="submit" value="Save" />
        </td>
      </tr>
    </tfoot>
    <tbody>
      <?php echo $form ?>
    </tbody>
  </table>
</form>

Nota La opción --with-show permite generar una acción y una plantilla para visualizar objetos (sólo en modo lectura).

Si ahora se accede a la dirección /frontend_dev.php/autor, ya se puede utilizar el módulo generado (figuras 4-1 y 4-2). Juega un poco con la interfaz y añade algo de información. El módulo generado permite listar, añadir, modificar y borrar autores. Además, puedes comprobar que las reglas de validación también se aplican a los formularios.

Listado de autores

Figura 4.1 Listado de autores

Modificando los datos de un autor con errores de validación

Figura 4.2 Modificando los datos de un autor con errores de validación

A continuación se realiza la misma operación sobre la clase Articulo:

$ ./symfony propel:generate-crud frontend articulo Articulo --non-verbose-templates --non-atomic-actions

El código generado es muy parecido al código de la clase Autor. Sin embargo, si se intenta crear un artículo nuevo, el código lanza un error fatal que se muestra en la figura 4-3.

Las tablas relacionadas deben definir el método __toString()

Figura 4.3 Las tablas relacionadas deben definir el método __toString()

El formulario ArticuloForm utiliza el widget sfWidgetFormPropelSelect para representar la relación entre los objetos Articulo y Autor. Este widget crea una lista desplegable con todos los autores disponibles. Para mostrar los autores, los objetos de tipo Autor se convierten en una cadena de texto mediante el método mágico __toString(), que debe estar definido en la clase Autor, como se muestra en el listado 4-7.

Listado 4-7 - Añadiendo el método __toString() en la clase Autor

class Autor extends BaseAutor
{
  public function __toString()
  {
    return $this->getNombre().' '.$this->getApellidos();
  }
}

Siguiendo el ejemplo de la clase Autor, también se pueden crear métodos __toString() en las clases Articulo, Categoria y Etiqueta.

Nota La opción method del widget sfWidgetFormPropelSelect permite establecer el nombre del método que se utiliza para convertir el objeto en texto.

La figura 4-4 muestra cómo crear un artículo después de incluir el método __toString() en la clase Autor.

Creando un artículo

Figura 4.4 Creando un artículo