Crea archivos PDF como si fueran una página Web
Un requerimiento común en los proyectos es la generación de reportes de los datos almacenados dentro de la aplicación. Lamentablemente las herramientas disponibles en PHP para la generación automática de reportes es bastante limitada, y posiblemente el único formato que disponemos para la presentación de estos datos de una manera agradable es el PDF.
Sin embargo, la generación de PDF es bastante tediosa, usualmente las librerías de PHP disponibles para la generación de estos archivos requieren manipular detalles como celdas, píxeles, posiciones absolutas en las coordenadas X e Y, etc. Realmente, muy poco ágil.
Afortunadamente existe una de las herramientas más increibles que haya encontrado navegando en la web: DOMPDF, esta librería permite convertri cualquier página web en un archivo PDF, practicamente con ningún esfuerzo. Es realmente impresionante, incluso tiene soporte para archivos externos css, tipos de letras, y no depende de ninguna extendión de php.
DOMPDF soporta declaraciones básicas de CSS 2.1, los grandes faltantes son position y float, lo cual hará que el diseño de tus HTML para la generación automática de PDF, se parezcan más a algo hecho en Dreamweaver.
Sin duda, las horas que ahorra esta librería son innumerables. Puedes tener una versión html de tu reporte para ser visualizada con el explorador, y usar el mismo código para la versión PDF.
La magia no termina aquí. He escrito además un helper para mi framework favorito, cakephp, que facilita en gran medida la utilización de esta librería. Aquí cómo usarlo:
- Descarga DOMPDF y coloca el contenido dentro de app/vendors/dompdf. Destro de esta carpeta debería estar el archivo dompdf_config.inc.php
- Descarga el helper desde su repositorio y colócalo en app/views/helpers
- Abre el archivo app/routes.php y coloca esta línea: Router::parseExtensions(‘pdf’) al principio de este archivo. Esto hará que las solicitudes como /personas/listar.pdf sean pasadas a traves del layout de pdf y se genere el archivo.
- Agrega RequestHandler a la lista de componentes de tu controlador, si es que no está incluido aún.
- Crear el layout: haz un nuevo archivo en app/views/layouts/pdf/default.ctp y coloca tu layout html como quieres que se vea en tu pdf. Haz uno sencillo. Puedes guiarte del layout por defecto que tengas. Aqui tienes un ejemplo. Observa las lineas adicionales al final. Esto hará que se genere correctamente el archivo.
- Crea la vista correspondiente en la carpeta pdf corerspondiente, por ejemplo: app/views/solicitudes/pdf/ver.ctp.
- Solicita el url correspondiente con la extension .pdf al final
- Disfruta
Gracias por el artículo
Está muy bien explicado pero yo no logro q me funcione.
Me parece que debo tener algún problema en los últimos pasos. El layout es un layout normal pero con las últimas líneas.
Pero después no entiendo muy bien lo que hay que meter en la vista. ¿hay que crear una carpeta pdf en la vista correspondiente y dentro de esta carpeta la función que quiero llamar?
Un saludo y enhorabuena por el artículo
Excelente, lo unico que no me anda. me manda un error dice:
Undefined variable: dompdf [APP\views\atencion_clientes\pdf\estadistica.ctp, line 2]
Gracias
Disculpen el retraso de mi respuesta. Estuve de vacaciones.
@juan
Recuerda que en cakephp las vistas se colocan en views/nombre_controlador/accion.ctp.
Lo que tienes que hacer siemplemente es crear /vies/nombre_controlador/pdf/accion.ctp
@Arcadio
No sé por qué estás usando la variable dompdf en tu vista. el helper se llama PDF, no Dompdf
Hola José:
Creo haber seguido todos los pasos correctamente.
También he hecho la correción que se indica en el Grupo de Google para Cakephp http://tinyurl.com/9ket8x, ya que tenía el mismo problema.
Ahora ya no me da error, el problema que tengo es que el parseExtensions no parece funcionar ya que tanto si llamo a controlador/accion como si llamo a controlador/accion.pdf se ejecuta la misma vista. ¿A alguien le ha ocurrido algo parecido?
Gracias por adelantado.
@Nomen
¿Tienes la vista especial para pdf?, si no la tienes siepre te va a mandar la vista html, aunque le pidas una extensión especial.
Hola José:
Sí que tengo la vista especial.
He solucionado el problema. He estado leyendo http://tinyurl.com/8njmv9, donde se explica cómo usar JSON en Cake. Una de las cosas que se indica es que “We also need enable the RequestHandler component. Add the following to your app_controller.php” y se pide que se añada “var $components = array(‘RequestHandler’);”
Yo lo he añadido en el propio controlador que va a generar el PDF, para que no sea un proceso que se realice en todos los controladores, ya que sólo lo necesito para este controlador, y ha funcionado.
Tienes razón, se me olvidó incluir eso en las instrucciones. Normalmente incluyo el RequestHandler en todos mis proyectos por que ofrece muchas cosas útiles. Voy a agregarlo al artículo.
Gracias!
Un placer colaborar para que mejore el manual.
Un saludo!
Hola buenas… veo muy interesante el artículo pero no logro hacerlo funcionar, he seguido todos los pasos (usando cake) y me da una serie de errores que no logro entender… algunos de ellos son estos:
Strict Standards: Non-static method Configure::corePaths() should not be called statically, assuming $this from incompatible context in /home/pabloked/workspace/LG_cake/cake/libs/debugger.php on line 330
Strict Standards: Non-static method Cache::read() should not be called statically, assuming $this from incompatible context in /home/pabloked/workspace/LG_cake/cake/libs/configure.php on line 489
No se si tienes alguna idea de que puede ser como la version del cake, etc…
Un saludo y muchas gracias por adelantado
Hola José:
Estoy viendo el helper que hiciste, he seguido los pasos del tuto que hiciste, pero ahora como hago para llamarlo. Agregue en el controlador el helper que creaste y luego lo llamo $Pdf->??. Agredeceria tu pronta respuesta.
Gracias.
@pabloked
Hola pablo, el problema es que tienes una version de php con los errores de strict standards activados, busca en google como ocultalos, o simpolemente coloca el nivel de debug de cakephp en 0 en el archivo core.php
@Pedro
Sigue todos los pasos, luego de agregar el helper debes crear las vistas correspondientes, la generación de pdf es automática, no es necesario realmente llamar al helper directamente.
Saludos
Hola José,
ya logre sacar los errores y entender un poco mas dompdf con cake. Ahora algunas cosas que no me quedan en claro, tengo mi vista y creo una carpeta que se llame pdf y ahi pongo lo que quiero que me muestre el pdf. Suponte tengo una vista que se llama carta(dentro de ella tengo los add, edit,view) dentro de esa creo la carpeta pdf y dentro de esa carpeta copio el codigo de view y la llamo igual?. Te explico mi esenario. Lo estoy probando en mi maquina atraves del localhost y lo que me esta ocurriendo es que cuando pongo la url carta/view.pdf se redirecciona a http://www.localhost.com, y ahi se muere.
Agradeceria tu pronta respuesta para poder resolverlo.
Gracias
Jose:
He seguido los pasos al pie de la letra (salvo por el layout y la vista que ocupe los que ya tenia) y no logro que me funcione, al solicitar la direccion con extension pdf solo aprece esto en el navegador:
?>
agradeceria que me guiaras
Trata de explicar un poco más. ¿Cómo es que ecupaste los layouts que ya tenias? ¿Qué Página estás solicitando?
Hola de nuevo Jose, estuve de viaje por eso me demore en ver tu respuesta
Mira:
La pagina que estoy solicitando es “mallas.pdf”, si no agrego la extension muestra la pagina normalmente.
Cree el archivo app/views/layouts/pdf/default.ctp con el layuot por defecto que tenia, agregandole las lineas
load_html($output);
$pdf->render();
$pdf->stream($title_for_layout.’.pdf’);
exit;
?>
Luego la vista que utilice fue la misma que tenia, pero esta la coloque en app/views/mallas/pdf/ver_mallas.ctp.
disculpa por el error de codigo, las lineas que agregue fueron estas:
load_html($output);
$pdf->render();
$pdf->stream($title_for_layout.’.pdf’);
exit;
?>
no puedo escribir el codigo. coloque las lineas que aparecian en el ejemplo que publicaste
Me sucede lo siguiente:
Cuando llamo a la url que debe tener el pdf, me sale un error “Firefox no puede encontrar el archivo en http://blablabla/cliente/index.pdf.”
tengo el debug en cero, y cuando abro cualquier accion de el controlador que carga al helper pdf, me sale la página en blanco, al poner debug en 1, me aparece una laaaarga lista de errores Strict Standards, y al final, trata de cargar modulos del DOMPDF que no existen, como “javascripthelper.cls.php”, por lo que da un error en el requiere_once().
Hola, gracias pr comentar. Estrés un error que ocurre con algunas versiones de php. En guano tenga acceso al código de uno de mis proyectos te envió la solución. Básicamente es cambiar el autoload de dompdf para que haga el require solo si el archivo es de dompdf y existe. El problema es que trata de cargar los helpers de cake como si fueran clases de dompdf.
Muchas gracias por el dato, le puse esto.
function DOMPDF_autoload($class) {
$filename = mb_strtolower($class) . “.cls.php”;
if(file_exists(DOMPDF_INC_DIR . “/$filename”)){
require_once(DOMPDF_INC_DIR . “/$filename”);
}
}
y dunciona sin problemas, ahora me queda hacer que se vea un poco mas bonito, poner css o algo.
Buenas!
Esta es la solución que buscaba y me estoy peleando con él… tengo problemas con la llamada… siempre me dice “El archivo no empieza por ‘%pdf-’” y me tiene desesperado….
el asunto es que lo que quiero es que sea un view lo que me devuelva en pdf… como lo debería llamar? view/1.pdf ?
gracias!
Coloca primero el debug en cero para probar que no sean errores en el html generado. La tabla de los sql normalmente daña el pdf. También revisa que no tengas espacion al inicio o al final de tus archivos php, esto hace que la primera linea del pdf sea un espacio y por eso se dañe también.
En caso de dudas de lo que esté haciendo el sistema, puedes abrir el pdf con un editor de texto plano y ver si en efecto el pdf no comienza por “%pdf”
OK!
Se soluciono, creo que fue un poco de todo con el tema del debug a 0 pero tambien que no hacia bien la llamada para el archivo, ya que en mi caso queria que fuera un view pasandole un parametro. La llamada tiene que ser controlador/view/1/nombrefchero.pdf y todo ok.
Otra cosa que tenia mal era que dentro de la carpeta views, dentro del controlador (por ejemplo clientes) tiene que estar por ejemplo el index, el view y una carpeta llamada pdf con el view.ctp (no sé porque yo le llame ver.ctp)… en fiiiiin
que todo funciona! muchas gracias por la ayuda!