Artículos de marzo 2009

Generar PDF dinámicos

En la empresa en la que trabajo tenemos un catálogo de más de 1000 productos vendibles que tienen su descripción, fotos, especificaciones, etc. Toda esta información está almacenada en bases de datos, hojas de cálculo y demás soportes y hasta ahora el proceso de generación de las fichas comerciales de los productos era realizada a mano por una persona del departamento de diseño.

Pues bien, ya que la información está disponible desde varias fuentes a las que se puede acceder por medio de un script PHP, me han encargado la tarea de automatizar el proceso.

Librerías de generación de PDFs en PHP

En la búsqueda de librerías de generación de PDFs dinámicos he encontrado las siguientes opciones:

PDFLib

Se trata de una librería de pago con bindeos para muchos lenguajes de programación que permite componer los PDFs objeto a objeto. Está perfectamente integrada en PHP y ofrece dos versiones, dependiendo de si trabajamos con PHP4 o PHP5 orientado a objetos.

También tiene una versión PDFLib Lite que es gratuita y tiene casi todo lo necesario.

FPDF

Esta es una versión libre, más limitada y lenta que la anterior. En este caso no podremos utilizar las funciones incorporadas en PHP sino que usaremos métodos de una clase desarrollada “a pelo” para generar nuestros PDFs. Sin embargo, la filosofía detrás de esta librería es la misma que en PDFLib.

R&OS CPDF

Igual que la anterior, pero parece aun más limitada.

DOMPDF

Esta librería es un wrapper que utilizará como backend de generación PDFLib, R&OS CPDF o GD para contruir los PDFs. Es un misterio para mi cómo hacen para generar PDFs con GD, pero sospecho que generan una “foto” de cada página y se lo enchufan a un fichero con formato PDF de alguna manera.

Conclusión

Si no me quedara más remedio que construir a mano los PDFs en PHP seguramente usaría DOMPDF o PDFLib Lite. Sin embargo, creo que la mejor opción es la que voy a describir a continuación:

SVG: La alternativa que gusta a pequeños y mayores

SVG: Scalable Vector Graphics. Se trata de un lenguage de marcado creado por la W3C para contener dibujos vectoriales. Se supone que será uno de los standards para ficheros de dibujo vectorial más usados en los próximos años.

La estructura de un SVG es la de un XML. Cada etiqueta define propiedades del documento y objetos como bloques de texto, párrafos, imágenes, formas, etc.

Este formato gustará a todos y todas porque las personas responsables del diseño podrán utilizar magnificas aplicaciones de diseño vectorial como Inkscape en las que podrán dar rienda suelta a su creatividad y nosotros, los encargados de rellenar de contenido sus diseños, podremos utilizar sencillas funciones de reemplazo de texto para tratar el contenido XML del fichero SVG y “producir” un documento final. El programador más habilidoso podrá incluso utilizar sus funciones preferidas de modificación del árbol DOM de XML para trabajar con el documento e incluso crear objetos on-the-fly.

Una vez creado un SVG final, podemos usar una infinidad de aplicaciones para convertir el SVG en PDF (o en el formato que nos dé literalmente la gana). El propio Inkscape permite ser ejecutado en línea de comandos y de la siguiente manera conseguiremos un radiante PDF:

$ inkscape -A documento.pdf documento.svg

Para más info hacer un ‘man inkscape’. El programa permite definir parámetros de exportación de las imágenes del documento para definir sus DPIs, por ejemplo.

Retweet
Publicado el : 11 marzo 2009
Categorías: General
Etiquetas: , , , , , , ,
Comentarios: Ningún comentario

Problemas (casi)resueltos de Propel (Symfony) y Oracle

Acaban de dejarme un comentario al post: Propel 1.3 ya puede inspeccionar Oracle digno de ser respondido como dios manda. Os pongo el extracto de una serie de preguntas que plantea mppfiles:

1) Los nombres de tablas deben estar sí o sí en mayúsculas
2) Los nombres de los campos DEBEN definirse con minúsculas y/o sin tildar el “preserve case” en ApEx (o sin encerrar los nombres de los campos entre comillas)
3) En varias ocasiones me han salido errores extraños del tipo: “duplicate table found: propel” y otros mas extraños aun, tuve que borrar los generated-schema*.yml y volver a construir el esquema y el modelo para que camine.
4) Al generar los forms, los nombres de los widgets se ponen en minusculas, lo que genera problemas al guardarlos despues (porque definimos previamente que sean mayusculas)
5) Ahora estoy peleando con los campos de tipo fecha. Al parecer el Oracle que tengo instalado (XE bajo Windows) maneja las fechas en formato “d/m/Y” o dd/MM/YYYY (o equivalentes), en definitiva: fechas en español) y me salen errores del tipo “Unable to execute INSERT statement. [wrapped: SQLSTATE[HY000]: General error: 1861 OCIStmtExecute: ORA-01861: el literal no coincide con la cadena de formato”, pensaba que tenía que ver con el formato ISO de los validators (Y-m-d, o YYYY/MM/DD o como sea), y aunque cambié el valor de
$this->validatorSchema['FECHA_NAC']->setOption(’date_output’,’d/m/Y’)
al hacer $form->getValues() lo muestra con ese formato, pero Propel insiste en guardar el valor en la base con el formato ISO, lo cual me parece mas que bien.

Paso a contestar la mayoría de puntos ya que creo que los he resuelto en mayor o menor medida:

1. Nombres de tablas

En Oracle los nombres de tablas se normalizan siempre a un formato en mayúsculas. Me parece una opción igual de válida como cualquier otra, aunque a la hora de programar no suele ser recomendable reproducir esto ya que normalmente se reservan las palabras en mayúsculas para nombres de constantes o, en el caso de PHP, superarrays como _REQUEST, _SERVER, etc.

La manera tradicional de nombrar tablas en bases de datos como MySQL, PostreSQL y demás suele ser la de palabras en minúsculas separadas por guión bajo. Una tabla llamada “user_personal_data” debería mapearse a una clase del estilo UserPersonalData en Propel. El problema es que Propel utiliza un método de la clase PhpNameGenerator llamado phpnameMethod que no convierte el nombre a minúsuclas antes de capitalizar la primera letra de cada parte del nombre.

En la versión de Propel en la que pude contribuir recientemente he corregido este comportamiento y he creado un nuevo método de nombrado que abarca más a la hora de normalizar nombres extraños de tablas o columnas. De este modo, no solo obtendrás un esquema de base de datos con un formato tipo UserPersonalData, sino que además podrás tolerar nombres de tabla con carácteres extraños.

Sin embargo, me preocupa el tema de las tildes que no había considerado aun. Creo que tendré que hacer una modificación para que los carácteres “á é í ó ú” se traduzcan en “a e i o u” y no desaparezcan sin más.

Si has descargado Symfony a través de su repositorio de Subversion, debes realizar un “svn up” en la carpeta “symfony/lib/plugins/sfPropelPlugin/lib/vendor/propel-generator” ya que de lo contrario no tendrás la última versión del generador ya que Symfony “bloquea” las librerías de Propel en una versión anterior a mi contribución.

2. Nombres de campos

Esto está resuelto del mismo modo que con el nombre de las tablas del que hablo en el punto anterior.

Yo trabajo contra una base de datos de un ERP Baan IVc4 que utiliza como nombre de columnas cosas como “T$ORNO” o “S$NAMA$RE“. Con una versión de Propel actualizada no tendrás ningún problema en generar el schema.yml en semejante escenario. Estos nombres se traducirían como “TOrno” y “SNamaRe“.

Sin embargo, el modelo generado a partir del schema.yml anterior no funcionará a no ser que lo edites manualmente ya que en las clases generadas creará incorrectamente el código fuente de las constantes de clase y algún que otro método. En los Peer generará, por ejemplo:

const T$ORNO = "T$ORNO";

Y esto falla.

Yo lo he resuelto realizando modificaciones a otras clases de Propel. Estas modificaciones no las he subido al repositorio de Propel porque creo que exigen un pequeño debate y aprobación por parte del grupo de desarrolladores de Propel ya que son bastante intrusivas y pueden afectar a modelos generados a partir de otros motores de bases de datos.

Básicamente, lo que he hecho es decirle al generador de modelos que emplee para todo el “phpName” y no el “name” de las columnas. Esto soluciona el problema por completo. Puedo enviarle un diff de los cambios que he hecho en estas clases a quien me lo pida para que pueda aplicar los cambios en su instalación de Propel.

3. Duplicate table found: propel

Esto es un error frecuente en Symfony cuando trabajas con varias bases de datos al mismo tiempo. En el fichero databases.yml tendrás una configuración parecida a esta:

all:
db1:
configuración de db1
db2:
configuración de db2
...

(Disculpad la maldita indentación de Worpdress)

El problema es que Symfony no respeta el nombre de la base de datos a la hora de generar el fichero schema.yml y utiliza el nombre “propel” para los esquemas siempre. Lo único que hay que hacer es asegurarse de que la primera posición del fichero schema.yml coincide con db1, db2, etc. antes de generar el modelo y luego todo funcionará de maravilla.

Si os devuelve este error a pesar de haber hecho lo anterior, lo más seguro es que tengáis un problema de cache. En este caso, recomiendo borrar el fichero schema.yml y el directorio lib/model (haz copia de seguridad de esto antes de borrarlo por si las moscas) y empezar de nuevo.

4.Forms

Creo que esto se resuelve con las medidas que he tomado con los nombres de tablas y columnas. En cualquier caso, a mi no me ocurre en mi escenario.

5. Fechas

Lamentablemente, todavía no me he peleado suficiente con esto como para darte una resupesta. Seguramente tú sepas más de esto que yo en este momento. Sólo te puedo recomendar optar siempre que se pueda por Timestamps en la base de datos.

En cualquier caso, hice una corrección en este sentido en el motor de ingeniería inversa que ganantiza que Propel no la cagará (como nos tiene acostumbrados) con los valores por defecto en los campos fecha.

Retweet
Publicado el : 5 marzo 2009
Categorías: General
Etiquetas: , ,
Comentarios: 4 comentarios