콘텐츠로 이동

NextPDF Symfony 빠른 시작

여기서는 PdfFactory를 주입하고 Document를 빌드한 다음 PdfResponse로 반환합니다. 백그라운드에서 PDF를 생성하려면 GeneratePdfMessage를 Messenger 전송으로 디스패치합니다.

1 단계 — 컨트롤러에서 PDF 생성

섹션 제목: “1 단계 — 컨트롤러에서 PDF 생성”

먼저 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, attachment disposition, Content-Length와 번들의 고정 보안 헤더가 포함됩니다. Symfony는 표준 Response 클래스와 그 헤더 모델을 문서화합니다(https://symfony.com/doc/current/components/http_foundation.html).

2 단계 — PDF 를 인라인으로 표시

섹션 제목: “2 단계 — PDF 를 인라인으로 표시”

브라우저가 PDF를 다운로드하지 않고 표시하게 하려면 inline()을 사용합니다:

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

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;
}
}

핸들러는 클래스 이름을 키로 사용하는 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'

핸들러는 로케이터에 클래스 문자열 ID로 빌더를 요청합니다. 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);
}
}

GeneratePdfMessagereadonly DTO입니다. 생성자는 비어 있거나 .pdf가 아닌 출력 경로, 경로 탐색 세그먼트, 스트림 래퍼 스킴, 널 바이트를 거부합니다. 또한 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

그런 다음 워커를 실행합니다:

Terminal window
php bin/console messenger:consume async
Terminal window
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/ — 일반적인 부팅 및 런타임 문제 해결.

각 행은 이 페이지에서 제시하는 규범적 주장을 나타내며, 게이트된 SDO 코퍼스의 전체 64자리 16진수 reference_id에 고정되어 있습니다. 출처(코퍼스 매니페스트, 검색 전송)는 _sidecars/rag-citations.yaml에 있습니다.

사양조항reference_id (참조 ID)주장
PSR-11psr_11_container#1.1.2.p4컨테이너 has()/get() 식별자 계약
  • /integrations/symfony/overview/ — 기능 요약.
  • /integrations/symfony/install/ — 설치 및 등록.
  • /integrations/symfony/integration/ — 엔드투엔드 연결 참조.