Como sabes tengo algo de tiempo trabajando con Symfony ( o.O ¡ya más de un año!) y como te comenté en Symfony : ¿Bundle o no bundle? a veces es necesario usar Bundle de terceros. Uno de los casos particulares que te mencionaba es en la generación de PDFs ya que una de las necesidades más comunes es tener que exportar reportes de la pantalla a este tipo de archivo.
Cuando comenzaba con Symfony me la pasaba probando bundle tras bundle hasta que encontraba el que solventaba las necesidades del proyecto y hoy te voy a hablar de uno de ellos que me gustó. El nombre de este bundle es KnpSnappyBundle, si sabes inglés puedes obtener más información aquí y sino aquí te contaré lo básico que necesitas saber para comenzar a usarlo.
KnpSnappyBundle trabaja con wkhtmltopdf y wkhtmltoimage, herramientas que permite pasar el HTML a PDF por lo que, para que funcione, tienes que tenerlas primero en tu servidor. Las puedes descargar de http://wkhtmltopdf.org/.
Una vez hecho esto procedes a agregar esta linea a tu Composer.json
"knplabs/knp-snappy-bundle": "dev-master"
Y en tu AppKernel.php
new Knp\Bundle\SnappyBundle\KnpSnappyBundle(),
Ahora debes indicar en el l archivo config.yml de tu proyecto, que se encuentra en la carpeta app/config, la ubicación de la carpeta donde están el wkhtmltopdf y wkhtmltoimage.
knp_snappy: pdf: enabled: true binary: /usr/local/bin/wkhtmltopdf options: [] image: enabled: true binary: /usr/local/bin/wkhtmltoimage options: []
Hecho esto y ejecutado el comando composer update tienes todo lo necesario para utilizarlo. ¿Fácil? Te daré un ejemplo, desde el controlador tendrás que escribir un código parecido a este:
/** * @Route("/archivopdf", name="archivopdf") * @Method("GET") * @Template("MiBundle:Reportes:archivopdf.html.twig") */ public function archivopdfAction() { $em = $this->getDoctrine()->getManager(); //Consulto a mi base de datos $query = $em->createQuery( "SELECT c.nombre,c.apellidoPaterno,c.apellidoMaterno,c.numeroControl FROM MiBundle:Personal c ); $entities = $query->getResult(); $html =$this->renderView('MiBundle:Reportes:archivopdf.html.twig', array( 'entities' => $entities, )); //Aquí defino los datos del documento como el tamaño, orientación, título, etc. $response = new Response ( $this->get('knp_snappy.pdf')->getOutputFromHtml($html, array('lowquality' => false, 'print-media-type' => true, 'encoding' => 'utf-8', 'page-size' => 'Letter', 'outline-depth' => 8, 'orientation' => 'Portrait', 'title'=> 'Personal con Certificado', 'user-style-sheet'=> 'css/bootstrap.css', 'header-right'=>'Pag. [page] de [toPage]', 'header-font-size'=>7, )), 200, array( 'Content-Type' => '/home/usuario/public_html/Proyecto/web/pdf', 'Content-Disposition' => 'attachment; filename="nombredearchivo.pdf"', ) ); return $response; }
Finalmente, en el archivo archivopdf.html.twig (porque así lo indicamos en el controlador) solo debes tener el código HTML con el que quieres sea presentada la información, puedes usar CSS también y ¡listo!
Como ves es muy fácil y si conoces HTML + CSS será más sencillo aún, lo que en mi caso me resulto complicado es encontrar el bundle. Si quieres saber las opciones de configuración del documento puedes ir directamente a las opciones de uso del wkhtmltopdf.
Espero te sirva. Prueba el bundle y me cuentas que te parece.
¡Nos leemos en la próxima!
49 ideas sobre “Generar PDF con Symfony: KnpSnappyBundle”
Hola, que buen resumen….
Gracias Jorge, bonito día!
Gracias por el aporte, muy bien explicado y aprovecho para preguntarte, como puedo hacer para que el pdf se muestre en otra ventana nueva del navegador.Ya que la instruccion ‘Content-Disposition’=>’inline; filename=»hoja.pdf»‘ me muestra el pdf en la misma ventana de mi aplicacion web.
Hola! 🙂 fácil, solo escribe el target=»_blank» en la liga donde llamas la ruta que te genera el pdf. Por ejemplo:
a href = » {{ path (‘lista_pdf’) }}» target = » _blank »
😉
Gracias por contestar, pero creo que no me di a entender correctamente, tengo un formulario donde obtengo los datos para filtrar la información que se mostrará en el pdf, y desde el controlador creo el archivo pdf con el objeto Response, así que no tengo ningún «a href» que comentas, por lo tanto, el archivo pdf se muestra en la misma ventana de mi aplicación y me gustaría que se mostrara en una ventana nueva.
¡Ah ya! Pensé que generabas desde la vista. Bien pues puedes utilizar la etiqueta base target=»_blank» en la cabecera de la vista donde presentas el PDF o bien puedes usar javascript o alguna librería para contener pdf’s como el pdf.js o PDFObject para recibir el response y mandarlo a un contenedor. Espero te sirva el dato, ¡nos cuentas!. Saludos!
Hola muy buen tutorial.. pero tengo problemas al querer instalar y usar el KnpSnappyBundle… segun el tuto de la página: https://github.com/KnpLabs/KnpSnappyBundle
debo instalar el composer… ya lo instale siguiendo los siguientes pasos: https://www.youtube.com/watch?v=X2LzAJbvuqY
una ves instalado hice todo lo que me decia la página: https://github.com/KnpLabs/KnpSnappyBundle
configure todo como dice pero al momento de ejecutar mi aplicacion me sale un error:
FatalErrorException: Error: Class ‘Knp\Bundle\SnappyBundle\KnpSnappyBundle’ not found in C:\xampp\htdocs\SICONDC\app\AppKernel.php line 11
por favor ayúdeme o digame que estoy haciendo mal
soy nuevo en symfony..
Disculpa la tardanza, he andado algo ocupada. ¿pudiste usarlo? ¿Ejecutaste el composer update Jhonatan? Al inicio es un poco enredado esto de los bundles aquí puedes ver los comandos del composer https://getcomposer.org/doc/00-intro.md
A muchísimas gracias..por la respuesta en si solo me falto hacer un update y ahí funciono todo.. muchísimas gracias…
Ahora tengo un inconveniente por que no se me carga una imagen al momento de generar un pdf desde el controlador:
public function reporteaeAction() {
$em = $this->getDoctrine()->getManager();
$datos = $em->getRepository(‘JHONATHANSicondcBundle:Materia’)->findAll();
$html = $this->renderView(‘JHONATHANSicondcBundle:Secretaria:reporteae.html.twig’, array(
‘datos’ => $datos));
$response = new Response(
$this->get(‘knp_snappy.pdf’)->getOutputFromHtml($html, array(‘lowquality’ => false,
‘print-media-type’ => true,
‘encoding’ => ‘utf-8’,
‘page-size’ => ‘Letter’,
‘outline-depth’ => 8,
‘orientation’ => ‘Portrait’,
‘title’ => ‘Reporte Asignaturas – Especialidades’,
‘user-style-sheet’ => ‘css2/bower_components/bootstrap/dist/css/bootstrap.min.css’,
‘header-right’ => ‘SICONDC’,
‘header-font-size’ => 10,
‘images’=> true,
‘footer-right’ => ‘Pag. [page] de [toPage]’,
‘footer-font-size’ => 7,
)), 200, array(
‘Content-Type’ => ‘application/pdf’,
‘Content-Disposition’ => ‘attachment; filename=»ReporteEspecialidades.pdf»‘
)
);
return $response;
}
he llamado a la imagen de estas 3 formas pero no me funciona ninguna de ellas… tengo que hacer algo mas
se lo agradecería si me ayudara… gracias
¿Cómo tienes la ruta a la imagen en el reporteae.html.twig ?
Para insertar una imagen con el KnpSnappy Bundle con Symfony 2.3 (que es la que utilizo) solo tienes que escribir la ruta con el request y usar un asset para completarla, por ejemplo yo tengo una imagen que se llama logo.png que se encuentra en la carpeta img de mi carpeta web del proyecto y llamo a la imagen con la etiqueta img en la siguiente línea:
src= » {{ app.request.scheme ~’://’ ~ app.request.httpHost ~ asset(‘img/logo.png’) }} »
Ojo, no se si con la última versión de Symfony funcione igual, tengo la impresión de que ya debe ser más fácil pero prueba. 🙂
Gracias… me funciono con el código que me envió… estoy muy agradecido!!
🙂
No hay de que 😉 Que bueno que fue de ayuda! Comparte para poder ayudar a más personas 🙂
Bonito día!
hola chica muy buen resumen queria preguntarte si quiero colocarle la fecha de cuando se creo el dpf como la colocaria
lo solucione colocando este
var meses = new Array («Enero»,»Febrero»,»Marzo»,»Abril»,»Mayo»,»Junio»,»Julio»,»Agosto»,»Septiembre»,»Octubre»,»Noviembre»,»Diciembre»);
var diasSemana = new Array(«Domingo»,»Lunes»,»Martes»,»Miércoles»,»Jueves»,»Viernes»,»Sábado»);
var f=new Date();
document.write(diasSemana[f.getDay()] + «, » + f.getDate() + » de » + meses[f.getMonth()] + » de » + f.getFullYear());
pero note que el aceptó de el dia miércoles me lo trae asi Miércoles,1 de julio de 2015
¿Ya revisaste que en la configuración del response forces a UTF-8?
‘encoding’ => ‘utf-8’
ya lo solucione queria saber como le puedo cambiar el nombre al pdf por ejemplo cada vez que genere una prueba nueva
ya lo solucione queria saber como le puedo cambiar el nombre al pdf por ejemplo cada vez que genere una prueba nueva y guarde ese pdf con el nombre prueba tres por ejemplo
Mmm, pienso que tendrías que codificar pasar el nombre al response en el arreglo:
array(
‘Content-Type’ =>
‘/home/usuario/public_html/Proyecto/web/pdf’,
‘Content-Disposition’ => ‘attachment;
filename=»nombredearchivo.pdf»‘,
)
Es decir, definir el nombre fuera del response y pasar el arreglo.
buenos dias me has ayudado muchisimo muchas gracias tengo otra duda si ya genere el pdf como una vista como hago para regresarme para anterior pagina que contiene el boton que me genera el pdf en una vista
Hola Génesis, que gusto haberte ayudado. No entiendo bien tu pregunta. Para regresar con el back de tu navegador, una vez que te abre el PDF no tienes manera de meterle algún botón, solo como una liga pero como estás trabajando una aplicación web, con el navegador puede regresar sin problema a la pantalla anterior.
bueno gracias igual si con esa pregunta no me supe explicar …… quiero hacerte otra pregunta tengo el siguiente botón y quiero agregarle algo que me mande a una nueva pestaña de mi navegador
No puedo ver tu código Génesis, me lo puedes mandar por correo a ana.loyo@ana2lp.mx y lo reviso 😉
****///////////***
Podrías decirme si se puede paginar con el knpsnappybundle. Gracias. Muy buena información.-
Hola, ¿a qué te refieres con paginar? Este bundle te permite generar archivos PDF con diversas características, dependerá como lo configures. Para paginación en tu aplicación te recomiendo el KnpPaginatorBundle 😉
Saludos!
Te agradezco la sugerencia, pero lo que en realidad necesito hacer es poner saltos de página con el knpsnappybundle, ya que tengo un twig que me muestra la información y quiero que salga a un PDF. Pero cuando realiza los saltos de página tiende a perder información, por eso es que necesito saber si hay alguna manera de hacer saltos de página con este bundle.- Gracias.-
Hola! ¿Sabes como hacer para colocarle una ruta específica en el controlador y el PDF quede guardado en ella? Por ejemplo que guarde todos los PDFs en /var/www/mi_archivo. Intente colocar la ruta en ‘Content-Type’ pero no me sirvio.
Gracias. Muy buen artículo y bonita página!
Hola Javier,
intenta con esta línea
$pdf->generate(‘TuHTML’, ‘/tmp/mis_archivos’);
Bonito día!
🙂
Hola Ana Luz! En primer lugar muchas gracias por este aporte. En 2022 lo sigo utilizando y va de maravilla la verdad.
Pero estoy intentando generar el pdf en la ruta que deseo y me salta error de «Error: escapeshellarg(): Argument exceeds the allowed length of 8192 bytes». Estoy ejecutando el server de Symfony, con el comando server:start, con lo que no se donde modficar el «memory_limit» y no se si me dará este error en producción… Sabes como arreglarlo?
Gracias!
Hola Javi, el día que escribiste justo estaba recibiendo a mi bebé, disculpa que no respondiera. En unos días lo checo y espero te sirva.
primero q todo gracias por ese pequeño tutorial para hacer pdf con symfony, te cuento apenas empeze en el mundo del symfony y esta pequeña guia me ayudo mucho, la pagina q cree con twig me la pasa a pdf pero no me pasa una imagenes q tiene esa pagina q se podria hacer para q tambien me pase las imagenes al pdf
Es justo lo que a mi me pasó al inicio con este bundle jajaja! Pero es muy fácil y por aquí en los comentarios lo respondí, te repito la respuesta:
Para insertar una imagen con el KnpSnappy Bundle con Symfony 2.3 (que es la que utilizo) solo tienes que escribir la ruta con el request y usar un asset para completarla, por ejemplo yo tengo una imagen que se llama logo.png que se encuentra en la carpeta img de mi carpeta web del proyecto y llamo a la imagen con la etiqueta img en la siguiente línea:
src= ” {{ app.request.scheme ~’://’ ~ app.request.httpHost ~ asset(‘img/logo.png’) }} ”
Ojo, no se si con la última versión de Symfony funcione igual, tengo la impresión de que ya debe ser más fácil pero prueba. 🙂
gracias cuando habia mandado la pregunta me puse a leer los otras preguntas y alli estaba la respuesta.
Tengo otra pregunta, como dije apenas estoy aprendiendo symfony bueno baje la version 2.7.6 y estoy practicando haciendo una pequeña aplicacion, alli pues la idea es practicar de todo un poquito ; se conecta a una base de datos postgres, hasta ahi todo bien tengo q actualizar todos los registros de una tabla, leyendo en otra pagina de internet sale q se puede utilizar la siquiente linea codigo:
UPDATE nombreBundle:nombre n SET n.ur= funcion(n.url);
funcion(n.url) es una funcion q ya tengo definidad en otra parte, y n es el alias del bundle, pero cuando hago esto me sale error de syntaxis y no se porque, esta linea de comando esta dentro de un controller, pero no se si antes de poner esa linea de comando toca q haer algo la verdad estoy como gringo por al ejecutar la pagina principal sale error de syntasis en esa linea
Hola Diego, no entiendo muy bien lo que quieres hacer. Me puedes mandar por correo el ejemplo de lo que haces para revisarlo?
Bonita tarde!
tratare de explicarte de otra forma quiero actualizar 1200 registros todos a la ves, entonces en otra pagina de internet encontre esta linea de codigo q supuestamente actualiza por asi decirlos en lote
UPDATE nombreBundle:nombre n SET n.ur= funcion(n.url);
entonces esta linea de codigo la agregue en un controlador y puedo la llave para q ejecutara, pero siempre me sale error de syntaxis.
Ah bien, entiendo ahora lo que quieres hacer … pero aún así necesitaría ver el fragmento de código donde pretendes hacer eso que comentas, no solo la linea y así te puedo ayudar. Mándalos a mi correo ana.loyo@ana2lp.mx y te respondo. Bonito día!
hola Ana Luz tengo otra preguntica en particular puede q sea de facil respuesta, pero para mi q soy nuevo en symfony se me complica. tengo 3 tablas una llamada pais, otra regiones y otra llamada ciudades, la idea es q la persona cuando seleccione de una lista desplegable el pais, en la lista desplegable de regiones solo me aparescan las regiones de ese pais lo mismo pasa para regiones cuando ya alla seleccionado una region de la lista desplegable solo me aparesca las ciudades de esa region q escogio.
entonces lo primero q estoy haciendo es mostrar en una plantilla es esto:
{{ render(controller(‘PaisBundle:Default:listarpaises’)) }}
este render me llama a este controlador q tiene q tiene el siguiente codigo
public function listarpaisesAction()
{
$em = $this->getDoctrine()->getManager();
$paises = $em->getRepository(‘PaisBundle:Pais’)->findBy(array(‘visibleRegistro’ => TRUE));
return $this->render(‘PaisBundle:default:listarpaises.html.twig’, array(‘paises’=>$paises));
}
este codigo me busca todos los paises que tenga el campo visible=true esto lo hace bien, este controlador
llama a la siguiente plantilla q tiene el siguiente codigo:
{% for pais in paises %}
{{ pais.nombrePais}}
{% endfor %}
var lista=document.getElementById(‘paisselecionado’);
var pais_seleccionado = lista.options[lista.selectedIndex].value;
este codigo lo q hace es mostrarme la lista desplegable cosa q lo hace bien, y en la variable pais_seleccionado
me esta guardando el codigo del pais seleccionado y es el que necesito para poder filtrar las regiones q le pertenecen a ese pais, la pregunta es ¿como hago para sacar ese valor de un javascrip ? y pasarlo a otro controlador q me haga la busqueda de las regiones y a donde pongo esa linea codigo??
Hola, en primer lugar gracias por el aporte, me ha sido de mucha ayuda para saber utilizar este Bundle. Estoy utilizando la versión 2.3 de Symfony y aparte del problema de las imágenes que ya vi la solución en los comentarios (utilizando request en src= ” {{ app.request.scheme ~’://’ ~ app.request.httpHost ~ asset(‘img/logo.png’) }} ”), tengo un problema que no consigo solucionar. Estoy utilizando FOSJsRoutingBundle para generar rutas y en la plantilla que convierto a pdf con KnpSnappyBundle tengo lo siguiente:
Con ésta línea al generar el pdf me da el siguiente error(el mismo error que me daba con las imagenes antes de usar request en las rutas):
The exit status code ‘1’ says something went wrong:
stderr: «Loading pages (1/6)
[> ] 0%
[======> ] 10%
QSslSocket: cannot resolve SSLv3_client_method
QSslSocket: cannot resolve SSLv3_server_method
….
¿Habría alguna forma de cambiar eso para que funcione? Estoy empezando en esto, así que agradecería tu ayuda.
Gracias y un saludo.
No se mostró la línea que me da problema, que es la siguiente:
Sigue sin mostrarse, supongo que será por las etiquetas de javascript, es donde se enlaza el código con las etiquetas script con el siguiente contenido:
type=»text/javascript» src=»{{ path(‘fos_js_routing_js’, {«callback»: «fos.Router.setData»}) }}»
Hola! Disculpa la tardanza, he tenido bastante trabajo. ¿pudiste resolver tu problema? Sino házmelo saber para ver como te puedo ayudar 🙂
Saludos y muchas gracias por el aporte me sirvió de mucho.
No hay de que! Espero poder escribir de más temas que puedan ser útiles! 🙂 Saludos!
Hola, estoy tratando de usar KnpSnappyBundle para generar pdf, pero no se donde poner el wkhtmltopdf. Puedes ayudarme?
aquí tienes mi config.yml
knp_snappy:
pdf:
enabled: true
binary: %kernel.root_dir%/wkhtmltopdf
options: []
estoy ttrabajando con W10, y he descargado el wkhtmltopdf-maste. Lo he copiado dentro de la carpeta Web. El error que me muestra es este,..
Attempted to load interface «GeneratorInterface» from namespace «Knp\Snappy».
Did you forget a «use» statement for e.g. «Sonata\EasyExtendsBundle\Generator\GeneratorInterface» or «Sonata\MediaBundle\Generator\GeneratorInterface»?
Buenos días, muchas gracias por el articulo.
Con esto es posible unificar html: array($portada, $html, $dos). Sabes si es posible que la variable $dos ya sea un .pdf?
Hola Jordi, no he utilizado el bundle últimamente pero trato de actualizar los datos y les cuento en unos días, gracias por tu comentario
Hola. Gracias por el aporte. Queria preguntarte, sabes si es compatible con Symfony 6?
Estoy haciendo un proyecto y necesito generar pdfs, con este bundle parece sencillo, pero en esta version de Symfony ya no existe el config.yml como tal.
Sabrías decirme donde implementar el condigo ese?
Gracias!!
Hola! Disculpa que no te respondiera. Justo cuando comenzaste a escribir estaba por tener a mi hija. Reviso con calma tus preguntas y te escribo correo o bien otro artículo, no pasa de este mes, espero te sirva 🙂 ¡Gracias por tus comentarios!