Je n'arrive pas à générer mon pdf, j'ai une erreur en retour sur l'url, il semble que le path ne soit pas pris encompte

voici mon controller avec dompdf

<?php

namespace App\Controller;

use App\Entity\Order;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Dompdf\Dompdf;
use Dompdf\Options;

//require_once 'vendor/dompdf/dompdf/autoload.inc.php';

class AccountOrderController extends AbstractController
{
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }
    /**
     * @Route("/compte/mes-commandes", name="account_order")
     */
    public function index(): Response
    {

        $orders = $this->entityManager->getRepository(Order::class)->findSuccessOrders($this->getUser());

        return $this->render('account/order.html.twig', [
            'controller_name' => 'AccountOrderController',
            'orders' => $orders
        ]);
    }

    /**
     * @Route("/compte/mes-commandes/{reference}", name="account_order_show")
     */
    public function show($reference): Response
    {

        $order = $this->entityManager->getRepository(Order::class)->findOneByReference($reference);

        if (!$order || $order->getUser() != $this->getUser()) {
            return $this->redirectToRoute('account_order');
        }

        return $this->render('account/order_show.html.twig', [
            'controller_name' => 'AccountOrderController',
            'order' => $order
        ]);
    }

    /**
     * @Route("/compte/ma-facture/{reference}", name="show_pdf")
     */
    public function facture($reference): Response
    {

        // Configure Dompdf according to your needs
        $pdfOptions = new Options();

        $pdfOptions->set('defaultFont', 'Arial');

        // Instantiate Dompdf with our options
        $dompdf = new Dompdf($pdfOptions);

        $order = $this->entityManager->getRepository(Order::class)->findOneByReference($reference);

        /* if (!$order || $order->getUser() != $this->getUser()) {
            return $this->redirectToRoute('account_order');
        }*/

        return $this->render('account/facture.html.twig', [
            'order' => $order
        ]);

        // Retrieve the HTML generated in our twig file
        $html = $this->renderView('account/facture.html.twig', [
            'order' => $order
        ]);

        // Load HTML to Dompdf
        $dompdf->loadHtml($html);

        // (Optional) Setup the paper size and orientation 'portrait' or 'portrait'
        $dompdf->setPaper('A4', 'paysage');

        $dompdf->setBasePath(realpath('account/facture.html.twig'));

        // Render the HTML as PDF
        $dompdf->render();

        // Output the generated PDF to Browser (force download)
        $dompdf->stream("mafacture.pdf", [
            "Attachment" => true
        ]);
    }
}

voici ma page avec le bouton imprimer

{% extends 'base.html.twig' %}
{% block title %}
    Ma commande - Le cercle des saveurs

{% endblock %}
{% block body %}
    <h1>
        Ma commande

        {{ order.reference }}
    </h1>
    <a href="{{ path('account_order') }}">
        Retour
    </a>
    <hr>
    <strong>
        Statut de la commande :
    </strong>
    {% if order.state == 1 %}
        Paiement accepté

    {% elseif order.state == 2 %}
        Préparation en cours

    {% elseif order.state == 3 %}
        Livraison en cours

    {% elseif order.state == 4 %}
        Livrée

    {% endif %}
</br>
<strong>
    Commande passée le :
</strong>
{{ order.createdAt|date('d/m/Y') }}</br><strong>
Référence de la commande :</strong><small>
{{ order.reference }}</small></br><strong>Transporteur choisi :</strong>{{ order.carrierName }}<hr><strong>Détails :</strong><table class="table mt-4"><thead>
<tr>
    <th scope="col">
        Produit
    </th>
    <th scope="col">
        Quantité
    </th>
    <th scope="col">
        Prix unitaire
    </th>
    <th scope="col">
        Total
    </th>
</tr></thead><tbody>
{% for product in order.orderDetails %}
    <tr>
        <td>
            {{ product.product }}
        </td>
        <td>
            x

            {{ product.quantity }}
        </td>
        <td>
            {{ (product.price / 100)|number_format(2, ',', '.') }}
            €
        </td>
        <td>
            {{ (product.total / 100)|number_format(2, ',', '.') }}
            €
        </td>
    </tr>
{% endfor %}</tbody></table><div class="text-right"><strong>
Sous-total :</strong>{{ (order.getTotal / 100)|number_format(2, ',', '.') }}€</br><strong>Livraison :</strong>{{ (order.carrierPrice / 100)|number_format(2, ',', '.') }}€</br><strong>Total général :</strong>{{ ((order.carrierPrice + order.getTotal) / 100)|number_format(2, ',', '.') }}€</div><a href="{{ path ('show_pdf') }}" class="btn btn-primary">Imprimer</a>{% endblock %}

Ce que je veux

le rendu simpliste pour le moment que je veux récupérer avec mon fichier twig

{% block body %}

    <h1>Ma commande
        {{ order.reference }}</h1>

    <hr>
    <strong>Statut de la commande :</strong>
    {% if order.state == 1 %}
        Paiement accepté
    {% elseif order.state == 2 %}
        Préparation en cours
    {% elseif order.state == 3 %}
        Livraison en cours
    {% elseif order.state == 4 %}
        Livrée
    {% endif %}
</br>
<strong>Commande passée le :</strong>
{{ order.createdAt|date('d/m/Y') }}</br><strong>Référence de la commande :&nbsp;</strong>{{ order.reference }}</br><strong>Moyen de retrait choisi :&nbsp;</strong>{{ order.carrierName }}<hr><strong>Détails :</strong><table class="table mt-4"><thead></thead><tr>
<th scope="col">Produit</th>
<th scope="col">Quantité</th>
<th scope="col">Prix unitaire</th>
<th scope="col">Total</th></tr></thead><tbody>{% for product in order.orderDetails %}
<tr>
    <td>{{ product.product }}</td>
    <td>x
        {{ product.quantity }}</td>
    <td>{{ (product.price / 100)|number_format(2, ',', '.') }}
        €</td>
    <td>{{ (product.total / 100)|number_format(2, ',', '.') }}
        €</td>
</tr>{% endfor %}</tbody></table><div class="text-right"><strong>Sous-total :</strong>{{ (order.getTotal / 100)|number_format(2, ',', '.') }}€</br><strong>Livraison :</strong>{{ (order.carrierPrice / 100)|number_format(2, ',', '.') }}€</br><strong>Total général :</strong>{{ ((order.carrierPrice + order.getTotal) / 100)|number_format(2, ',', '.') }}€</div>{% endblock %}

Ce que j'obtiens
An exception has been thrown during the rendering of a template ("Some mandatory parameters are missing ("reference") to generate a URL for route "show_pdf".").

Merci pour votre aide

19 réponses


Jessy Brs
Réponse acceptée

Top, avec plaisir ! :D

Salut tu peux montrer ton message d'erreur s'il te plaît.

Je vois sinon l'élement suivant ">setBasePath". Ce sont pour les les liens externes stylesheets, image etccc.
Et il me semble qu'il faut que les chemins soit absolues.
Donc je ne comprend pas pourquoi tu réappelles ton fichier twig dedans.

Au plaisir

Hello,
effectivement, j'ai retiré le set base path.
Mon erreur apparaît dès que je mets sur mon button href="{{ path('show_pdf')}}" dans mon order_show.html.twig
Voici ce qui arrive :
https://1drv.ms/i/s!ApTy6lAHvKDhiKcXxD5y5t4e70--jg?e=iqlfIn

merci pour ton retour

Hello,

de ce que je vois, tu veux générer une URL vers "show_pdf", mais quand je regarde la définition de ta route, elle prend un paramètre :

/**
  * @Route("/compte/ma-facture/{reference}", name="show_pdf")
  */

Il faut donc générer ton URL avec les bons paramètres et tu devrais avoir un PDF correct.

Hello, c'est logique. J'ai changé path

<a href="{{ path ('show_pdf', { 'reference' : order.reference }) }}" class="btn btn-primary">Imprimer</a>

et ququand je clique sur le bouton j'ai une autre erreur qui je ne comprends pas puisque j'ai mon use

https://1drv.ms/i/s!ApTy6lAHvKDhiKcZZM7Wkkwin8JXWA?e=J0ATQf

Hello,
Bon j'ai réinstallé dompdf. je n'ai plus d'erreur mais il m'ouvre une page blanche.
Une idée ?
Merci

Tu as vérifié le chemin vers ton fichier html ?
Remontre ton controller et ton template

Jeswy Brs,
Tu sais le voir plus haut. J'arrive à imprimer un pdf mais en mettant {% extend 'base.html.twig' %} mais du coup je récupère le header et le footer du site. Si je retire de nouveau page blanche

Si tu le retires, tu dois de nouveau mettre le html de base avec les balises <head> et <body>

J'ai déjà essayé mais lorsque je sauvegarde il met mes balises </body> et </html> à la fin du end if. Du coup je n'ai que le début du pdf avant le end if

Hello Jessy Brs,
comme expliqué n'accepte que la fin des balises body et html après le endif, mais il me sort un pdf sur plusieurs pages. Une idée, merci.

{# {% extends 'base.html.twig' %}
{% block title %}
    Ma commande - Le cercle des saveurs

{% endblock %}
{% block body %}#}
<html>
<head>

</head>

<body>
<h1>Le Cercle des Saveurs</h1>
<hr>
<h3>
    Facture n° {{ order.reference }}
</h3>
<hr>
<strong>
    Statut de la commande :
</strong>
{% if order.state == 1 %}
    Paiement accepté
{% elseif order.state == 2 %}
    Préparation en cours
{% elseif order.state == 3 %}
    Livraison en cours
{% elseif order.state == 4 %}
    Livrée
{% endif %}
</body>
</html>
</br>
<strong>
    Commande passée le :
</strong>
{{ order.createdAt|date('d/m/Y') }}</br><strong>
    Référence de la commande :</strong><small>
    {{ order.reference }}</small></br><strong>Transporteur choisi :&nbsp;</strong>{{ order.carrierName }}<hr><strong>Détails :</strong><table class="table mt-4"><tr>
        <th scope="col">
            Produit
        </th>
        <th scope="col">
            Quantité
        </th>
        <th scope="col">
            Prix unitaire
        </th>
        <th scope="col">
            Total
        </th></tr></thead><tbody>{% for product in order.orderDetails %}
        <tr>
        <td>
            {{ product.product }}
        </td>
        <td>
            x

            {{ product.quantity }}
        </td>
        <td>
            {{ (product.price / 100)|number_format(2, ',', '.') }}
            €
        </td>
        <td>
            {{ (product.total / 100)|number_format(2, ',', '.') }}
            €
        </td>
        </tr>{% endfor %}</tbody></table><div class="text-right"><strong>Sous-total :</strong>{{ (order.getTotal / 100)|number_format(2, ',', '.') }}€</br><strong>Livraison :</strong>{{ (order.carrierPrice / 100)|number_format(2, ',', '.') }}€</br><strong>Total général :</strong>{{ ((order.carrierPrice + order.getTotal) / 100)|number_format(2, ',', '.') }}€</div>{# {% endblock %}#}
</body>
</html>

https://1drv.ms/b/s!ApTy6lAHvKDhiKcdplYtIPexk1EyoQ?e=pppDur

Ton problème de PDF est résolu.
Là c'est une problème de html.

Tu retire ta base.html.twig pour ne pas avoir le menu de ton site. C'est très bien.
Tu ajoutes les balises body et head car ils sont obligatoires. Très bien. Maintenant il faut respecter le format standart.

<!doctype html>
<html lang="fr">
<head>
  <meta charset="utf-8">
  <title>Titre de la page</title>
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
</head>
<body>
  ...
  <!-- Tout le contenu de ton pdf -->
  ...
</body>
</html>

Et là je ne me retrouve pas avec plusieurs balise body et html.

Hello Jessy Brs,

C'est ce que j'ai essayé de faire, mais une fois que je mets quelque chose dans le head comme tu me le montres, j'ai de nouveau une page blanche

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
  </head>
  <body>
<p>Un paragraphe.</p>
</body>
</html>

Prend celui-ci. Si tu as une page blanche, le problème sera ailleur.

Essaie de mettre dans une premier temps juste un paragraphe comme dans l'exemple.

Normalement tu devrais avoir quelque chose. Notemment le paragraphe.

essai effectué, page blanche

Ok tu peux montrer ton fichier.
Composer.json
controller
twig merci

hello Jessy Brs voici composer.json

{
    "type": "project",
    "license": "proprietary",
    "require": {
        "php": "^7.2.5",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "doctrine/annotations": "^1.0",
        "doctrine/doctrine-bundle": "^2.3",
        "doctrine/doctrine-migrations-bundle": "^3.2",
        "doctrine/orm": "^2.12",
        "dompdf/dompdf": "^2.0",
        "easycorp/easyadmin-bundle": "^3.5",
        "knplabs/knp-paginator-bundle": "*",
        "mailjet/mailjet-apiv3-php": "^1.5",
        "phpdocumentor/reflection-docblock": "^5.3",
        "sensio/framework-extra-bundle": "^5.1",
        "stripe/stripe-php": "^10.5",
        "symfony/asset": "5.0.*",
        "symfony/console": "5.0.*",
        "symfony/dotenv": "5.0.*",
        "symfony/expression-language": "5.0.*",
        "symfony/flex": "^1.3.1",
        "symfony/form": "5.0.*",
        "symfony/framework-bundle": "5.0.*",
        "symfony/google-mailer": "5.0.*",
        "symfony/http-client": "5.0.*",
        "symfony/intl": "5.0.*",
        "symfony/mailer": "5.0.*",
        "symfony/monolog-bundle": "^3.1",
        "symfony/notifier": "5.0.*",
        "symfony/process": "5.0.*",
        "symfony/property-access": "5.0.*",
        "symfony/property-info": "5.0.*",
        "symfony/proxy-manager-bridge": "5.0.*",
        "symfony/security-bundle": "5.0.*",
        "symfony/serializer": "5.0.*",
        "symfony/string": "5.0.*",
        "symfony/translation": "5.0.*",
        "symfony/twig-bundle": "5.0.*",
        "symfony/validator": "5.0.*",
        "symfony/web-link": "5.0.*",
        "symfony/yaml": "5.0.*",
        "symfonycasts/reset-password-bundle": "*",
        "symfonycasts/verify-email-bundle": "*",
        "twig/extra-bundle": "^2.12|^3.0",
        "twig/twig": "^2.12|^3.0"
    },
    "require-dev": {
        "phpunit/phpunit": "^9.5",
        "symfony/browser-kit": "5.0.*",
        "symfony/css-selector": "5.0.*",
        "symfony/debug-bundle": "5.0.*",
        "symfony/maker-bundle": "^1.0",
        "symfony/phpunit-bridge": "^6.0",
        "symfony/stopwatch": "5.0.*",
        "symfony/web-profiler-bundle": "5.0.*"
    },
    "config": {
        "preferred-install": {
            "*": "dist"
        },
        "sort-packages": true,
        "allow-plugins": {
            "symfony/flex": true
        }
    },
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    },
    "replace": {
        "paragonie/random_compat": "2.*",
        "symfony/polyfill-ctype": "*",
        "symfony/polyfill-iconv": "*",
        "symfony/polyfill-php72": "*",
        "symfony/polyfill-php71": "*",
        "symfony/polyfill-php70": "*",
        "symfony/polyfill-php56": "*"
    },
    "scripts": {
        "auto-scripts": {
            "cache:clear": "symfony-cmd",
            "assets:install %PUBLIC_DIR%": "symfony-cmd"
        },
        "post-install-cmd": [
            "@auto-scripts"
        ],
        "post-update-cmd": [
            "@auto-scripts"
        ]
    },
    "conflict": {
        "symfony/symfony": "*"
    },
    "extra": {
        "symfony": {
            "allow-contrib": false,
            "require": "5.0.*"
        }
    }
}

controller

<?php

namespace App\Controller;

use App\Entity\Order;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Dompdf\Dompdf;
use Dompdf\Options;

//require_once 'dompdf/dompdf/autoload.inc.php';

class AccountOrderController extends AbstractController
{
    private $entityManager;

    public function __construct(EntityManagerInterface $entityManager)
    {
        $this->entityManager = $entityManager;
    }
    /**
     * @Route("/compte/mes-commandes", name="account_order")
     */
    public function index(): Response
    {

        $orders = $this->entityManager->getRepository(Order::class)->findSuccessOrders($this->getUser());

        return $this->render('account/order.html.twig', [
            'controller_name' => 'AccountOrderController',
            'orders' => $orders
        ]);
    }

    /**
     * @Route("/compte/mes-commandes/{reference}", name="account_order_show")
     */
    public function show($reference): Response
    {

        $order = $this->entityManager->getRepository(Order::class)->findOneByReference($reference);

        if (!$order || $order->getUser() != $this->getUser()) {
            return $this->redirectToRoute('account_order');
        }

        return $this->render('account/order_show.html.twig', [
            'controller_name' => 'AccountOrderController',
            'order' => $order
        ]);
    }

    /**
     * @Route("/compte/ma-facture/{reference}", name="show_pdf")
     */
    public function facture($reference)
    {
        //require_once 'dompdf/autoload.inc.php';

        // Configure Dompdf according to your needs
        $pdfOptions = new Options();

        $pdfOptions->set('defaultFont', 'Arial');

        // Instantiate Dompdf with our options
        $dompdf = new Dompdf($pdfOptions);

        $order = $this->entityManager->getRepository(Order::class)->findOneByReference($reference);

        // Retrieve the HTML generated in our twig file
        $html = $this->renderView('account/facture.html.twig', [
            'order' => $order
        ]);

        // Load HTML to Dompdf
        $dompdf->loadHtml($html);

        // (Optional) Setup the paper size and orientation 'portrait' or 'portrait'
        $dompdf->setPaper('A4', 'landscape');

        // Render the HTML as PDF
        $dompdf->render();

        dump($dompdf);

        // Output the generated PDF to Browser (force download)
        $dompdf->stream("mafacture.pdf", [
            "Attachment" => true
        ]);
    }
}

et le twig

{# {% extends 'base.html.twig' %}
{% block title %}
    Ma commande - Le cercle des saveurs

{% endblock %}
{% block body %}#}
<html>
    <head></head>

    <body>
        <h3>Le Cercle des Saveurs</h3>
        <hr>
        <h4>
            Facture n°
            {{ order.reference }}
        </h4>
        <hr>
        <strong>
            Statut de la commande :
        </strong>
        {% if order.state == 1 %}
            Paiement accepté

        {% elseif order.state == 2 %}
            Préparation en cours

        {% elseif order.state == 3 %}
            Livraison en cours

        {% elseif order.state == 4 %}
            Livrée

        {% endif %}
        <strong>

            Commande passée le :</strong>
        {{ order.createdAt|date('d/m/Y') }}</body>
</html></br><strong>Référence de la commande :</strong><small>{{ order.reference }}</small></br><strong>Transporteur choisi :&nbsp;</strong>{{ order.carrierName }}<hr><strong>Détails :</strong><table class="table mt-4"><tr>
<th scope="col">
    Produit</th>
<th scope="col">
    Quantité</th>
<th scope="col">
    Prix unitaire</th>
<th scope="col">
    Total</th></tr></thead><tbody>{% for product in order.orderDetails %}
<tr>
    <td>
        {{ product.product }}
    </td>
    <td>
        x

        {{ product.quantity }}
    </td>
    <td>
        {{ (product.price / 100)|number_format(2, ',', '.') }}
        €
    </td>
    <td>
        {{ (product.total / 100)|number_format(2, ',', '.') }}
        €
    </td>
</tr>{% endfor %}</tbody></table><div class="text-right"><strong>Sous-total :</strong>{{ (order.getTotal / 100)|number_format(2, ',', '.') }}€</br><strong>Livraison :</strong>{{ (order.carrierPrice / 100)|number_format(2, ',', '.') }}€</br><strong>Total général :</strong>{{ ((order.carrierPrice + order.getTotal) / 100)|number_format(2, ',', '.') }}€</div>{# {% endblock %}#}</body></html>

Merci

Salut, il faudrait que tu retournes une réponses dans ton controller.

$dompdf->loadHtml($html);
$dompdf->render();
$dompdf->stream("mafacture.pdf", [
  "Attachment" => true
]);

return new Response('', 200, [
  'Content-Type' => 'application/pdf',
]);

Hello Jessy Brs,

Merci, ça fonctionne. Je n'ai plus qu'à faire la mise en page.
Encore un grand merci.

Laurent