KnpLabs / KnpSnappyBundle

Easily create PDF and images in Symfony by converting html using webkit
http://knplabs.com
MIT License
1.23k stars 143 forks source link

[Example] Generate a PDF file from a Twig view with headers and footers in Symfony3 #195

Closed eved42 closed 4 years ago

eved42 commented 7 years ago

It's not an issue but an example of a correct way to generate a PDF file from a Twig view in a Symfony3 project, with a header and a footer.

I think it's important to show a complete configuration because I spent lots of hours to make it works, I think it can be very useful for everyone who starts with KnpSnappyBundle.

My project : Symfony 3.3.* in local with Wampserver 3.0.0

1) Install KnpSnappyBundle 2) Install wemersonjanuario/wkhtmltopdf-windows

3) config.yml

knp_snappy:
    pdf:
        enabled: true
        binary: %kernel.root_dir%/../vendor/wemersonjanuario/wkhtmltopdf-windows/bin/64bit/wkhtmltopdf.exe
        options:
           page-size: A4
           dpi: 300
           image-quality: 80
           margin-left: 15mm
           margin-right: 15mm
           margin-top: 15mm
           margin-bottom: 15mm
           user-style-sheet: %kernel.root_dir%/../web/assets/css/pdf.css

4) header.html.twig You have to add a complete path to your assets.

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>My PDF</title>
    </head>
    <body>
        <header>
            <img src="{{ path ~ asset('assets/images/preview/logo.jpg') }}" alt="Logo" height="180" />
        </header>
    </body>
</html>

5) content.html.twig

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>My PDF</title>
        <link href="https://fonts.googleapis.com/css?family=Open+Sans:400,400i,700,700i" rel="stylesheet">
    </head>
    <body>
        <h1>My PDF</h1>
        <p>Harum trium sententiarum nulli prorsus assentior.</p>
    </body>
</html>

6) footer.html.twig (example of using a page counter)

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title>Contrat Thuasne Services</title>
        <script>
            /* page counter */
            function subst() {
                var vars={};
                var x=document.location.search.substring(1).split('&');
                for (var i in x) {var z=x[i].split('=',2);vars[z[0]] = unescape(z[1]);}
                var x=['topage','page'];
                for (var i in x) {
                    var y = document.getElementsByClassName(x[i]);
                    for (var j=0; j<y.length; ++j) y[j].textContent = vars[x[i]];
                }
            }
        </script>
    </head>
    <body onload="subst()">
        <footer>
            <table>
                <tr>
                    <td style="width: 33%;">{{ customer.name }}</td>
                    <td style="width: 34%;" class="center"><span class="page"></span>/<span class="topage"></span></td>
                    <td style="width: 33%;" class="right">&copy; Society {{ "now"|date("Y") }}</td>
                </tr>
            </table>
        </footer>
    </body>
</html>

7) Controller :

/**
 * Generate and save a PDF
 *
 * @Route("/contracts/{id}/pdf", name="contract_pdf")
*/
public function pdfAction($id, Request $request) {
    // get contract from database
    $em = $this->getDoctrine()->getManager();
    $c = $em->getRepository('AppBundle:Contract')->find($id);

    $path = $request->server->get('DOCUMENT_ROOT');    // C:/wamp64/www/
    $path = rtrim($path, "/");                         // C:/wamp64/www

    $html = $this->renderView('contracts/pdf/content.html.twig', array('c' => $c));

    $header = $this->renderView('contracts/pdf/header.html.twig', array(
        'path' => $path
    ));
    $footer = $this->renderView('contracts/pdf/footer.html.twig', array(
        'customer' => $c->getCustomer()
    ));

    $output = $path . $request->server->get('BASE');        // C:/wamp64/www/project/web
    $output .= '/pdf/contract-'. $c->getCustomerCode() .'.pdf';

    // Generate PDF file
    $this->get('knp_snappy.pdf')->generateFromHtml($html, $output, array(
        'header-html' => $header,
        'footer-html' => $footer,
    ));

    // Message + redirection
    $this->addFlash('success', 'The PDF file has been saved.');
    return $this->redirectToRoute('contract');
}

Your 3 Twig files must be "stand-alone" HTML files with a DOCTYPE, <html>, <head> and <body> tags. If you have some errors, they probably came from a bad link to a css file, picture, etc.

Hope it helps ! ;-)

dsentker commented 6 years ago

Where does the "path" variable comes from in your header.html.twig?

eved42 commented 6 years ago

@dsentker From the controller :

$path = $request->server->get('DOCUMENT_ROOT');    // C:/wamp64/www/
$path = rtrim($path, "/");                         // C:/wamp64/www

$header = $this->renderView('contracts/pdf/header.html.twig', array(
    'path' => $path
));
dsentker commented 6 years ago

Thank you!

ducho commented 5 years ago

@eved42 Sorry, but this solution not working!

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.