Перейти к содержимому

Быстрый старт с NextPDF для Symfony

Внедрите PdfFactory, создайте Document и верните его через PdfResponse. Если нужно формирование в фоне, отправьте GeneratePdfMessage в транспорт Messenger.

Внедрите NextPDF\Symfony\Service\PdfFactory. Метод create() возвращает новый NextPDF\Core\Document. Он применяет заданные вами значения по умолчанию для приложения-создателя, автора и языка. Верните документ через NextPDF\Symfony\Http\PdfResponse.

src/Controller/InvoiceController.php
<?php
declare(strict_types=1);
namespace App\Controller;
use NextPDF\Symfony\Http\PdfResponse;
use NextPDF\Symfony\Service\PdfFactory;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;
final class InvoiceController
{
#[Route('/invoice/{number}', name: 'invoice_pdf')]
public function download(PdfFactory $pdf, string $number): Response
{
$doc = $pdf->create();
$doc->addPage();
$doc->cell(0, 10, "Invoice #{$number}", newLine: true);
$doc->cell(0, 10, 'Thank you for your business.');
return PdfResponse::download($doc, "invoice-{$number}.pdf");
}
}

PdfResponse::download() возвращает Symfony\Component\HttpFoundation\Response. Он задаёт Content-Type: application/pdf, заголовок Content-Disposition со значением attachment, Content-Length, а также фиксированные заголовки безопасности бандла. Стандартный класс Response и модель его заголовков описаны в документации Symfony (https://symfony.com/doc/current/components/http_foundation.html).

Используйте inline(), если браузер должен показать PDF, а не загрузить его:

return PdfResponse::inline($doc, 'preview.pdf');

Заголовок Content-Disposition получает значение inline. Все остальные заголовки остаются прежними.

Для больших документов используйте потоковые методы. Они отдают PDF фрагментами по 64 KB, что снижает пиковое потребление памяти. Эти методы возвращают Symfony\Component\HttpFoundation\StreamedResponse и не задают Content-Length.

return PdfResponse::streamDownload($doc, 'annual-report.pdf');

Для потоковой передачи в браузере используйте streamInline(). В документации Symfony описан контракт обратного вызова StreamedResponse: это вызываемый объект, возвращающий void и сбрасывающий вывод (https://symfony.com/doc/current/components/http_foundation.html).

Если установлен symfony/messenger, вы можете вынести формирование за пределы обработки запроса.

Реализуйте NextPDF\Symfony\Message\PdfBuilderInterface. Обработчик передаёт вам новый, предварительно настроенный Document и сериализуемый контекст из сообщения.

src/Pdf/InvoicePdfBuilder.php
<?php
declare(strict_types=1);
namespace App\Pdf;
use NextPDF\Core\Document;
use NextPDF\Symfony\Message\PdfBuilderInterface;
final class InvoicePdfBuilder implements PdfBuilderInterface
{
public function build(Document $document, array $context): Document
{
$document->addPage();
$document->setFont('dejavusans', '', 12);
$document->cell(0, 10, 'Invoice #' . $context['invoice_id']);
return $document;
}
}

Обработчик получает сборщики из локатора служб PHP Standard Recommendation 11 (PSR-11), где ключом служит имя класса. Доступны только зарегистрированные сборщики. Добавьте сборщик в локатор в файле config/services.yaml:

services:
App\Pdf\InvoicePdfBuilder: ~
nextpdf.pdf_builder_locator:
class: Symfony\Component\DependencyInjection\ServiceLocator
arguments:
- 'App\Pdf\InvoicePdfBuilder': '@App\Pdf\InvoicePdfBuilder'
tags: ['container.service_locator']
NextPDF\Symfony\Message\GeneratePdfHandler:
arguments:
$builderLocator: '@nextpdf.pdf_builder_locator'

Обработчик запрашивает у локатора сборщик по идентификатору class-string. В PSR-11 идентификатор контейнера — это строка, которая однозначно идентифицирует запись (PSR-11 §1.1.2).

Внедрите Symfony\Component\Messenger\MessageBusInterface, затем отправьте сообщение:

src/Controller/ReportController.php
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Pdf\InvoicePdfBuilder;
use NextPDF\Symfony\Message\GeneratePdfMessage;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Routing\Attribute\Route;
final class ReportController
{
#[Route('/invoice/{id}/queue', name: 'invoice_queue')]
public function queue(MessageBusInterface $bus, int $id): Response
{
$bus->dispatch(new GeneratePdfMessage(
builderClass: InvoicePdfBuilder::class,
outputPath: '/var/storage/invoices/' . $id . '.pdf',
builderContext: ['invoice_id' => $id],
));
return new Response('PDF generation queued.', 202);
}
}

GeneratePdfMessage — это объект передачи данных (DTO) с модификатором readonly. Его конструктор отклоняет пути вывода, которые пусты, не заканчиваются на .pdf, содержат сегменты обхода каталогов, используют схемы stream-wrapper или содержат нулевые байты. Кроме того, он требует, чтобы builderClass был синтаксически корректным именем класса. Обработчик повторно проверяет путь вывода во время выполнения перед записью. Если путь безопасен при отправке, но небезопасен в момент обработки, обработчик всё равно отклоняет его. Атрибут #[AsMessageHandler] и контракт отправки MessageBusInterface следуют стандартной модели Symfony Messenger (https://symfony.com/doc/current/messenger.html).

4d — маршрутизация сообщения и запуск воркера

Заголовок раздела «4d — маршрутизация сообщения и запуск воркера»

В файле config/packages/messenger.yaml направьте сообщение в транспорт:

framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
NextPDF\Symfony\Message\GeneratePdfMessage: async

Затем запустите воркер:

Окно терминала
php bin/console messenger:consume async
Окно терминала
php bin/console debug:container --tag=container.service_locator
php bin/console messenger:consume async --limit=1 -vv

Первая команда подтверждает, что локатор сборщиков зарегистрирован. Вторая команда обрабатывает одно сообщение из очереди и показывает ход выполнения обработчика.

  • /integrations/symfony/configuration/ — настройте значения по умолчанию, шрифты и службу документов.
  • /integrations/symfony/production-usage/ — ознакомьтесь с безопасностью воркеров и потоковой передачей под нагрузкой.
  • /integrations/symfony/troubleshooting/ — устраните типичные проблемы запуска и выполнения.

Каждая строка представляет нормативное утверждение с этой страницы, привязанное к полному 64-значному шестнадцатеричному reference_id из закрытого корпуса организации по разработке стандартов (SDO). _sidecars/rag-citations.yaml содержит сведения о происхождении, включая манифест корпуса и транспорт получения данных.

СпецификацияПунктreference_id (идентификатор ссылки)Утверждение
PSR-11psr_11_container#1.1.2.p4Контракт идентификатора has()/get() контейнера
  • /integrations/symfony/overview/ — ознакомьтесь со сводкой возможностей.
  • /integrations/symfony/install/ — установите и зарегистрируйте бандл.
  • /integrations/symfony/integration/ — ознакомьтесь со сквозным справочником по интеграции.