Crear un CRUD o ABM con Zend Framework

Por zsamer en Noviembre 24, 2008

En este artículo veremos como agregar/eliminar/modificar datos de una base de datos utilizando Zend_Db_Table.

En informática CRUD es el acrónimo de Crear, Obtener, Actualizar y Borrar (Create, Read, Update y Delete en inglés). Es usado para referirse a las funciones básicas en bases de datos o la capa de persistencia en un sistema de software. En algunos lugares, se utilizan las siglas ABM para lo mismo (Alta Baja Modificación), obviando la operación de Obtener. A veces se nombra ABML siendo la ultima letra (L) de listar, listado o lectura, etc.

Crear una Tabla

Vamos a utilizar MySQL, así que las sentencias SQL para crear la tabla son:

SQL:
  1. CREATE TABLE album (
  2. id int(11) NOT NULL AUTO_INCREMENT,
  3. artist varchar(100) NOT NULL,
  4. title varchar(100) NOT NULL,
  5. PRIMARY KEY (id)
  6. )

Utiliza esta sentencia en un cliente MySQL como phpAdmin o mediante la línea de comandos de MySQL.

Agregar estos Álbumes.

Vamos a insertar unos registros a la tabla, para realizar pruebas de la funcionalidad de acceso a la información desde la pagina inicial (home). Vamos a tomar los primeros los CD’s del “Hot 100” de Amazon.co.uk:

SQL:
  1. INSERT INTO album (artist, title) VALUES ('James Morrison', 'Undiscovered'),
  2. ('Snow Patrol', 'Eyes Open');

El Modelo (model)

Zend_Db_Table es una clase abstracta, así que debemos de proporcionar una descripción específica para gestionar álbumes. No importa como llamemos a nuestra clase, pero es de sentido común asignarle el nombre de la tabla de la base de datos. Así que nuestra clase se llamara Album ya que nuestra tabla se llama album. Se le va indicar el nombre de la tabla a Zend_Db_Table para que la gestione, debemos de proteger el nombre de la tabla utilizando la propiedad $_name. Zend_Db_Table asume que la tabla tiene una llave primaria que tiene habilitada la opción de auto-increment. El nombre de este campo puede ser modificado si así se desea.
Vamos a guardar la clase Album en el directorio de models:

quickstart/application/models/Album.php

PHP:
  1. <?php
  2. class Album extends Zend_Db_Table
  3. {
  4.     protected $_name = 'album';
  5. }

Afortunadamente para nosotros los requisitos son sencillos, ya Zend_Db_Table resuelve toda la funcionalidad que necesitamos. Sin embargo si necesitas agregar mayor funcionalidad a model, entonces este es el lugar adecuado para ponerlo. Por lo general, alguna de las funcionalidades extras será específica de los métodos de búsqueda para encontrar algún tipo de dato que se requiera. También podemos pedirle información relacionada de varias tablas a Zend_Db_Table para que encuentre los datos solicitados.
Nuestra clase modelo extiende a la clase Zend_Db_Table_Abstract, esta última implementa un conocido patrón de diseño llamadoTable Data Gateway y Row Data Gateway

Listado de los Álbumes

Ahora que hemos inicializado la configuración y la información de la base de datos, podemos entrar de lleno al código de la aplicación y mostrar el listado de los CD’s. La clase controladora que se encargará de realizar esta tarea será la clase AlbumController. Está muy claro que cada acción (action) dentro del AlbumController estará manipulando la base de datos de album por medio de la clase Album, así que cargaremos la clase album cuando inicializamos el controlador (controller). A través del método init():

quickstart /application/controllers/AlbumController.php

PHP:
  1. class AlbumController extends Zend_Controller_Action
  2. {
  3.     /**
  4.      * FlashMessenger
  5.      *
  6.      * @var Zend_Controller_Action_Helper_FlashMessenger
  7.      */
  8.     protected $_flashMessenger = null;
  9.    
  10.     public function init()
  11.     {       
  12.         $this->initView();
  13.         $this->_flashMessenger = $this->_helper->FlashMessenger;
  14.             $this->view->baseUrl = $this->_request->getBaseUrl();
  15.         $this->view->messages = $this->_flashMessenger;
  16.             Zend_Loader::loadClass('Album');
  17.     }
  18. }

Esto es un ejemplo de una implementación de Zend_Loader::loadClass() para cargar nuestras propias clases, funciona correctamente porque hemos incluido la ruta de nuestro directorio de models dentro del archivo index.php.

Vamos a mostrar la lista de nuestros álbumes en una tabla dentro de indexAction():
quickstart /application/controllers/AlbumController.php

PHP:
  1. /*...*/
  2.     public function indexAction()
  3.     {
  4.         $this->view->title = "Listado de Albums";
  5.         $album = new Album();
  6.         $this->view->albums = $album->fetchAll();
  7.     }
  8. /*...*/

La función Zend_Db_Table::fetchAll() nos regresa un Zend_Db_Table_Rowset que nos permitirá interactuar con los registros plasmados en el template de nuestro archivo view:

quickstart /application/views/scripts/album/index.phtml

PHP:
  1. <?php if(count($this->messages->getMessages())>0):?>
  2. <h3 style="color:#FFCB3F"><?php echo current($this->messages->getMessages()); ?>&nbsp;</h3>
  3. <?php endif;?>
  4. <h3><?php echo $this->escape($this->title); ?></h3>
  5. <p><a href="<?php echo $this->baseUrl; ?>/album/add">Nuevo Album</a></p>
  6. <table>
  7. <tr>
  8. <th>T&iacute;tulo</th>
  9. <th>Artista</th>
  10. <th>&nbsp;</th>
  11. </tr>
  12. <?php foreach($this->albums as $album) : ?>
  13. <tr>
  14. <td><?php echo $this->escape($album->title);?></td>
  15. <td><?php echo $this->escape($album->artist);?></td>
  16. <td>
  17. <a href="<?php echo $this->baseUrl; ?>/album/edit/id/<?php echo $album->id;?>">Editar</a>
  18. <a href="<?php echo $this->baseUrl; ?>/album/delete/id/<?php echo $album->id;?>" onclick="return confirm('¿Está seguro que desea eliminar album <?php echo $this->escape($album->title);?>?')">Eliminar</a>
  19. </td>
  20. </tr>
  21. <?php endforeach; ?>
  22. </table>

Si nos dirigimos a esta dirección http://localhost/quickstart/public/album (o cualquier ruta que hayan decidido) debe de mostrarnos una lista de dos álbumes.

Agregar nuevos Álbumes

Ahora podemos ver la funcionalidad para agregar nuevos álbumes. Lo cual se puede dividir en dos partes:
1. Mostrar al usuario un formulario con los detalles.
2. Procesar el envió del formulario y almacenar la información en la base de datos.
Todo esto se realiza dentro de addAction():
quickstart/application/controllers/AlbumController.php

PHP:
  1. /*...*/
  2.  
  3.     public function addAction()
  4.     {
  5.         $this->view->title = "Agregar nuevo Album";
  6.         $form = $this->_getForm();
  7.         $form->setAction($this->view->baseUrl . '/album/add');
  8.  
  9.         if($this->getRequest()->isPost()) {
  10.             $formData = $this->_request->getPost();
  11.             if (!$form->isValid($formData)) {
  12.                 $this->view->form = $form;
  13.                 $form->populate($formData);
  14.                 return $this->render('form');
  15.             }
  16.            
  17.             try {
  18.                 $albumModel = new Album();
  19.                 $album = $albumModel->createRow();
  20.                 $album->artist = $form->getValue('artist');
  21.                 $album->title = $form->getValue('title');
  22.                 $album->save();
  23.                 $this->_flashMessenger->addMessage('Album ha sido guardado con &eacute;xito');
  24.                 $this->_redirect('/album/');
  25.             } catch (Exception $e) {
  26.                 $this->_flashMessenger->addMessage($e->getMessage());
  27.             }
  28.         }
  29.        
  30.         $this->view->form = $form;
  31.         $this->render('form');
  32.     }
  33.  
  34.     private function _getForm()
  35.     {
  36.         $form = new Zend_Form();
  37.         $form->setMethod('post');
  38.  
  39.         // Crear y configurar el elemento artist:
  40.         $artist = $form->createElement('text', 'artist');
  41.         $artist->setLabel('Artista')
  42.                ->addValidator(new Zend_Validate_Alnum(true))
  43.                ->setRequired(true);
  44.  
  45.         // Crear y configurar el elemento title:
  46.         $title = $form->createElement('text', 'title');
  47.         $title->setLabel('Título')
  48.               ->addValidator(new Zend_Validate_Alnum(true))
  49.               ->setRequired(true);
  50.  
  51.         // Agregar los elementos al form:
  52.         $form->addElement($artist)
  53.              ->addElement($title)
  54.              ->addElement('submit', 'add', array('label' => 'Add'));
  55.  
  56.         return $form;
  57.     }
  58. /*...*/

Hay que observar cómo se analiza la variable $_SERVER['REQUEST_METHOD'] para verificar que el formulario haya sido enviado. Si se ha enviado, obtenemos el objeto formulario con su los validadores y filtros correspondiente, para asegurarnos que ningún código HTML sea permitido. Después asumimos que se han llenado los campos correspondientes, hacemos uso de la clase Album(), para registrarlos en la base de datos. Después de agregar el nuevo registro, los redirigimos a la raíz de la aplicación con el método _redirect().

Para finalizar configuramos el view con el template adecuado para la forma. Adelantándonos un poco, podemos visualizar que la forma edit action será similar a esta, por eso utilizaremos un mismo template (form.phtml) que será llamado desde la acción add y edit:
La vista para agregar un álbum:
quickstart/application/views/scripts/album/form.phtml

PHP:
  1. <?php echo $this->title;?>
  2. <?php echo $this->form;?>

Modificar un Álbum

Modificar un álbum es casi idéntico que agregarlo, así que el código es similar:
quickstart /application/controllers/AlbumController.php

PHP:
  1. /*...*/
  2.     public function editAction()
  3.     {
  4.         $id = (int)$this->_request->getParam('id', 0);
  5.         $this->view->title = "Editar Album";
  6.         $form = $this->_getForm();
  7.         $form->setAction($this->view->baseUrl . '/album/edit/id/' . $id);
  8.        
  9.         $albumModel = new Album();
  10.         $album = $albumModel->find($id)->current();
  11.        
  12.         if (null === $album) {
  13.             $this->_flashMessenger->addMessage('Este Album no existe');
  14.             $this->_redirect('/album');
  15.         }
  16.        
  17.         if ($this->_request->isPost())
  18.         {
  19.             $formData = $this->_request->getPost();
  20.             if (!$form->isValid($formData)) {
  21.                 $this->view->form = $form;
  22.                 $form->populate($formData);
  23.                 return $this->render('form');
  24.             }
  25.            
  26.             try {
  27.                 $album->artist = $form->getValue('artist');
  28.                 $album->title = $form->getValue('title');
  29.                 $album->save();
  30.                 $this->_flashMessenger->addMessage('Album ha sido guardado con &eacute;xito');
  31.                 $this->_redirect('/album/');
  32.             } catch (Exception $e) {
  33.                 $this->_flashMessenger->addMessage($e->getMessage());
  34.             }
  35.         }
  36.  
  37.         $this->view->album = $album;
  38.         $form->populate($this->view->album->toArray());
  39.         $this->view->form = $form;
  40.         $this->render('form');
  41.     }
  42. /*...*/

Utiliza la misma vista que la acción add. form.phtml

Eliminar un Album

Para terminar nuestra aplicación debemos de añadir la eliminación de registros. Tenemos un enlace “Delete” junto a cada registro de nuestra lista, sería muy ingenuo de nuestra parte si se eliminara al hacer click en dicho enlace. Esto sería erróneo. Si recordamos las especificaciones HTML, podemos recordar que no debemos llevar a cabo una acción irreversible con GET sin antes confirmar por seguridad. Debemos mostrar una forma de confirmación cuando el usuario realice clic en “Delete” y después presionan el botón de “Aceptar”, llevamos a cabo la eliminación. El código se asemeja al action de “edit” y “add”:

quickstart /application/controllers/AlbumController.php

PHP:
  1. /*...*/
  2.     public function deleteAction()
  3.     {
  4.         $id = (int)$this->_request->getParam('id', 0);
  5.        
  6.         $albumModel = new Album();
  7.         $album = $albumModel->find($id)->current();
  8.        
  9.         if (null !== $album) {
  10.             try {
  11.                 $album->delete();
  12.                 $this->_flashMessenger->addMessage('Album ha sido borrado con &eacute;xito');
  13.             } catch (Exception $e) {
  14.                 $this->_flashMessenger->addMessage($e->getMessage());
  15.             }
  16.         } else{
  17.             $this->_flashMessenger->addMessage('Este Album no existe');
  18.         }
  19.  
  20.         $this->_redirect('/album');
  21.     }
  22. /*...*/

Hay que hacer nota, que hacemos un “redirect” después de ejecutar la eliminación del objeto. Esto se hace con fin de poder redirigirnos de vuelta al listado de los álbumes al final de la función. Además verifica que el objeto fue encontrado en la base de datos antes de ejecutar su eliminación.

Espero que haya sido de utilidad.

;-)

Comentarios

32 Responses to “Crear un CRUD o ABM con Zend Framework”

  1. Daniel on Noviembre 24th, 2008 10:36 am

    Magnifico tutorial! (como todos), además se puede encajar con el que hiciste hace poco de tu clase Grid. Muy buen trabajo!
    ¿Qué utilizas para mostrar el código en los tutoriales de forma tan clara?
    Gracias y hasta pronto.

  2. zsamer on Noviembre 24th, 2008 11:56 am

    Gracias Daniel, así es, para mi es un gusto compartir y trato de hacer lo mejor posible.

    ;-)

  3. Pablo Morales on Noviembre 24th, 2008 1:05 pm

    Muy bueno como siempre negro.

    Lastima que seguis usando metodos que no son action en el controller :P

  4. meneame.net on Noviembre 24th, 2008 1:12 pm

    Crear un Crud,o Abm con Zend Framework…

    Una guia como crear un modulo para alta baja modificaciones, y listado de datos….

  5. zsamer on Noviembre 24th, 2008 1:50 pm

    Pablo no entendí: “Lastima que seguis usando metodos que no son action en el controller.” ¿Por qué?

    Quien dice que no se pueda o no sea buenas prácticas. Las mejores practicas lo hacen, solo basta ver los ejemplos de la propio Zend en su quickstart, Magento lo hace a menudo en sus controladores.

    Controller es una clase más que implementa cierta interfaz y debe tener los métodos que sea necesario para su función ya sean action o no, como por ejemplo _upload, _save o alguna operación repetitiva de lógica de negocio, para reutilizar código.

    En el caso del formulario también hay otra opción quizás sea la mejor, pero es más larga y ampliaría el tutorial, lo que no sería lo optimo. Esta otra opción es crear nuestro propio form que herede del Zend_Form y en el metodo init() hacer toda la operación para crear el formulario, pero insisto no era el caso de este tutorial.

    Si nos remontamos a otros framework como spring de java que tiene una implementación MVC muy parecida a la de ZF en muchos ejemplos sus controladores tienen métodos que no son necesariamente action.

  6. Daniel on Noviembre 24th, 2008 2:42 pm

    Hola Zsamer,
    ¿Cómo haces para presentar el código en tu blog? Quiero decir, con los números, colores y cada función con su link al manual de php. ?Usas algún script? Te estaría muy agradecido si me lo dijeras.
    Gracias y hasta pronto.

  7. Pablo Morales on Noviembre 24th, 2008 3:09 pm

    @zsamer: Me parece mucho mas limpio que un controller, solo contengan los Action, que de hecho es la funcion de la C en MVC, el mismo codigo que estas usando ahi deberia ser un Helper. Pero puede ser manias mias. Con un helper es bastante claro, pero obviamente te va a llevar mas lineas en este post.

    @Daniel: http://www.deanlee.cn/wordpress/code_highlighter_plugin_for_wordpress/

  8. zsamer on Noviembre 24th, 2008 11:17 pm

    Daniel, yo uso el plugins de wordpress: wp plugins gsyntax-hiliter.

    saludos.

  9. Asinox on Noviembre 25th, 2008 5:07 pm

    Excelente tutorial, mucho mejor en español.

    Saludos

  10. Asinox on Noviembre 25th, 2008 5:12 pm

    Me ha gustado mucho como ha mantenido todos los tutoriales basado en un solo proyecto “quickstar” :)

    Saludos

  11. Asinox on Noviembre 25th, 2008 6:57 pm

    Pablo: podrias hacer un tutorial de la forma en que dices?, por que me he quedado con esa duda sobre “no son Action”, necesitaria un ejemplo vivo para saber de que hablas, pues tenia pensado que http://controller/action/parametro era como funcionaba la cosa….

    Saludo

  12. Asinox on Noviembre 25th, 2008 7:09 pm

    No es por nada…. jejeje el mensaje de confirmacion con JS … exactamente de donde sale?

    En la documentacion de ZendF, en que parte puedo leer al respecto?

    Saludos

    Nota: cuando trato de eliminar un registro, me da error sobre “que no se encontro el delete.phtml”, pero igual crearlo no cuesta nada.

    Saludos

  13. Asinox on Noviembre 25th, 2008 7:11 pm

    mmm hice el detele.phtml , pero hay un problema, al borrar el registro me lleva al delete.phtml y tengo que darle refresh para que vuelva al listado de albumnes….

    Algo suelto?

    Saludos

  14. zsamer on Noviembre 25th, 2008 7:39 pm

    Asinox, debería de funcionar tal como esta en tutorial, si no te redirige después de eliminar debes de tener algún problema. Puede ser que tengas alguna salida html antes del _redirect, o alguna otra cosa.

    En todo caso prueba con los siguiente:

    Al final del método deleteAction agrega exit();

    Ej:
    $this->_redirect(’/album’);
    exit();

  15. Asinox on Noviembre 26th, 2008 4:55 am

    Creo que me perdi de algo, pero no sé si en algun lado habian creado el controller Album…por que aqui en este Post no esta, pero igual todo esta bien, solo he cambiado las referencias al controlador album por indexController, ya que tengo este tutorial en ese controller…todo bien, solo queria aclarar que no vi en ningun lado donde se creaba el controlador Album…

    En cuanto al error al eliminar…pues copie el codigo tuyo sobre el que habia escrito yo mirandolo…y perfecto

    Gracias, con este Post en verdad he empezado a comprender ZF mucho mejor…este post me ayudo mucho, ahora entiendo mucho mejor un libro que tengo.

    Saludos

  16. zsamer on Noviembre 26th, 2008 12:17 pm

    Asinox, tienes toda la razón se me fué ese detalle, donde en realidad la clase Controladora (Controller) debería ser AlbumController y no indexController. Ya lo arreglé.

    O bien como dices que sea indexController y modificar los redirect al index:

    $this->_redirect(’/index’);

  17. Pablo Morales on Noviembre 26th, 2008 1:40 pm

    @Asinox: ya estoy haciendo un tutorial, no con tanta calidad y prolijidad como los de Zsamer, pero estoy en eso.

  18. Asinox on Noviembre 26th, 2008 2:03 pm

    Gracias a ambos :)

    Pablo, pues es que me interesa ver eso tambien…

    Saludos :)

  19. Gus on Noviembre 27th, 2008 1:51 am

    Muy bueno el tutorial, una consulta, estoy empezando con ZF, y no entiendo bien como se puede ‘acomodar’ el render de un zend_form, es decir, ubicacion de campos y botones use display groups pero no entiendo de fondo como acomodar los elementos del form con flexibilidad.
    Espero me entiendan
    Saludos

  20. zsamer on Noviembre 27th, 2008 12:29 pm

    Por defecto los elementos se ordenan por orden de ingreso al objeto form, además se puede configurar el orden con el método setOrder del objeto elemento.

    Para más te aconsejo que leas el manual oficial ahí se explica bien detallado.

    saludos.

  21. Diego Sapriza on Noviembre 28th, 2008 6:15 pm

    muy bueno!

  22. Proyecto BlogZf - Parte 3 | Blog personal de Pablo Morales on Diciembre 4th, 2008 1:41 pm

    [...] buen ejemplo de como crear un CRUD con Zend Framework  lo tenemos en el blog de Zsamer. Lo primero que tenemos que hacer es configurar la conexion a la base de datos, los datos de esta [...]

  23. Top Posts 2008 | Zend Framework: Estado del Arte on Febrero 2nd, 2009 2:09 pm

    [...] Crear un CRUD o ABM con Zend Framework [...]

  24. paolo on Febrero 28th, 2009 3:13 pm

    Holas Zsamer talves ya dejastes este blog o este post por ser antiguo pero por fis necesito una ayuda mira que he estado haciendo el CRUD pero no me resulta nada al momento de hacer as actualiaciones es decir le doy a update y me retorna uno le doy a save de la forma en que lo planteas en el blog pero tambien solo me retorna 1 este es mi codigo


    $personaModel = new PersonaModel ( );
    // $where = $personaModel->getAdapter ()->quoteInto ( 'id_persona', $id );
    try {
    // print_r($valuesForm);
    $persona = $personaModel->find($id)->current(); //array('id_persona'=>$id));
    print_r($persona->id_persona);
    $persona->nombres=$valuesForm['nombres'];
    $persona->apellido_paterno = $valuesForm['apellido_apterno'];
    $persona->apellido_materno = $valuesForm['apellido_materno'];
    $persona->telefono = $valuesForm['telefono'];
    $persona->save();
    echo “Los datos de la persona se modificaron correctamente”;

    } catch ( Exception $error ) {
    echo “error al guardar los datos” + $error;
    }

    donde $valuesForm son los valores que me llegan desde el formulario, ha estoy enviando los datos via ajax y la respuesta tambien con json y jquery
    plis te estare agradecido por la ayuda

  25. wilson on Julio 4th, 2009 5:15 am

    Hola zsamer

    Me preguntaba por que ZF, no tiene un generador de admin automatico, asi como synfony o django.Ya que esto me ahorraria un monton de tiempo.

    Si alguien lo ha creado y tuvieras conocimiento de ello, me podrias enviar alguna referencia para buscarlo y analizarlo

    Si no fue creado, crees que seria bueno implementar uno y cual seria el grado de complejidad para crearlo osea que tan dificil seria el implementarlo.

    De antemano Gracias por tu respuesta

  26. maxi on Julio 27th, 2009 3:48 am

    hola intente probar la primer parte solo la de ver la lista de albumnes y me arroja el siguiente error.

    Fatal error: Call to a member function getMessages() on a non-object in F:\wamp\www\Biblioteca\application\views\scripts\index\index.phtml on line 1

    sabes que puede ser? gracias
    saludos

  27. saul on Agosto 27th, 2009 2:08 am

    interesante el tutorial, pero no me parace tam limpio el codigo , comparando con los framework que se usan para hacer aplicaiones java … unn

  28. Caro on Septiembre 8th, 2009 1:51 pm

    hola… estoy empezando con zend… estoy un poco confundida con la estructura q se hace porq por lo visto en el controlador se colocan los botones y las cajas texto aqui no estamos cumpliendo con el MVC.. alguien m pueden explicar como funciona esto…??? xq estoy intentando hacer un formulario pero estoy confundida por esto.. por fa el q pueda ayudarm c lo agradeceria.. :)

  29. Gilberto on Septiembre 8th, 2009 7:08 pm

    Muchisimas gracias por estos excelentes aportes. Hace poco me interese en aprender a trabajar con este framework y la verdad es el primer sitio que encuentro con información realmente util (en español). De nuevo muchas gracias por todo el tiempo que dedicas.

  30. Caro on Septiembre 16th, 2009 12:47 pm

    Buenos dias.. tengo una duda, no entiendo dond sabe el boton cual es su accion… se que en el controlador esta esto ‘/album/edit/id/’ y m imagino q es cuando el sabe cual funcion va a ejecutar…?? pero sigo sin entender porq en album no existen esas funciones ellas estan en el controlador.. si alguien m puede ayudar c lo agradeceria!!

  31. zsamer on Septiembre 16th, 2009 1:56 pm

    Hola Caro, te invito a que tomes el próximo curso de Zend, ahí aprenderás todo como enfrentar un proyecto con Zend Framework. El costo es bastante accesible.

    Si te interesa puedes registrarte en este link:
    Registro Curso Zend

  32. Caro on Septiembre 16th, 2009 2:19 pm

    Gracias pero pense q m podia ayudar… Gracias!!!

Deja tu comentario




XHTML: puedes usar estas etiquetas: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>