domingo, 27 de julio de 2008

Mi blog ahora en www.borisduin.com.ve

Sr@s: Desde hoy nuevamente retomo mi blog, pero desde mi pagina web personal. Por allá los espero para seguir hablando de symfony y algo más.

miércoles, 26 de diciembre de 2007

Trabajando con múltiples shemas de postgresql en Symfony.

El manejador de BdD postgres, tal véz el mejor motor de BdD libre que existe (que me disculpen los amante de MySQL ;-) ) tiene la posibilidad de trabajar con schemas, que es una manera muy interesante de organizar las distintas tablas de nuestra BdD. Para entender un poco lo que son los schemas en postgres acá les colocó un link a la página de Expresión Digital donde tienen una definición bastante sencilla de lo que son y como se implementan ( Es importante no confundir el concepto de schema de postgres con el concepto aplicado a los archivos de schema utilizado en Symfony).

Una debilidad que tiene Propel/Creole, el ORM utilizado en Symfony, es que no soporta trabajar con múltiples schemas de postgresql. Por defecto este asume que trabajará con el schema por defecto, llamado public. Què pasa si tenemos múltiples schemas en nuestra BdD en Postgresql, y queremos utilizar Symfony?, pues sencillamente con la instalación por defecto de Symfony esto no es viable.
Pero viable no quiere decir que sea imposible. Hace aproximadamente un año me tocó trabajar con una BdD en Postgres con varios schemas con Symfony, y al toparme con esta debilidad de Propel/Creole procedí a reescribir un par de clases de el core de dicho ORM para solventar dicho escollo. Después de 2 días de trabajo logré ajustar las siguiente clase de Creole:
.- PgSQLConnection: Ubicada en la carpeta vendor/creole/drivers/pgsql en las librerías de Symfony, se encarga de realizar la conexión a la BdD en base a un arreglo de parámetros de conexión. A esta clase le agregué una condición para que en caso de que se especifique el parámetro schema se ejecute la instrucción SET search_path TO en la BdD, indicando los schemas que se hayan especificado. Con ese simple cambio es posible especificar un dsn en el archivo database.yml como el que se presenta a continuación:

dev:
propel:
class: sfPropelPgDatabase
param:
dsn: pgsql://miusuario:miclave@miservidor/mibdd?schema='public','VENTAS'

De esta manera nuestra aplicación en Symfony trabajaría con las tablas tanto del schema public como VENTAS de la BdD indicada.

Otro punto importante es si nosotros escribimos manualmente el archivo schema.yml de Symfony o lo generamos a partir de nuestra BdD con el comando symfony propel-build-schema. En el caso de usar el comando propel-build-schema tenemos las misma restricción, y que por defecto generará el schema.yml exclusivamente del schema public de la BdD. Para poder generar el schema.yml con las tablas de varios schemas modifiqué la siguiente clase:

.- PgSQLDatabaseInfo: Ubicada en la carpeta vendor/creole/drivers/pgsql/metadata en las librerías de Symfony, es utilizada para realizar las consultas necesarias a la BdD para la generación del schema.yml. Realicé algunos ajustes al método initTables de dicha clase para recuperar la lista de tablas de varios schemas, en caso de que se hayan especificado. De esta manera se puede editar el archivo propel.ini de la siguiente manera para generar el shcema.yml con las tablas de los schemas public y VENTAS de la BdD:

propel.targetPackage = lib.model
propel.packageObjectModel = false
propel.project = miproyecto
propel.database = pgsql
propel.database.createUrl = pgsql://miservidor/
propel.database.url = pgsql://miusuario:miclave@miservidor/mibdd?schema='public','VENTAS'


Un problema que tiene este mecanismo es el de manejar tablas con el mismo nombre entre los schemas, así por ejemplo pueden tener una tabla llamada persona en el schema public y otra llamada persona en el schema VENTAS, a nivel de postgres esto es válido, pero en Symfony, esto nos traería inconvenientes. Es posible crear una aplicación en nuestro proyecto que trabaje solo con el schema public, y otra que trabaje solo con el schema VENTAS con este cambio que les indico, pero si tienen tablas con el mismo nombre es recomendable que utilizen la propiedad package y/o phpname en el schema.yml para indicar que las clases de dichos schemas se generen en directorios distintos y con nombres de clase diferentes.

A continuación les colocó un link al servicio mediafire (servicio muy bueno por cierto) donde podrán descargar las 2 clases modificadas que les comenté.

Una desventaja que tiene este cambio es que si se actualiza Symfony es necesario volver a reemplazar las clases en cuestión. Hace aproximadamente 10 meses coloqué un ticket en el trac de Propel/Creole solicitando la posibilidad de un cambio o mejora con el código en cuestión, pero hasta la fecha no he tenido una respuesta satisfactoria. Existen otras posibilidades de ajustar el código de Propel/Creole para que trabaje con Schemas de Postgres, pero hasta la fecha, personalmente considero que está es una de las más sencillas.