Integrando Propel con Zend Framework: Primera Parte

Por zsamer en Junio 2, 2008

En mi ultimo articulo Bootstrap Class había quedado comprometido de escribir un post sobre cómo integrar ZF con el ORM Propel, así que ha llegado el momento de cumplir lo prometido ;-) .

Introduciendo un poco el termino ORM, mapeo objeto-relacional (más conocido por su nombre en inglés, Object-Relational mapping, o sus siglas O/RM, ORM, y O/R mapping) es una técnica de programación para convertir datos entre el sistema de tipos utilizado en un lenguaje de programación orientado a objetos y el utilizado en una base de datos. En la práctica esto crea una base de datos orientada a objetos virtual, por sobre la base de datos relacional. Esto posibilita el uso de las características propias de la orientación a objetos (básicamente herencia y polimorfismo).

Abrir dos conexiones paralelas a una misma base de datos no es una buena idea ni mejores practicas, podría producir graves problemas de rendimiento en nuestra aplicación y sobre todo si nuestro proyecto va a tener un importante numero de visitas interactuando con nuestra aplicación al mismo tiempo. La idea es poder hacer uso tanto de Zend_Db_Table como de Propel dentro de nuestro proyecto, pero aquí podríamos plantearnos la siguiente pregunta ¿Cómo implementar ambos ORM dentro de nuestro proyecto sin tener que abrir dos conexiones paralelas? La solución la iremos viendo en el transcurso de este post.

Este post no pretende abarcar temas de instalación ni de manual de uso de Propel, solo veremos su integración con Zend Framework y un breve ejemplo de uso, así que se da por hecho que el lector tiene algún conocimiento de Propel, en caso contrario pueden visitar el sitio y leer el manual.

La integración solo es valida para la versión 1.3 o superior de Propel (Propel 1.3), ya que a partir de la versión 1.3 Propel utiliza PDO en vez de Creole como capa de abstracción a la base de datos, sin duda un gran cambio, lo mejor que pudo haber hecho Propel ;-) .

Para el lector que no tenga experiencia con Propel recomiendo leer el manual como mencioné más arriba y ademas leer el siguiente post Installing Propel object persistence layer for Web application (Cuidado: Creole ya no es necesario ya que utiliza PDO).

Manos a la obra, primero tenemos que descargar Propel 1.3 y luego su dependencia Phing, su instalación leer manuales respectivos.

Estructura de directorio de nuestro proyecto

Estructura de directorio

En la imagen de arriba notamos dos cosas nuevas, aparece un nuevo directorio en la raíz de nuestro proyecto "build" ahí contendrá todos los archivos de configuración relacionado al generador de propel, en su mayoría archivos xml. Entre los archivos tenemos build.properties, runtime-conf.xml y schema.xml, además de un directorio "sql" donde se guardaran los archivos schema.sql sentencias generadas create table y constraint.
También notamos un nuevo directorio dentro de library "propel", el cual contiene el runtime class (librerías de propel).

El generador de Propel (propel-gen) espera encontrar la definición de nuestro esquema de base de datos (schema.xml) y nuestro archivo de propiedades del build (build.properties) en el directorio build (quickstart\build). Este directorio también contendrá los SQL generados. Nuestras clases de modelo generadas se crearán (por el generador) en el directorio "quickstart\application\models" y los archivos de configuración generados (por el generador) se crearán en "C:\xampp\htdocs\quickstart\application\config".

Hasta ahora todo esta en orden, ahora tenemos que definir nuestros archivos del build.

Describiendo nuestra base de datos en XML

A fin de crear un modelo que represente exactamente nuestras tablas de la base de datos y sus relaciones, necesitaremos escribir un XML que represente nuestra base de datos.

Sin entrar en mayor detalle, a continuación muestra la definición de schema.xml.
quickstart\build\schema.xml

CODE:
  1. <?xml version="1.0" encoding="ISO-8859-1" standalone="no"?>
  2. <database name="quickstart" defaultIdMethod="native">
  3.  <table name="project" description="Project Table">
  4.   <column name="project_id" type="integer" primaryKey="true" autoIncrement="true" required="true" description="Project Id"/>
  5.   <column name="title" type="varchar" size="255" required="true" description="Project Title"/>
  6.   <column name="logo" type="varchar" size="255" required="false" description="Project Logo"/>
  7.   <column name="address" type="varchar" size="255" required="false" description="Project Address"/>
  8.   <column name="sale_office" type="varchar" size="255" required="false" description="Sale Office"/>
  9.   <column name="phone" type="varchar" size="255" required="false" description="Phone"/>
  10.   <column name="is_active" type="char" size="1" required="true" default="1" description="Is Active"/>
  11.  </table>
  12.  
  13.  <table name="project_images" description="Project Images">
  14.   <column name="image_id" type="integer" required="true" primaryKey="true" autoIncrement="true" description="Image Id"/>
  15.   <column name="project_id" type="integer" required="true" description="Foreign Key for Project"/>
  16.   <column name="name" type="varchar" size="128" required="true" description="Image Name"/>
  17.   <column name="description" type="LONGVARCHAR" required="true" default="" description="Image Name"/>
  18.   <foreign-key foreignTable="project">
  19.    <reference local="project_id" foreign="project_id"/>
  20.   </foreign-key>
  21.  </table>
  22. </database>

Propiedades del Build

A fin de construir nuestro proyecto, el generador de Propel necesita saber cierta información y esperará encontrarla en el archivo build.properties dentro de nuestro directorio "build", para mayor detalle.

Básicamente necesita lo siguiente:

  1. Nombre de nuestro proyecto
  2. Que RDBMS estamos usando (mysql, oracle, mssql, etc...)
  3. Cómo conectarnos a nuestra base de datos (asumiendo que propel crea las tablas en la base de datos por nosotros)

En nuestro ejemplo vamos a usar mysql, aunque podría ser cualquier otro RDBMS soportado por PDO.

quickstart\build\build.properties

CODE:
  1. # set some basic properties for the project and the database connection
  2. propel.project = quickstart
  3. propel.database = mysql
  4. propel.database.url = mysql:host=localhost;dbname=quickstart
  5. propel.database.user = mi_user
  6. propel.database.password = mi_password
  7. propel.mysql.tableType = InnoDB
  8.  
  9. propel.targetPackage = project
  10.  
  11. # directories
  12. propel.output.dir = C:\xampp\htdocs\quickstart
  13. propel.php.dir = ${propel.output.dir}/application/models
  14. propel.phpconf.dir = ${propel.output.dir}/application/config
  15. propel.sql.dir = ${propel.output.dir}/build/sql

Configurando nuestro Runtime XML

El runtime XML es usado en nuestra aplicación para configurar nuestras generadas clases/objetos de la capa de modelo y las clases de runtime de propel. Esta información no es necesaria para la generación de los SQL ni las clases de modelos, solo para términos de configuración ya que en el proceso de generación el archivo Runtime XML (runtime configuración) será transformado en un array por el generador y será guardado de un archivo PHP dentro del mencionado directorio "quickstart\application\config" y será nombrado a "nombredelproyecto-conf.php" en nuestro caso quickstart-conf.

Entonces creamos un nuevo archivo llamado runtime-conf.xml dentro del directorio "build" y copy paste el siguiente contenido:
quickstart\build\runtime-conf.xml

CODE:
  1. <?xml version="1.0" encoding="ISO-8859-1"?>
  2.  
  3. <config>
  4.  <!-- Uncomment this if you have PEAR Log installed
  5.  <log>
  6.   <type>file</type>
  7.   <name>/path/to/prople.log</name>
  8.   <ident>propel-bookstore</ident>
  9.   <level>7</level>
  10.  </log>
  11.  -->
  12.  <propel>
  13.   <datasources default="quickstart">
  14.    <datasource id="quickstart"> <!-- this ID must match <database name=""> in schema.xml -->
  15.     <adapter>mysql</adapter> <!-- sqlite, mysql, myssql, oracle, or pgsql -->
  16.     <connection>
  17.      <dsn>mysql:host=localhost;dbname=quickstart</dsn> <!-- the PDO connection DSN for database -->
  18.      <user>mi_user</user>
  19.      <password>mi_password</password>
  20.     </connection>
  21.    </datasource>
  22.   </datasources>
  23.  </propel>
  24. </config>

Construyendo Nuestro Proyecto

Podemos usar el script propel-gen para generar los SQL y PHP object model para nuestro proyecto.
En resumen podemos ejecutar el build llamando al script propel-gen con el path de nuestro proyecto directorio.

CODE:
  1. $> propel-gen /path/to/project_name

en nuestro caso:

CODE:
  1. $> propel-gen /path/to/quickstart

Lo anterior hara los siguientes procesos:

  1. crea los SQL DDL para crear nuestra tablas (tables, sequences, foreign keys, indexes, etc.)
  2. crea las clases PHP5 que proveen OO representación de nuestra base de datos (capa modelo)
  3. convierte el runtime configuración en un PHP array que contiene la configuración para los modelos

Una vez ejecutado el comando podemos ver el resultado como archivos generados a partir de las configuraciones y archivos XML vistos anteriormente.

Asumiendo que el proceso termino satisfactoriamente podemos tener los siguientes archivos/directorios generados contenidos dentro de nuestro proyecto.

Directorio Descripción
quickstart/application/models/project/*.php Los modelos generados PHP clases que serán usado para acceder a nuestra database y tratar con los datos.
quickstart/build/sql/schema.sql Los archivos SQL DDL para crear las tablas y objetos de nuestra base de datos (tables, sequences, etc.)
quickstart/application/config/quickstart-conf.php El convertido PHP array para mantener nuestro runtime configuración en la aplicación.

Usando los Generados archivos SQL y OM

Primer que nada tenemos que crear nuestra base de datos:
E.g. for MySQL:

CODE:
  1. $> mysqladmin create nuestra_base_de_datos

(en nuestro caso debería estar creada si no es asi entonces habría que crearla).

Luego ejecutamos el comando para crear nuestas tablas en la base de datos a partir de loas archivos SQL generados a partir del schema.xml:

CODE:
  1. $> propel-gen /path/to/project_name insert-sql

en nuestro caso:

CODE:
  1. $> propel-gen /path/to/quickstart insert-sql

Hasta aquí tenemos bastante avanzado nuestro articulo, pero aun falta la parte más importante y es la integración con Zend Framework, dejaremos hasta aquí el articulo por hoy ya que se ha alargado mas de la cuenta y continuaremos con la segunda parte en el próximo post como una segunda entrega de articulo Integrando Propel con Zend Framework.

No se lo pierdan, nos vemos en la segunda parte de este articulo que tratará específicamente la integracion con Zend Framework para ello será necesario extender la clase Zend_Db_Adapter_Pdo_Mysql (utilizando mysql) y agregaremos un par de métodos y funcionalidades en la clase Core/Bootstrap de nuestro sistema cubierto en el articulos anterior Bootstrap Class, supongo que ya se lo están imaginando...

:-)

Comentarios

13 Responses to “Integrando Propel con Zend Framework: Primera Parte”

  1. _imc_ on Junio 3rd, 2008 11:59 am

    Hola

    Una duda… porque no usas UTF-8 en los XML???

    Una recomendación sobre la instalación de propel y phing, usar sus canales PEAR para facilitarlo :).

    Comentar que tanto propel-gen como phing deben encontrarse en el PATH, y ejecutar el comando en el directorio build o apuntando al directorio build

    Creo que la parte de Propel da para más de un artículo, sobre todo explicar la estructura de clases que crea y la funcionalidad de las mismas…

    Te paso el enlace de Symfony donde se explica un poco la estructura ;) no se si me he adenlantado al siguiente artículo.

    Un saludo

    Isidro

  2. zsamer on Junio 3rd, 2008 12:58 pm

    gracias Isidro, la idea es ver la integración con ZF, no un articulo detallado y acabado sobre uso de propel, incluso explique más de propel de lo que tenía pensado para el articulo.

    Si con el XML tienes razón es mejor usar UTF-8.

    Gracias por el link esta muy bueno, abarca bastante el tema de uso de las clases de modelo.

    saludos.

  3. JuanCho on Junio 5th, 2008 12:54 pm

    Te felicito por la información que brindas. Recien estoy comenzando y ha sido de mucha ayuda. Habria alguna posibilidad de que en las cajas te texto que introduces el codigo, no tengan los números de línea, ya que cada vez que lo pego debo sacarlos. Saludos! y gracias por tu trabajo!.

  4. zsamer on Junio 5th, 2008 3:24 pm

    JuanCho, tienes que hacer clic en PLAIN TEXT y te muestra el código sin los números.

  5. Francisco on Junio 5th, 2008 10:52 pm

    Tengo una duda…
    Si en el bootstrap usas el Autoload… Por qué volves a incluir las clases de la libreria Zend en cada controlador?

    Un abrazo

  6. zsamer on Junio 5th, 2008 10:56 pm

    por costumbre, pero se pueden no poner.

  7. Integrando Propel con Zend Framework: Segunda Parte | Zend Framework: Estado del Arte on Junio 7th, 2008 1:19 am

    [...] de vuelta con el articulo Integrando Propel con Zend Framework, en la Primera Parte vimos una introducción de Propel, estructuras de directorios de nuestro proyecto, finalmente como [...]

  8. Implementar ORM en Zend Framework Db Table | Zend Framework: Estado del Arte on Agosto 29th, 2008 3:31 pm

    [...] Hibernate como ORM, a mi gusto uno de los mejores ORM en Java y también he trabajado con Propel en PHP5, y he tomado funcionalidades de ambos para incorporarlas en este [...]

  9. Jeryyms on Octubre 25th, 2008 5:18 pm

    Nice site you have

  10. Gabriel Arias on Diciembre 16th, 2008 11:52 am

    Hola, te hago un par de consulta de principiante.
    Primero, Zend_Db_Table es un ORM?
    Segundo, en el caso que así fuera, cual es la ventaja de propel respecto de Zend_Db_Table?
    Estuve viendo algo de propel y parece ser no muy complicado su uso, pero no se nada todavía de Zend_Db_Table.
    Te aclaro que tus post son muy claros y se aprende mucho con ellos y fue lo que me animó a enfrentar el zend framework. Gracias por el material entregado.

  11. zsamer on Diciembre 16th, 2008 12:23 pm

    Hola Gabriel, Zend Framework no tiene una implementacion de ORM propiamentetal, si cubre algunos aspectos pero no todos. Implementa un conocido patrón de diseño llamado Table Data Gateway y “Row Data Gateway”.

    Sin embargo desarrollé un componente llamado ORM con Zend Framework Db Table, que tiene como finalidad dar mayor funcionalidad de ORM a Zend_Db_Table, implementado con Zend_Db_Table Relationships, sin alterar ni tocar ninguna de sus funcionalidades ya existentes.

  12. Sesso on Enero 24th, 2009 1:38 am

    Great site.

  13. fussball on Marzo 2nd, 2009 11:21 am

    Gute Arbeit hier! Gute Inhalte.

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>