Pular para o conteúdo

Migre uma base de código TCPDF 6.x para o NextPDF

O pacote nextpdf/compat-legacy expõe os nomes de métodos públicos, a ordem dos parâmetros e os valores padrão do TCPDF 6.x sobre o motor do core do NextPDF por meio do adaptador NextPDF\Compat\Tcpdf\TCPDF. Siga esta ordem de migração: troque para o motor com a menor alteração possível, comprove o que já funciona, ative o modo estrito para encontrar o que ainda não funciona, corrija os pontos de chamada um de cada vez e, depois, aposente o adaptador e use a API moderna. O adaptador apoia a migração; ele não é o destino.

Pré-requisitos antes de começar:

  • O core do NextPDF e o nextpdf/compat-legacy estão instalados.
  • Você tem uma base de código TCPDF 6.x existente com uma suíte de testes. A suíte é a rede de segurança para cada etapa abaixo.

Este é um guia prático. Para entender o comportamento de cada método em uma chamada TCPDF, leia a página de cobertura de métodos. Para a estratégia completa arquivo por arquivo, com código, leia a página de migração upstream. Os dois links estão na seção Veja também.

Instale o adaptador junto com o core. Não remova ainda a biblioteca TCPDF real — manter as duas permite comparar a saída durante a migração.

Terminal window
composer require nextpdf/compat-legacy

Antes de alterar qualquer código, confirme que o vínculo com o motor é resolvido (nextpdf/core ^3.0) e que a suíte ainda executa.

O adaptador é uma camada de compatibilidade, não um fork do TCPDF nem um clone byte-idêntico. Dos cerca de 120 métodos públicos do TCPDF 6.x analisados, aproximadamente 94 mapeiam diretamente para uma operação de NextPDF\Core\Document e se comportam de forma compatível para os parâmetros documentados. Uma minoria define ou aceita parâmetros legados que o motor não respeita (ignorados silenciosamente), ou não produz saída alguma (não implementados ou não aplicáveis). A matriz de cobertura oficial, verificada por testes, está no repositório do pacote em docs/TCPDF_COVERAGE.md. Se este guia e essa matriz divergirem, a matriz prevalece.

Dois fatos moldam toda a migração:

  • Os bytes de saída diferem. O motor é uma implementação independente de PDF 2.0, portanto os bytes renderizados diferem da saída do TCPDF mesmo quando o resultado visível parece igual. Testes que verificam os bytes exatos do PDF precisam ter sua linha de base refeita com base no conteúdo renderizado ou em propriedades estruturais.
  • O modo estrito é a sua ferramenta de auditoria. Com o modo estrito desativado (o padrão), os métodos que não conseguem reproduzir o comportamento do TCPDF degradam silenciosamente. Com o modo estrito ativado, essas chamadas lançam TcpdfNotImplementedException, informando exatamente os parâmetros ignorados e uma dica de migração. Execute o modo estrito em uma passagem de auditoria dedicada, nunca em produção.

O adaptador também expõe o documento do motor que ele encapsula por meio de getDocument(), que retorna o NextPDF\Core\Document. Use isso como o caminho de saída: migre os pontos de chamada para a API moderna um de cada vez até poder remover o adaptador.

TópicoSuperfície
Construirnew NextPDF\Compat\Tcpdf\TCPDF('P', 'mm', 'A4')
Aliases globais opcionaisNextPDF\Compat\Tcpdf\LegacyBootstrap::enableAliases()
Ativar a auditoriaTCPDF::setStrictMode(true)
Exceção de auditoriaNextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException
Saída de emergência para a API modernaTCPDF::getDocument(): NextPDF\Core\Document
SaídaTCPDF::Output(string $name, string $dest)S, F, E, I, D

LegacyBootstrap::enableAliases() é idempotente. Ela registra \TCPDF, \TCPDF_STATIC, \TCPDF_FONTS, \TCPDF_COLORS e \TCPDF_IMAGES apenas quando essas classes ainda não existem. As páginas de cobertura de métodos e de início rápido vinculadas em Veja também cobrem o comportamento completo de cada método e os destinos de saída.

Altere o import, mantenha as chamadas no estilo TCPDF e gere um PDF.

quickstart-first.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF('P', 'mm', 'A4');
$pdf->SetCreator('Quickstart');
$pdf->SetTitle('First Document');
$pdf->SetFont('helvetica', '', 12);
$pdf->AddPage();
$pdf->Cell(0, 10, 'Hello from the NextPDF engine', 1, 1, 'C');
$pdf->Output(__DIR__ . '/quickstart.pdf', 'F');

Output($name, 'F') grava o arquivo e retorna uma string vazia. Diferentemente do TCPDF legado, o Output() do adaptador não escreve no buffer de saída ativo, então você pode chamá-lo com segurança dentro de um worker de fila ou de um handler HTTP que controla a própria resposta.

Quando você não pode alterar pontos de chamada que instanciam new \TCPDF(...) no namespace global, ative os aliases opcionais uma vez na inicialização.

quickstart-alias.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\LegacyBootstrap;
LegacyBootstrap::enableAliases();
// Legacy code now resolves \TCPDF to the adapter:
$pdf = new \TCPDF('P', 'mm', 'A4');
$pdf->AddPage();
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Legacy call site, modern engine');
$pdf->Output(__DIR__ . '/aliased.pdf', 'F');

Não ative aliases enquanto a biblioteca TCPDF real ainda puder ser carregada por autoload. O alias é ignorado quando uma classe \TCPDF já existe, então você pode continuar usando o TCPDF legado sem perceber. Durante a migração, prefira imports por arquivo.

A etapa segura da migração é a auditoria em modo estrito. Execute um fluxo de produção representativo, ou a suíte, com o modo estrito ativado, e colete cada TcpdfNotImplementedException. Cada exceção é um item de trabalho: ela informa o método, os parâmetros ignorados e uma dica.

migration-audit.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\Exception\TcpdfNotImplementedException;
use NextPDF\Compat\Tcpdf\TCPDF;
function renderInvoice(TCPDF $pdf): void
{
// ... your existing rendering code, unchanged ...
}
$pdf = new TCPDF('P', 'mm', 'A4');
$pdf->setStrictMode(true);
try {
renderInvoice($pdf);
$pdf->Output(__DIR__ . '/audit.pdf', 'F');
} catch (TcpdfNotImplementedException $exception) {
// Each message names the method, the ignored parameters, and a hint.
fwrite(STDERR, 'MIGRATION GAP: ' . $exception->getMessage() . "\n");
}

Para cada lacuna, escolha a correção correta de menor custo: descarte um parâmetro do qual você nunca dependeu, ou expresse a intenção por meio da API moderna via getDocument(). A saída de emergência lida com tudo o que a superfície do TCPDF não consegue expressar.

migration-escape-hatch.php
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use NextPDF\Compat\Tcpdf\TCPDF;
$pdf = new TCPDF();
$pdf->AddPage();
// Legacy path stays for the parts that already work:
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here —
// for example a clickable image (the legacy Image() link parameter
// is one of the silently ignored parameters):
$document = $pdf->getDocument();
$document->image('logo.png', 10, 30, 40, 0);
$document->link(10, 30, 40, 20, 'https://example.com');

Execute o modo estrito como um job dedicado de integração contínua (CI) e, em seguida, desative-o e implante o caminho de código auditado. Mantenha um job de CI periódico em modo estrito para capturar regressões à medida que você refatora.

  • MultiCell() retorna 1, Write() retorna 0. Esses são marcadores de compatibilidade, não valores calculados. Ajuste qualquer código que desvie o fluxo com base nesses valores de retorno.
  • Error() lança uma exceção em vez de chamar die(). O adaptador lança RuntimeException. Código que depende do encerramento do processo deve capturar a exceção.
  • Parâmetros ignorados silenciosamente. Métodos como Image(), writeHTML(), SetProtection() e Bookmark() aceitam parâmetros legados que são ignorados. Use o modo estrito para encontrá-los. Para uma imagem clicável, desenhe a imagem e, em seguida, adicione Document::link() sobre o mesmo retângulo.
  • Métodos não implementados. setSignature(), addEmptySignatureAppearance() e endPage() são no-ops que lançam exceção no modo estrito; Open() é um no-op seguro que nunca lança exceção. Remova endPage() e Open(). A assinatura requer uma edição comercial do NextPDF por meio da API de assinatura moderna.
  • A versão do PDF é fixa. setPDFVersion() não pode mirar uma versão mais antiga do PDF; a saída é sempre PDF 2.0. setUserRights() está obsoleto no PDF 2.0 e é ignorado com um aviso.
  • Conflito de alias. Se algo ainda for resolvido para a classe TCPDF real depois de você remover tecnickcom/tcpdf, a ressalva do alias se aplica — importe o adaptador explicitamente nesses pontos de chamada.

O adaptador delega ao motor; o custo de construção do documento escala com o conteúdo, não com a camada do adaptador. Como o Output() do adaptador não escreve no buffer de saída, ele é seguro dentro de um worker de fila — mova a geração pesada no estilo TCPDF para fora da thread da requisição da mesma forma que você moveria qualquer geração do NextPDF. Refazer a linha de base de testes em nível de bytes com base no conteúdo renderizado é um custo único, e oferece a você testes que sobrevivem a futuras atualizações do motor.

  • Criptografia. SetProtection() ignora os parâmetros legados mode e pubkeys; o motor usa AES-256 para o handler padrão. Para criptografia baseada em certificado, use o ponto de entrada moderno de criptografia de chave pública exposto no adaptador, não os parâmetros legados.
  • A assinatura é restrita. O suporte a assinatura baseline é uma capacidade da edição comercial alcançada por meio da API de assinatura moderna com um objeto de valor de certificado; o setSignature() legado é um no-op. Este guia não faz afirmações sobre perfis de assinatura com validação de longo prazo ou com carimbo de tempo para nenhuma edição.
  • Falhe explicitamente durante a auditoria. O modo estrito torna visível a perda silenciosa de parâmetros, de modo que você saiba quando o adaptador não respeitou a intenção de quem chamou. Trate as exceções coletadas como a lista de trabalho da migração, não como comportamento de produção.
  • Nunca escreva um bloco catch vazio. O exemplo de auditoria captura TcpdfNotImplementedException e escreve uma linha bem definida para o item de trabalho.

A postura completa de criptografia e assinatura durante a migração está na página de segurança e operações do compat-legacy.

Este guia não faz nenhuma afirmação normativa de padrões por conta própria. O adaptador gera saída em PDF 2.0 (ISO 32000-2) e não pode mirar uma versão mais antiga. Esse comportamento e sua cláusula estão fixados na página de cobertura de métodos upstream, que também registra o princípio OWASP de falhar explicitamente por trás do modo estrito e o enquadramento de completude funcional da ISO/IEC 25023 da auditoria de cobertura. Esta página do cookbook reafirma o uso e remete essas citações à página upstream.