Guía de inicio rápido de NextPDF para Symfony
De un vistazo
Sección titulada «De un vistazo»El flujo consiste en inyectar PdfFactory, construir un Document y devolverlo mediante PdfResponse. Para generar un PDF en segundo plano, se despacha un GeneratePdfMessage a un transporte de Messenger.
Paso 1 — Generar un PDF en un controlador
Sección titulada «Paso 1 — Generar un PDF en un controlador»Se inyecta NextPDF\Symfony\Service\PdfFactory. Su método create() devuelve un NextPDF\Core\Document nuevo. Los valores predeterminados configurados ya se aplican automáticamente: el creador, el autor y el idioma. Ese documento se devuelve mediante NextPDF\Symfony\Http\PdfResponse.
<?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() devuelve una Symfony\Component\HttpFoundation\Response. Incluye Content-Type: application/pdf, una disposición attachment, un Content-Length y los encabezados de seguridad fijos del bundle. Symfony documenta la clase canónica Response y su modelo de encabezados (https://symfony.com/doc/current/components/http_foundation.html).
Paso 2 — Mostrar un PDF en línea
Sección titulada «Paso 2 — Mostrar un PDF en línea»Para que el navegador muestre el PDF en lugar de descargarlo, usar inline():
return PdfResponse::inline($doc, 'preview.pdf');La disposición pasa a ser inline. El resto de los encabezados se mantiene igual.
Paso 3 — Transmitir un PDF grande
Sección titulada «Paso 3 — Transmitir un PDF grande»Para documentos grandes, las variantes de transmisión emiten el PDF en fragmentos de 64 KB. Esto reduce el uso máximo de memoria. Devuelven una Symfony\Component\HttpFoundation\StreamedResponse y omiten Content-Length.
return PdfResponse::streamDownload($doc, 'annual-report.pdf');streamInline() es el equivalente en línea. Symfony documenta el contrato del callback de StreamedResponse: un callable void que escribe la salida (https://symfony.com/doc/current/components/http_foundation.html).
Paso 4 — Generar un PDF de forma asíncrona
Sección titulada «Paso 4 — Generar un PDF de forma asíncrona»Cuando symfony/messenger está instalado, se puede trasladar la generación fuera del hilo de la solicitud.
4a — Implementar un builder
Sección titulada «4a — Implementar un builder»Implementar NextPDF\Symfony\Message\PdfBuilderInterface. El handler pasa al builder un Document nuevo y preconfigurado. También le pasa el contexto serializable del mensaje.
<?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; }}4b — Registrar el builder en el localizador
Sección titulada «4b — Registrar el builder en el localizador»El handler resuelve los builders desde un localizador de servicios PSR-11 indexado por nombre de clase. Por eso, solo son accesibles los builders registrados. Agregar el builder a un localizador en 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'El handler solicita al localizador el builder por su id de tipo class-string. Un identificador de contenedor PSR-11 es una cadena que identifica de forma única una entrada (PSR-11 §1.1.2).
4c — Despachar el mensaje
Sección titulada «4c — Despachar el mensaje»Se inyecta Symfony\Component\Messenger\MessageBusInterface y luego se despacha el mensaje:
<?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 es un DTO readonly. Su constructor rechaza rutas de salida vacías o que no sean .pdf, segmentos de path-traversal, esquemas de stream-wrapper y bytes nulos. También exige que builderClass sea un nombre de clase sintácticamente válido. El handler vuelve a validar la ruta de salida en tiempo de ejecución, antes de escribir. Así, una ruta que era segura al despacharse, pero insegura al consumirse, se sigue rechazando. El atributo #[AsMessageHandler] y el contrato de despacho de MessageBusInterface siguen el modelo estándar de Symfony Messenger (https://symfony.com/doc/current/messenger.html).
4d — Enrutar el mensaje y ejecutar un worker
Sección titulada «4d — Enrutar el mensaje y ejecutar un worker»En config/packages/messenger.yaml, enrutar el mensaje a un transporte:
framework: messenger: transports: async: '%env(MESSENGER_TRANSPORT_DSN)%' routing: NextPDF\Symfony\Message\GeneratePdfMessage: asyncLuego ejecutar un worker:
php bin/console messenger:consume asyncVerificar que funciona
Sección titulada «Verificar que funciona»php bin/console debug:container --tag=container.service_locatorphp bin/console messenger:consume async --limit=1 -vvEl primer comando confirma que el localizador de builders está registrado. El segundo comando consume un único mensaje de la cola e imprime el progreso del handler.
Próximos pasos
Sección titulada «Próximos pasos»- /integrations/symfony/configuration/ — ajustar los valores predeterminados, las fuentes y el servicio de documentos.
- /integrations/symfony/production-usage/ — seguridad del worker y transmisión bajo carga.
- /integrations/symfony/troubleshooting/ — problemas comunes de arranque y de tiempo de ejecución.
Conformidad
Sección titulada «Conformidad»Cada fila es una afirmación normativa hecha en esta página, fijada a un reference_id completo de 64 caracteres hexadecimales del corpus SDO restringido. La procedencia (manifiesto del corpus, transporte de recuperación) está en _sidecars/rag-citations.yaml.
| Especificación | Cláusula | reference_id | Afirmación |
|---|---|---|---|
| PSR-11 | psr_11_container#1.1.2.p4 | Contrato de identificador del contenedor has()/get() |
Consulta también
Sección titulada «Consulta también»- /integrations/symfony/overview/ — resumen de capacidades.
- /integrations/symfony/install/ — instalación y registro.
- /integrations/symfony/integration/ — referencia de cableado de extremo a extremo.