Показать PDF через вызов AJAX к API Symfony с помощью dompdf или wkhtmltopdf

Недавно мне пришлось разработать веб-сайт с Symfony и React. Одна из функций, которую я должен был сделать, заключалась в том, чтобы сгенерировать PDF-файл с помощью Symfony и вернуть его на передний план. Я нашел много руководств по dompdf или wkhtmltopdf для symfony, но ничего о том, как справиться с тем фактом, что мой фронт был не Twig, а React!

С ДомПДФ

Сначала я попробовал domPDF, очень хорошую библиотеку, если вы хотите быстро создать PDF.

Следуйте инструкциям в их гитхабе, чтобы установить его так, как вы хотите.

Тогда вот пример создания PDF-файла, который вы уже могли найти в других учебниках:

$domPdf = new Dompdf();
$html = $this->renderView('pdf/my_pdf.html.twig');
$domPdf->loadHtml($html);
$domPdf->setPaper('A4', 'portrait');
$domPdf->render();
$domPdf->stream('my-pdf.pdf');

Stream создаст ответ, который будет использоваться внешним интерфейсом. Например, в JS после вызова API вы будете использовать ответ PDF:

apiCallToYourRoute.then((res) => {
 if (res.data) {
  const newBlob = new Blob([res.data], { type: 'application/pdf' });
  const downloadUrl = window.URL.createObjectURL(newBlob);
  window.open(downloadUrl);
 }
});

Если вы сделаете это, вы увидите PDF-файл, открывающийся в вашем браузере с… белой страницей :(

Вам просто нужно изменить одну вещь из предыдущего кода php:

$domPdf->stream('transport.pdf', [
    'compress' => false,
]);

С wkhtmltopdf

Моя вторая попытка была с wkhtmltopdf, потому что dompdf было недостаточно для того, что я хотел сделать. Например, мне нужно было использовать некоторые функции CSS 3.0. Я позволю вам провести небольшое исследование, вы найдете много плюсов и минусов в этих обеих библиотеках.

Вы можете использовать knpSnappyBundle или KnpSnappyбинарником). Я использовал второй метод, но не стесняйтесь делать, как хотите.

$pdf = new Pdf($rootPath.'/vendor/h4cc/wkhtmltopdf-amd64/bin/wkhtmltopdf-amd64');
$html = $this->renderView('pdf/my_pdf.html.twig');

$pdf->getOutputFromHtml($html);
return new Response(
    $pdf->getOutputFromHtml($html),
    200,
    array(
        'Content-Type' => 'application/pdf',
        'Content-Disposition' => 'inline; filename="my-pdf.pdf"',
    )
);

И снова у вас будет ответ, который используется интерфейсом. Тот же пример кода js:

apiCallToYourRoute.then((res) => {
  if (res.data) {
  const newBlob = new Blob([res.data], { type: 'application/pdf' });
  const downloadUrl = window.URL.createObjectURL(newBlob);
  window.open(downloadUrl);
 }
});

Еще раз PDF-файл будет открыт в вашем браузере с … снова белой страницей!

Как и в случае с dompdf, вам нужно добавить небольшую опцию, чтобы библиотека не сжимала возвращаемый PDF:

$this->pdf->setOptions([
  'no-pdf-compression' => true,
]);

Надеюсь, это поможет вам, и не стесняйтесь комментировать и помогать друг другу!