Por favor, haz un clic sobre los anuncios cuando pases por mi blog, ya? =)

Zend Framework 5: El Modelo de datos

26 comentarios
Esta es la quinta parte de mi tutorial de Zend. La parte anterior la puedes hallar aquí.

Hasta ahora hemos mostrado cómo crear un controlador y sus respectivas acciones, que no son nada más que crear una clase en PHP y agregarle funciones. Pero que esto debe ser hecho usando la línea de comandos (zf.bat ó zf.sh) para que también se agreguen los datos al archivo xml de configuración del proyecto.

Ahora lidiaremos con la parte del Modelo, es decir, con el acceso a bases de datos. 
Para los siguientes artículos de este tutorial desarrollaremos un pequeño sistema para guardar datos de álbumes de música, artistas y temas. Usaremos una base de datos Mysql. Asumo que tú, esmerado estudiante, posees conocimientos de SQL  y sabes cómo crear una base de datos en MySql, crear usuarios y darles privilegios.

Recomiendo usar Mysql GUI Tools. Es una heramienta que permite administrar bases de datos MySql. Fue creada por MySql, tiene una bonita interfaz gráfica y es gratis.  Descárgala desde aquí.




Creando la base de datos

Este es el script de la base de datos que procederemos a crear:

-- MySQL Administrator dump 1.4
--
-- ------------------------------------------------------
-- Server version    5.0.45-community-nt


/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;

/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;


--
-- Create schema albums
--

CREATE DATABASE IF NOT EXISTS albums;
USE albums;

--
-- Definition of table `album`
--

DROP TABLE IF EXISTS `album`;
CREATE TABLE `album` (
  `id` int(11) NOT NULL auto_increment,
  `artista_id` int(11) default NULL,
  `nombre` varchar(50) default NULL,
  `fecha` date default NULL,
  `descripcion` varchar(100) default NULL,
  PRIMARY KEY  (`id`),
  KEY `fk_relationship_1` (`artista_id`),
  CONSTRAINT `fk_relationship_1` FOREIGN KEY (`artista_id`) REFERENCES `artista` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `album`
--

/*!40000 ALTER TABLE `album` DISABLE KEYS */;
INSERT INTO `album` (`id`,`artista_id`,`nombre`,`fecha`,`descripcion`) VALUES 
 (1,1,'nos sobran los motivos','2000-09-10','grabacion en vivo'),
 (2,1,'de juez y parte','1995-09-10','album'),
 (3,1,'estaboca es mia','1993-09-10','album muy bueno');
/*!40000 ALTER TABLE `album` ENABLE KEYS */;


--
-- Definition of table `artista`
--

DROP TABLE IF EXISTS `artista`;
CREATE TABLE `artista` (
  `id` int(11) NOT NULL auto_increment,
  `nombre` varchar(50) NOT NULL,
  `descripcion` varchar(100) default NULL,
  `email` varchar(100) default NULL,
  `fecha_ingreso` datetime default NULL,
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `artista`
--

/*!40000 ALTER TABLE `artista` DISABLE KEYS */;
INSERT INTO `artista` (`id`,`nombre`,`descripcion`,`email`,`fecha_ingreso`) VALUES 
 (1,'joaquin sabina','trobador español','joaquin@sabina.es','2010-10-22 00:00:00'),
 (2,'bruce dickinson','rockero ingles','bruce@hell.net','2010-10-22 00:00:00'),
 (3,'yann tiernsen','compositor frances','yann@france.net','2009-01-01 00:00:00');
/*!40000 ALTER TABLE `artista` ENABLE KEYS */;


--
-- Definition of table `temas`
--

DROP TABLE IF EXISTS `temas`;
CREATE TABLE `temas` (
  `id` int(11) NOT NULL auto_increment,
  `album_id` int(11) default NULL,
  `titulo` varchar(50) NOT NULL,
  `duracion` time default NULL,
  PRIMARY KEY  (`id`),
  KEY `fk_relationship_2` (`album_id`),
  CONSTRAINT `fk_relationship_2` FOREIGN KEY (`album_id`) REFERENCES `album` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;

--
-- Dumping data for table `temas`
--

/*!40000 ALTER TABLE `temas` DISABLE KEYS */;
INSERT INTO `temas` (`id`,`album_id`,`titulo`,`duracion`) VALUES 
 (1,3,'esta noche contigo','00:05:00'),
 (2,3,'por el boulevard de los sueños rotos','00:07:00'),
 (3,3,'más de cien mentiras','00:08:00'),
 (4,3,'mujeres fatal','00:04:00'),
 (5,3,'besos con sal','00:03:30');
/*!40000 ALTER TABLE `temas` ENABLE KEYS */;




/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;


Ahora, crearemos un usuario MySQL que tenga privilegios de insert, update, delete y select sobre la base de datos albums (si no sabes cómo hacer esto, puedes usar  al usuario root si quieres, aunque no es recomendable hacer eso en un ambiente de desarrollo serio)

Crearemos al usuario albumusuario, clave: 123
Bien, ya estamos listos para empezar a trabajar con la base de datos.


Conectando la base de datos con el proyecto en ZF

Primero, abramos al archivo /application/configs/application.ini y agreguemos lo siguiente (las nuevas líneas están destacadas):

[production]
phpSettings.display_startup_errors = 0
phpSettings.display_errors = 0
includePaths.library = APPLICATION_PATH "/../library"
bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
bootstrap.class = "Bootstrap"
appnamespace = "Application"
resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
resources.frontController.params.displayExceptions = 0

resources.db.adapter = PDO_MYSQL
resources.db.params.host = localhost
resources.db.params.username = albumusuario
resources.db.params.password = 123
resources.db.params.dbname = albums


[staging : production]

[testing : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1

[development : production]
phpSettings.display_startup_errors = 1
phpSettings.display_errors = 1
resources.frontController.params.displayExceptions = 1


Nota: para que esto funcione, php debe tener habilitado el adaptador  PDO_MYSQL. Debes asegurarte de que sea así. En Xampp viene habilitado por defecto, pero puede que en tu instalación no sea así.


Para habilitarlo, debes abrir php.ini y asegurarte de que 
extension=pdo_mysql
esté descomentado, y reiniciar apache.

Para qué hacemos esto en el archivo applicacion.ini? Pues porque al iniciarse ZF, se conectará a la base de datos  usando los parámetros de resources.db. ZF creará por sí mismo la cadena de conección, dependiendo del adaptador que estemos usando. Una vez colocadas estas líneas, podemos empezar a hacer consultas a la base de datos sin preocuparnos.

Creando las clases del Modelo

Ahora crearemos las clases PHP  que representarán a las tablas de la base de datos. Esto es muy sencillo.

Tipeamos Alt+Z para ejecutar un comando de Zend desde Netbeans, escribimos 'tabl' en el filtro y seleccionamos el comando
create db-table

y en Parámeteros escribimos: album album (nombre_clase nombre_tabla_referenciada)


Observamos que se ha creado una nueva clase en
/applications/models/DbTable/Album.php :

class Application_Model_DbTable_Album extends Zend_Db_Table_Abstract
{

    protected $_name = 'album';
}

Esta clase representa a la tabla album de la base de datos, como lo indica la variable protected $_name.

Hagamos los mismo con las otras dos tablas:
Alt+z y seleccionamos el comando
create db-table

y en Parámeteros escribimos: artista artista (nombre_clase nombre_tabla_referenciada)

Alt+z y seleccionamos el comando
create db-table

y en Parámeteros escribimos: temas temas(nombre_clase nombre_tabla_referenciada)

Ahora deberíamos tener tres clases en la carpeta /applications/models/DbTable :
Album.php
Artista.php
Tema.php

Pero ¿Cómo las usamos? Ahora lo veremos


Usando las clases del Modelo

Ahora vamos a agregar algo de código en las clases del Modelo de datos.

 Abre /applications/models/DbTable/Album.php  y reemplaza su contenido con

class Application_Model_DbTable_Album extends Zend_Db_Table_Abstract {

    //nombre de la tabla de la db a la que hace referencia
    protected $_name = 'album';

    /**
     * devuelve un arreglo con los datos del album con id=$id
     * @param  $id id del album
     * @return  arreblo asociativo
     */
    public function get($id)
    {
        $id = (int) $id;
        //$this->fetchRow devuelve fila donde id = $id
        $row = $this->fetchRow('id = ' . $id);
        if (!$row)
        {
            throw new Exception("Could not find row $id");
        }
        //formateo fecha a dia-mes-año para que se vea mejor
        $fecha = $row->fecha;
        $fecha = date("d-m-Y", strtotime($fecha));
//        die($fecha);
        $row->fecha = $fecha;
        return $row->toArray();
    }

    /**
     *  agrega un nuevo album a la base de datos
     * @param  $artista_id
     * @param  $nombre
     * @param  $fecha fehca de registro de este album en la base de datos
     * @param  $descripcion
     */
    public function agregar($artista_id, $nombre, $fecha, $descripcion)
    {
        $data = array('artista_id' => $artista_id, 'nombre' => $nombre,
            'fecha' => $fecha, 'descripcion' => $descripcion);
        //$this->insert inserta nuevo album
        $this->insert($data);
    }

    /**
     * modifica los datos del album id= $id
     * @param  $id
     * @param  $artista_id
     * @param  $nombre
     * @param  $descripcion
     */
    public function cambiar($id, $artista_id, $nombre, $fecha, $descripcion)
    {
        $data = array('artista_id' => $artista_id, 'nombre' => $nombre,
            'fecha' => $fecha, 'descripcion' => $descripcion);
        //$this->update cambia datos de album con id= $id
        $this->update($data, 'id = ' . (int) $id);
    }

    /**
     * borra el album con id= $id
     * @param  $id
     */
    public function borrar($id)
    {
        //$this->delete borrar album donde id=$id
        $this->delete('id =' . (int) $id);
    }

    public function listar()
    {
        //devuelve todos los registros de la tabla
        return $this->fetchAll();
    }
}

Examina el código con cuidado. Le he agregado a la clase los métidos para agregar, modificar, listar y eliminar registros. Como puedes ver, no se ocupan instrucciones SQL en ninguna parte.

En forma resumida, para manipular una tabla usamos las siguientes funciones:

$row = $this->fetchRow('id = ' . $id);
devuelve un objeto con los datos del registro de id = $id

 $this->insert($data);
inserta un nuevo registro en la tabla. $data es un array asociativo con el formato array( 'nombre_campo'=>'valor', 'nombre_campo2'=>'valor2', ...);

$this->update($data, 'id = ' . (int) $id);
actualiza el registro con el id = $id. $data es un aray asociativo, al igual que al llamar a $this->insert();

$this->delete('id =' . (int) $id);
borra el registro cuya id = $id.

return $this->fetchAll();
devuelve todos los registros de la base de datos. Puede recibir un parámetro para indicar filtro, orden o paginación.


El código para la clase /applications/models/DbTable/Artista.php sería:

class Application_Model_DbTable_Artista extends Zend_Db_Table_Abstract {

    protected $_name = 'artista';

    /**
     * devuelve un arreglo con los datos del artista con id=$id
     * @param  $id id del artista
     * @return  arreglo asociativo
     */
    public function get($id)
    {
        $id = (int) $id;
        //$this->fetchRow devuelve fila donde id = $id
        $row = $this->fetchRow('id = ' . $id);
        if (!$row)
        {
            throw new Exception("Could not find row $id");
        }
        $fecha = $row->fecha_ingreso;
        $fecha = date("d-m-Y", strtotime($fecha));
//        die($fecha);
        $row->fecha_ingreso = $fecha;
        return $row->toArray();
    }

    /**
     *  agrega un nuevo artista a la base de datos
     */
    public function agregar($nombre,  $descripcion, $email, $fecha_ingreso)
    {
        $data = array('nombre' => $nombre,
            'descripcion' => $descripcion, 'email' => $email,
             'fecha_ingreso'=>$fecha_ingreso );
        //$this->insert inserta nuevo artista
        $this->insert($data);
    }

    /**
     * modifica los datos del artista id= $id
     */
    public function cambiar($id,$nombre,  $descripcion, $email, $fecha_ingreso)
    {
         $data = array('nombre' => $nombre,
            'descripcion' => $descripcion, 'email' => $email,
             'fecha_ingreso'=>$fecha_ingreso );
        //$this->update cambia datos de artista con id= $id
        $this->update($data, 'id = ' . (int) $id);
    }

    /**
     * borra el artista con id= $id
     * @param  $id
     */
    public function borrar($id)
    {
        //$this->delete borrar artista donde id=$id
        $this->delete('id =' . (int) $id);
    }
     public function listar()
    {
         //devuelve todos los registros de la tabla
         return $this->fetchAll();
    }

}

Y el código para El código para la clase /applications/models/DbTable/Temas.php sería:

class Application_Model_DbTable_Temas extends Zend_Db_Table_Abstract {

    protected $_name = 'temas';

    /**
     * devuelve un arreglo con los datos del tema con id=$id
     * @param  $id id del tema
     * @return  arreglo asociativo
     */
    public function get($id)
    {
        $id = (int) $id;
        //$this->fetchRow devuelve fila donde id = $id
        $row = $this->fetchRow('id = ' . $id);
        if (!$row)
        {
            throw new Exception("Could not find row $id");
        }
        return $row->toArray();
    }

    /**
     *  agrega un nuevo tema a la base de datos
     */
    public function agregar($album_id, $titulo, $duracion)
    {
        $data = array('album_id' => $album_id,
            'titulo' => $titulo, 'duracion' => $duracion);
        //$this->insert inserta nuevo tema
        $this->insert($data);
    }

    /**
     * modifica los datos del tema id= $id
     */
    public function cambiar($id, $album_id, $titulo, $duracion)
    {
        $data = array('album_id' => $album_id,
            'titulo' => $titulo, 'duracion' => $duracion);
        //$this->update cambia datos de tema con id= $id
        $this->update($data, 'id = ' . (int) $id);
    }

    /**
     * borra el tema con id= $id
     * @param  $id
     */
    public function borrar($id)
    {
        //$this->delete borrar tema donde id=$id
        $this->delete('id =' . (int) $id);
    }

    public function listar()
    {
        //devuelve todos los registros de la tabla
        return $this->fetchAll();
    }

}


Bien, nuestras clases del Modelo están listas para usarse.
Ahora, el soçiguiente paso es trabajar con las acciones y las vistas, y es lo que haremos en el siguiente artículo.

26 comentarios :

Anónimo dijo...

Excelente tutorial ! estoy ansioso por ver el siguiente, Saludos!

Damian dijo...

Noooooooo!! quiero el proximo capitulo ahora!!. Dale loco, es lo mejor que encontre hasta ahora.

Saludos!

Travianero dijo...

Leccion aprendida, muy bueno esto. Solo tengo tengo una duda. Soy muy nuevo en esto, pero me da la sensacion que para album, artista y temas se esta redundando en el codigo para agregar, modificar (los metodos), amigo corrigeme o explicame si es asi. A seguir con el sgte. capitulo!!!

Angelorum dijo...

Correcto, Travianero, se produce una redundancia redudante que redunda en la redundancia XD


Pero prefiería hacerlo así para simplificar la explicación.
Por ejemplo, en los sitemas que he hecho llamo a una misma función para insertar o actualizar datos, y según la acción desde donde se llame (por ej, addAction() ó updateAction(), yo llamo a mi función con un valor distinto.

Pero cmo esto prentedía ser un tutorial básico, preferí no complicar las cosas ;)

Travianero dijo...

entendido y duda despejada :D. Gracias x la pronta respuesta ^^. Mola mucho este tutorial ;)

Anónimo dijo...

hola ángel opte por instalar el
mysql gui tools ya que como decías creo que me resultaría mas fácil de aprender que en el del xammp sera que podrías postear algún guía rápida de como configurar el mysql gui para trabajar con este ide porque porque la verdad no tengo conocimiento todavía si se puede en español mejor.

SaLUDOS

Anónimo dijo...

Otra consulta angel de la parte de pghp.ini para asegurarme q esta habilitado me fije en el ini pero no existe el .so

;extension=php_mssql.dll
;extension=php_mysql_mysqlnd.dll
extension=php_mysql_libmysql.dll
;extension=php_mysqli_mysqlnd.dll
extension=php_mysqli_libmysql.dll
;extension=php_oci8.dll
extension=php_pdo.dll
;extension=php_pdo_dblib.dll
;extension=php_pdo_firebird_firebird.dll
;extension=php_pdo_firebird_interbase.dll
;extension=php_pdo_mssql.dll
;extension=php_pdo_mysql_mysqlnd.dll
extension=php_pdo_mysql_libmysql.dll
extension=php_pdo_odbc.dll
;extension=php_pdo_pgsql.dll
extension=php_pdo_sqlite.dll
;extension=php_pdo_sqlite_external.dll
;extension=php_pgsql.dll
;extension=php_pspell.dll
;extension=php_shmop.dll
;extension=php_snmp.dll
extension=php_soap.dll
extension=php_sockets.dll
extension=php_sqlite.dll
extension=php_sqlite3.dll
;extension=php_sybase_ct.dll
;extension=php_tidy.dll
extension=php_xmlrpc.dll
extension=php_zip.dll

Angelorum dijo...

ese es un error mío de explicación:

el .so al parecer es sólo para sistemas en linux.

Debes habilitar la extensión pdo_mysql para tu sistema. en tu caso, debería ser
extension=php_pdo_mysql_libmysql.dll
la que ya tienes descomentada.

Saludos

Anónimo dijo...

Ok gracias por la aclaración Angel ahora me gustaria como ya te dije algun tuto como el de estos de mysql
me gustaria si se puede

Saludos

Anónimo dijo...

Nuevamente yo Angel por favor si me pudieras ayudar como crear los script para la bd de tu ejemplo o si me pudieras para lo como ya te habría dicho algun link bueno o tuto para aprender por lo menos para tener buen conocimiento de programación web con estos lenguajes.

Siendo que tengo una chance de trabajar en esto como para comenzar y no me gustaría perder bastantes documentales tengo pero la mayoría como sabes no se explican bien asi como vos explicas



Sinceramente te agradecería siendo que también tengo que hacer un proyecto de pagina web y me estoy bien ya en apuros . Ah y también que hosting me recomendaría uno bueno

Anónimo dijo...

Buenas amigos, muy buena guia para los que arrancamos con Zend, gracias!.
Ahora una pequeña consulta, como se puede relacionar tablas y hacer querys tipo joins a varias tablas en Zend Framework.

Angelorum dijo...

Para hacer joins y otras yerbas, mira la parte 11 de mi tutorial, la sección 3 :P :
http://angelorum.blogspot.com/2010/11/zend-framework-11-sesiones-registro.html

Angelorum dijo...

para crear los scripst puedes hacer usando una herramienta gráfica como mysql guitools con el MySql Administrator, o bien por línea de comandos. Creo que andas algo flojo en saber cómo manejar un gestor de base de datos.

Zend framework es una libreria para usar PHP de una forma mas eficiente, pero para usarlo bien necesitas saber bien trabajar con PHP.

Esto tal ves te serviria para aprender a manejar mysql http://www.desarrolloweb.com/manuales/34/

Y esto para php: http://www.desarrolloweb.com/manuales/58/

Anónimo dijo...

y si la verdad que si ángel bastante diría sii conozco sta web
Otra consulta ya se como crear usuario en mysql administrador ahora la opción de insertar todo esos datos para el script lo que me confunde? de tus ej ? lo que no se como hacer si me podrías ayudar


Saludos

Anónimo dijo...

Hola angel si pods ayudarme de nuevo con lo de tu ejemplo con que nombre le pongo el script de la bd para la conexion? Te agradeceria si pudieras darme ayuda mas presica en cuanto a mysql o alguna web de donde vos aprendiste porfa..

Mira te copio de lo que decia el sitio:

Aunque existen muchas formas de crear bases de datos MySQL, una de las mejores formas es utilizando scripts, es decir, un texto con instrucciones para MySQL. Normalmente si queremos guardar estos scripts, los deberíamos de guardar con la extensión sql.

Ahora, vamos a crear una base de datos de prueba, a la que llamaremos biblioteca, y en ella crearemos una tabla y varios campos para que esta sea utilizable.

Anónimo dijo...

perdon quise decir las llaves

Anónimo dijo...

Hola Angelorum, muy buena tu pagina.
Una consulta te quisiera hacer... como estoy empezando con el zend framework estoy viendo varios foros al respecto, lo que estoy viendo que algunos desarrolladores utilizan Doctrine en detrimento de Zend_Db... cual es el motivo? Zend_Db no ofrece algunas ventajas que si las ofrece Doctrine.
Me puedes orientar al respecto?
Gracias

Angelorum dijo...

Ni idea, jamas habia oido de Doctrine.

Voy a ver de qué se trata XD

Mt2h dijo...

Super claro ;)
Gracias =)

Anónimo dijo...

Buenas angel me gustaria saber que nombre le pongo al scrip de la BASE DE DATOS Y en que lugar se guarda este script..

POrfavor si me orientas..

Angelorum dijo...

Hola. Debes guardar el script de la base de datos con extension .sql, y después usarlo para crear la base de datos en mysql.

Saludos

Oscar Florez dijo...

Hola, ante todo gracias por el tutorial, me ha ayudado mucho, he tenido un pequeño problema con la configuracion de la base de datos hago los mismos paso que dijiste mas arriba y me sale este error
Message: The mysql driver is not currently installed

La verdad tengo descomentada la linea que corresponde al driver de mysql en el php.ini y reinicio apache normalmente pero me sigue dando error, lo mismo me sucede con oracle. Podrias orientarme' Ante todo muchas gracias

Anónimo dijo...

Gracias por el tutorial, me aclaro muchas dudas

Anónimo dijo...

Simplemente excelente!

Jonathan Camargo dijo...

primero que todo GRACIAS POR EL TUTORIAL.
quisiera saber si las tablas que son formadas por relaciones n a m se tienen que meter en mis clases php.
Muchas graciaaaaasssss

Patricio Andres Gonzalez Osses dijo...

Primero Gracias por el tutorial e aprendido bastante con el, pero me surgen unas dudas es posible utilizar las sentencias ORDER BY o LIMIT, si es posible como se utilizan.

Atentamente Gracias.