Una vez generadas las clases de los formularios, a continuación se crea un módulo de Symfony que permita trabajar con los objetos a través de un navegador. El objetivo es crear, modificar y borrar objetos de las clases Article
, Author
, Category
y Tag
.
En primer lugar se crea el módulo correspondiente a la clase Author
. Aunque este módulo se puede crear manualmente, el plugin de Doctrine incluye la tarea doctrine:generate-crud
para crear un módulo de tipo CRUD basado en la clase de un objeto del modelo. Si se emplea el mismo formulario que en la sección anterior:
$ ./symfony doctrine:generate-crud frontend author Author
La tarea doctrine:generate-crud
requiere tres argumentos:
frontend
: nombre de la aplicación en la que se crea el móduloauthor
: nombre del módulo creadoAuthor
: nombre de la clase del modelo para la que se crea el módulo
Nota CRUD es el acrónimo de las palabras inglesas "Creation / Retrieval / Update / Deletion" (Crear, Obtener, Actualizar y Borrar) que resumen las cuatro operaciones básicas que se realizan con los datos del modelo.
El listado 11-4 muestra que la tarea genera cinco acciones que permiten listar (index
), crear (create
), modificar (edit
), guardar (update
) y borrar (delete
) los objetos de la clase Author
.
Listado 11-4 - La clase authorActions
generada por la tarea
// apps/frontend/modules/author/actions/actions.class.php
class authorActions extends sfActions
{
public function executeIndex()
{
$this->authorList = $this->getAuthorTable()->findAll();
}
public function executeCreate()
{
$this->form = new AuthorForm();
$this->setTemplate('edit');
}
public function executeEdit($request)
{
$this->form = $this->getAuthorForm($request->getParameter('id'));
}
public function executeUpdate($request)
{
$this->forward404Unless($request->isMethod('post'));
$this->form = $this->getAuthorForm($request->getParameter('id'));
$this->form->bind($request->getParameter('author'));
if ($this->form->isValid())
{
$author = $this->form->save();
$this->redirect('author/edit?id='.$author->get('id'));
}
$this->setTemplate('edit');
}
public function executeDelete($request)
{
$this->forward404Unless($author = $this->getAuthorById($request->getParameter('id')));
$author->delete();
$this->redirect('author/index');
}
private function getAuthorTable()
{
return Doctrine::getTable('Author');
}
private function getAuthorById($id)
{
return $this->getAuthorTable()->find($id);
}
private function getAuthorForm($id)
{
$author = $this->getAuthorById($id);
if ($author instanceof Author)
{
return new ArticleForm($author);
}
else
{
return new ArticleForm();
}
}
}
El flujo de trabajo del formulario de este módulo se controla mediante los métodos create
, edit
y update
. Por tanto, la tarea doctrine:generate-crud
también puede generar un único método que se encargue de estas funcionalidades mediante la opción --non-atomic-actions
:
$ ./symfony doctrine:generate-crud frontend author Author --non-atomic-actions
El código generado con la opción --non-atomic-actions
(ver listado 11-5) es mucho más conciso.
Listado 11-5 - La clase authorActions
generada con la opción --non-atomic-actions
class authorActions extends sfActions
{
public function executeIndex()
{
$this->authorList = $this->getAuthorTable()->findAll();
}
public function executeEdit($request)
{
$this->form = new AuthorForm(Doctrine::getTable('Author')->find($request->getParameter('id')));
if ($request->isMethod('post'))
{
$this->form->bind($request->getParameter('author'));
if ($this->form->isValid())
{
$author = $this->form->save();
$this->redirect('author/edit?id='.$author->getId());
}
}
}
public function executeDelete($request)
{
$this->forward404Unless($author = Doctrine::getTable('Author')->find($request->getParameter('id')));
$author->delete();
$this->redirect('author/index');
}
}
Esta tarea también genera dos plantillas, indexSuccess
y editSuccess
. La plantilla editSuccess
generada no utiliza la instrucción <?php echo $form ?>
. Se puede modificar este comportamiento con la opción --non-verbose-templates
:
$ ./symfony doctrine:generate-crud frontend author Author --non-verbose-templates
Esta última opción es muy útil cuando se están creando los prototipos, tal y como muestra el listado 11-6.
Listado 11-6 - La plantilla editSuccess
// apps/frontend/modules/author/templates/editSuccess.php
<?php $author = $form->getObject() ?>
<h1><?php echo $author->isNew() ? 'New' : 'Edit' ?> Author</h1>
<form action="<?php echo url_for('author/edit'.(!$author->isNew() ? '?id='.$author->getId() : '')) ?>" method="post" <?php $form->isMultipart() and print 'enctype="multipart/form-data" ' ?>>
<table>
<tfoot>
<tr>
<td colspan="2">
<a href="<?php echo url_for('author/index') ?>">Cancel</a>
<?php if (!$author->isNew()): ?>
<?php echo link_to('Delete', 'author/delete?id='.$author->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 específicas para visualizar los datos de un objeto. Esta plantilla solamente permite visualizar los datos, no modificarlos.
Si accedes ahora a la dirección /frontend_dev.php/author
con un navegador, puedes visualizar el módulo generado automáticamente (ver figuras 11-1 y 11-2). Prueba a listar los autores, crear nuevos autores, modificar sus datos e incluso borrarlos gracias a la interfaz generada. Como puedes comprobar, las reglas de validación también se tienen en cuenta al crear o modificar los datos.
Si ahora se repite la operación con la clase Article
:
$ ./symfony doctrine:generate-crud frontend article Article --non-verbose-templates --non-atomic-actions
El código generado es muy parecido al código de la clase Author
. No obstante, si intentas crear un nuevo artículo, la aplicación produce el error fatal que se muestra en la figura 11-3.
El formulario ArticleForm
utiliza el widget sfWidgetFormDoctrineSelect
para representar la relación entre los objetos Article
y Author
. Este widget crea una lista desplegable con todos los autores disponibles. Cuando la aplicación trata de mostrar los autores, los objetos de tipo Author
se convierten en una cadena de texto gracias al método mágico __toString()
. Por lo tanto, es obligatorio definir el método __toString()
en la clase Author
tal y como muestra el listado 11-7.
Listado 11-7 - Definiendo el método __toString()
en la clase Author
class Author extends BaseAuthor
{
public function __toString()
{
return $this->getFirstName().' '.$this->getLastName();
}
}
De la misma forma que en la clase Author
, se pueden crear métodos __toString()
en las otras clases del modelo: Article
, Category
y Tag
.
Nota sfDoctrineRecord
intenta adivinar cuál es el método __toString()
adecuado si no lo encuentra. Para ello comprueba si existen columnas llamadas title
, name
, subject
, etc. Si existe alguna de esas columnas, la utiliza como representación del objeto en forma de cadena de texto.
Nota La opción method
del widget sfWidgetFormDoctrineSelect
establece el método utilizado para obtener la representación del objeto en forma de cadena de texto.
La figura 11-4 muestra cómo crear un artículo después de haber incluído el método __toString()
.