Guia do desenvolvedor Laravel
Visão geral
Seção intitulada “Visão geral”O pacote Laravel adapta o NextPDF às convenções do Laravel sem alterar o ciclo de vida do documento no core. O container é responsável pelos registries e pelas factories compartilhados. Cada documento PDF é descartável; portanto, você deve construí-lo, retorná-lo, transmiti-lo ou salvá-lo uma única vez.
Use este guia ao projetar serviços de aplicação, jobs de fila, fluxos de resposta ou cobertura de testes para o nextpdf/laravel.
Limites da arquitetura
Seção intitulada “Limites da arquitetura”| Camada | Pertence a | Responsabilidade | Não coloque aqui |
|---|---|---|---|
| Controller | Aplicação | Autorizar a requisição, escolher um document builder e retornar uma resposta. | Regras de layout do PDF compartilhadas entre casos de uso. |
| Serviço de aplicação | Aplicação | Coletar dados de domínio e chamar o código de construção do documento. | Lógica de inicialização do container ou configuração do pacote. |
| Document builder | Aplicação | Traduzir dados de domínio em chamadas de documento do NextPDF. | Objetos de requisição, lógica de consultas do Eloquent ou detalhes de transporte da fila. |
| Integração com Laravel | nextpdf/laravel | Registrar factories, registries, signer, cliente TSA, facade, responses e queue job. | Caminhos de armazenamento específicos do negócio ou política de tenant. |
| Motor core | nextpdf/nextpdf | Construir e serializar o PDF. | Política de response, fila ou sistema de arquivos do Laravel. |
Ciclo de vida em tempo de execução
Seção intitulada “Ciclo de vida em tempo de execução”| Etapa | Comportamento | Ação do desenvolvedor |
|---|---|---|
| Registro do service provider | NextPdfServiceProvider::register() registra os registries compartilhados, a document factory, o document binding, o cliente HTTP, o cliente da autoridade de carimbo do tempo (TSA), o signer e os contratos opcionais de e-invoice. | Publique e revise o config/nextpdf.php antes da produção. |
| Resolução do documento | O facade Pdf e o binding PdfDocumentInterface resolvem um documento novo por meio do DocumentFactoryInterface. | Resolva um documento uma vez por requisição, comando ou job enfileirado. |
| Autoria | O código da aplicação chama as APIs de documento do core por meio do facade ou do documento injetado. | Mantenha a extração de dados de domínio fora do document builder. |
| Saída terminal | PdfResponse emite a saída HTTP, ou o documento é salvo em disco. | Escolha um único caminho de saída terminal por documento. |
| Execução na fila | GeneratePdfJob reconstrói o documento no worker e valida novamente o caminho de saída. | Passe contexto escalar e mantenha os callbacks idempotentes. |
Estrutura de aplicação recomendada
Seção intitulada “Estrutura de aplicação recomendada”| Caminho | Finalidade |
|---|---|
app/Pdf/Builders/* | Document builders puros. Eles recebem dados e retornam um documento completo. |
app/Pdf/Data/* | Pequenos objetos de transferência de dados (DTOs) que carregam entradas de documento já autorizadas. |
app/Services/* | Orquestração da aplicação, consultas, repasse de autorização e seleção do caminho de armazenamento. |
app/Jobs/* | Wrappers opcionais em torno do GeneratePdfJob quando a aplicação precisa de jobs nomeados. |
tests/Feature/Pdf/* | Testes de resposta HTTP, dispatch de fila e autorização. |
tests/Unit/Pdf/* | Testes de builder com entradas pequenas e determinísticas. |
Mantenha os builders independentes dos objetos de requisição do Laravel. Você deve conseguir chamar um builder a partir de um controller, comando, teste ou queue worker com a mesma entrada.
<?php
namespace App\Pdf\Builders;
use App\Pdf\Data\InvoicePdfData;use NextPDF\Contracts\PdfDocumentInterface;
final readonly class InvoicePdfBuilder{ public function build(PdfDocumentInterface $pdf, InvoicePdfData $data): PdfDocumentInterface { $pdf->setTitle($data->title) ->addPage() ->setFont('dejavusans', '', 12) ->writeHtml($data->html);
return $pdf; }}Padrão de resposta síncrona
Seção intitulada “Padrão de resposta síncrona”Use injeção via construtor quando o fluxo de PDF fizer parte da lógica da aplicação. Use o facade apenas em fluxos curtos de controller, em que o estilo estático é mais fácil de ler.
<?php
namespace App\Http\Controllers;
use App\Pdf\Builders\InvoicePdfBuilder;use App\Pdf\Data\InvoicePdfData;use NextPDF\Contracts\PdfDocumentInterface;use NextPDF\Laravel\Http\PdfResponse;
final readonly class DownloadInvoiceController{ public function __invoke( PdfDocumentInterface $pdf, InvoicePdfBuilder $builder, ) { $document = $builder->build( $pdf, InvoicePdfData::fromInvoiceId(1234), );
return PdfResponse::download($document, 'invoice-1234.pdf'); }}Os helpers de resposta materializam os bytes do documento antes de construir a resposta do Laravel. Eles são helpers de resposta, não renderizadores em segundo plano.
Padrão de fila
Seção intitulada “Padrão de fila”GeneratePdfJob aceita um callable de builder e um caminho de saída. O job valida caminhos inseguros em tempo de execução. O código da aplicação ainda deve escolher uma raiz de armazenamento segura para o tenant antes do dispatch.
<?php
use App\Pdf\Builders\QueuedInvoiceBuilder;use NextPDF\Laravel\Jobs\GeneratePdfJob;
GeneratePdfJob::dispatch( outputPath: storage_path('app/pdfs/invoice-1234.pdf'), builder: [QueuedInvoiceBuilder::class, 'build'],)->onQueue(config('nextpdf.queue.queue', 'pdf'));Mantenha os callbacks de fila pequenos. Prefira gravar estado durável a partir de um job listener da aplicação, em vez de armazenar closures complexas no payload da fila.
Pontos de extensão
Seção intitulada “Pontos de extensão”| Ponto de extensão | Use para | Restrição |
|---|---|---|
PdfDocumentInterface (binding) | Substituir ou decorar a criação de documentos para padrões que valem em toda a aplicação. | Deve retornar uma instância nova de documento. |
DocumentFactoryInterface | Criar documentos novos explicitamente em serviços e testes. | Não armazene em cache os documentos retornados. |
config/nextpdf.php | Padrões, configurações de fila, configurações do renderizador Chrome, hooks de assinatura, TSA e cache OCSP. | Trate as variáveis de ambiente como configuração de deployment, não como entrada de requisição. |
GeneratePdfJob (builder) | Construir documentos de forma assíncrona. | O callable deve ser serializável pelo transporte de fila do Laravel. |
| Callbacks de sucesso/falha | Notificação ou limpeza após a geração. | Mantenha os callbacks idempotentes e atentos a efeitos colaterais. |
| Contratos Premium opcionais | Embedder, validador, profile e runner Schematron de e-invoice. | Resolva apenas onde o pacote opcional está instalado e licenciado. |
Fluxo de trabalho de desenvolvimento
Seção intitulada “Fluxo de trabalho de desenvolvimento”- Construa o primeiro documento de forma síncrona em um controller ou feature test.
- Mova o código de layout para uma classe builder em
app/Pdf/Builders. - Mova a lógica de consultas e de autorização para um serviço de aplicação.
- Adicione testes de
PdfResponsepara cabeçalhos e nomes de arquivo. - Mova a geração lenta ou de alto volume para o
GeneratePdfJob. - Adicione testes de fila para contexto serializado, política de caminho de saída e tratamento de falhas.
- Meça o consumo de memória e o tempo de renderização com dados de produção representativos.
Tratamento de falhas
Seção intitulada “Tratamento de falhas”| Falha | Onde deve ser tratada | Resposta recomendada |
|---|---|---|
| Requisição inválida ou documento não autorizado | Controller ou policy. | Retorne a resposta normal de autorização ou validação da aplicação. |
| Fonte ausente ou imagem inválida | Teste de builder e logging da aplicação. | Faça a requisição ou o job falhar; não emita PDFs parciais. |
| Caminho de saída inseguro | Serviço de armazenamento da aplicação e GeneratePdfJob. | Rejeite antes do dispatch e conte com a validação no lado do worker como defesa em profundidade. |
| Falha de assinatura ou de TSA | Fronteira do serviço de assinatura. | Decida se o documento pode ficar sem assinatura; por padrão, falhe de forma fechada (fail closed) para documentos regulados. |
| Timeout da fila | Configuração e observabilidade do queue worker. | Reexecute apenas quando o builder for determinístico e o caminho de saída for seguro de sobrescrever. |
Padrões seguros
Seção intitulada “Padrões seguros”| Aspecto | Padrão | Quando substituir |
|---|---|---|
| Nome da fila | pdf | Use uma fila dedicada quando a geração concorrer com jobs voltados ao usuário. |
| Timeout do job | 120 segundos | Aumente somente após medir o tamanho do documento e a capacidade do worker. |
| Nome do arquivo de resposta | document.pdf | Use identificadores de negócio sanitizados. |
| Registry de fontes | Compartilhado e bloqueado após o warmup. | Adicione preload_fonts para fontes usadas em hot paths. |
| Registry de imagens | Cache compartilhado e limitado. | Reduza image_cache_mb para workers com pouca memória. |
| Fragmentação da resposta transmitida | Chunks de 64 KB. | Não dependa dos limites dos chunks; eles são um detalhe de saída. |
Checklist de testes
Seção intitulada “Checklist de testes”- Os testes de controller verificam
Content-Type,Content-Dispositione cabeçalhos defensivos. - Os testes de builder usam DTOs determinísticos e não consultam o banco de dados.
- Os testes de fila verificam se o builder recebe um documento novo.
- Os testes de caminho cobrem traversal, stream-wrapper, null-byte e rejeição de arquivos que não sejam
.pdf. - Os testes de worker renderizam documentos representativos sob o mesmo limite de memória que a produção.
- Os testes opcionais de assinatura cobrem certificado ausente, senha inválida, TSA indisponível e nível de assinatura configurado.