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

Переход с TCPDF 6.x на NextPDF

Переходите в чёткой последовательности. Сначала переведите проект на движок NextPDF с минимально возможными изменениями. Зафиксируйте, что уже работает. Проверьте, что не работает. Исправьте каждое место вызова. Затем удалите адаптер. Слой совместимости поддерживает этапы со второго по четвёртый; он не является конечной целью.

На этой странице описана стратегия. Точное поведение конкретного метода смотрите в /integrations/tcpdf-compat/method-coverage/ и в авторитетной матрице репозитория docs/TCPDF_COVERAGE.md.

TCPDF 6.x codebase

Swap dependency: install compat-legacy

Run existing suite unchanged

Strict-mode audit: enumerate behavioral gaps

Fix call sites: drop ignored params or move to modern API

Re-baseline byte-level test assertions

Remove the TCPDF dependency

Incrementally retire the adapter onto Document

Diagram

На каждом этапе приложение остаётся готовым к выпуску. Полный одномоментный переход никогда не требуется.

Установите nextpdf/compat-legacy (см. /integrations/tcpdf-compat/install/). Пока не удаляйте tecnickcom/tcpdf: наличие обоих пакетов позволяет сравнивать результаты.

Выберите, как унаследованные места вызова должны разрешать класс:

  • Предпочтительно: в каждом файле замените текущий use/require на use NextPDF\Compat\Tcpdf\TCPDF;. Это явный подход, его легко найти поиском.
  • Если пока нельзя изменять места вызова: один раз при загрузке включите необязательные глобальные псевдонимы с помощью LegacyBootstrap::enableAliases() (см. /integrations/tcpdf-compat/boot-and-discovery/). При этом \TCPDF и четыре вспомогательных класса будут разрешаться как классы адаптера.

На практике эти две стратегии взаимоисключающи. Если реальная библиотека TCPDF остаётся доступной для автозагрузки и вы включаете глобальные псевдонимы, псевдоним не создаётся, если класс \TCPDF уже существует. В таком случае вы можете незаметно продолжить использовать устаревший TCPDF. На этапе 1 отдавайте предпочтение импортам в отдельных файлах, чтобы точно знать, какой класс использует каждое место вызова. См. /integrations/tcpdf-compat/troubleshooting/.

Этап 2 — запуск существующего набора тестов без изменений

Заголовок раздела «Этап 2 — запуск существующего набора тестов без изменений»

Запустите полный набор тестов с адаптером, не меняя ничего другого. Большинство делегированных методов (94 из ~120 рассмотренных) ведут себя совместимо. Ожидайте два предсказуемых типа сбоев:

  1. Проверки на уровне байтов. Тесты, которые сравнивают точные байты формата Portable Document Format (PDF), завершатся неудачей, поскольку движок — независимая реализация. Это ожидаемо и не является дефектом. Отложите их до этапа 4.
  2. Ветвление по возвращаемым значениям. Некоторые методы возвращают совместимые заглушки вместо вычисленных значений. В частности, MultiCell() возвращает 1, а Write()0. Код, который ветвится по этим возвращаемым значениям, нужно скорректировать.

Занесите каждый сбой в каталог. Классифицируйте его как байтовый эталон, возвращаемое значение или настоящий пробел в поведении.

Этот этап делает переход безопасным. Запустите набор тестов или репрезентативный рабочий сценарий с включённым строгим режимом:

examples/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 $e) {
// Each message names the method, the ignored parameters, and a hint.
fwrite(STDERR, 'MIGRATION GAP: ' . $e->getMessage() . "\n");
}

Рассматривайте каждое исключение TcpdfNotImplementedException как отдельную задачу. Сообщение указывает метод, точный список игнорируемых параметров и подсказку по переходу. Методы, которые выбрасывают исключения, перечислены и проверены тестами в tests/Unit/Compat/Tcpdf/TcpdfStrictModeTest.php. Обоснование каждого случая приведено в docs/TCPDF_COVERAGE.md.

Запускайте строгий режим как отдельную задачу непрерывной интеграции (CI), а не в производственной среде. Цель — выявить пробелы, а не заставить производственную среду выбрасывать исключения.

Для каждого пробела выбирайте самое простое корректное исправление:

Тип пробелаИсправление
Игнорируемый параметр не имеет значения (например, параметр $align в TCPDF, на который вы никогда не полагались)Удалите параметр. Вызов становится совместимым (не byte-identical).
Игнорируемый параметр имел значение (например, кликабельная ссылка Image())Перепишите участок с помощью современного API. Нарисуйте изображение, затем добавьте Document::link() поверх прямоугольника.
Метод не реализован (setSignature(), endPage())endPage() / Open(): удалите вызов. Подписание: см. /integrations/tcpdf-compat/security-and-operations/; для него требуется коммерческая редакция.
Неприменимый метод (setPDFVersion(), setUserRights())Удалите вызов. Вывод всегда соответствует PDF 2.0; права пользователя считаются устаревшими в PDF 2.0.
Ветвление по возвращаемому значениюВычислите значение самостоятельно или перенесите эту логику в современный API.

Используйте обходной путь, когда интерфейс TCPDF не позволяет выразить нужное:

examples/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 as-is for the parts that work:
$pdf->SetFont('helvetica', '', 12);
$pdf->Cell(0, 10, 'Header line', 0, 1);
// Modern path for what the TCPDF surface cannot express here:
$document = $pdf->getDocument();
$document->image('logo.png', 10, 30, 40, 0);
$document->link(10, 30, 40, 20, 'https://example.com');

Переустановка эталонов для тестов на уровне байтов

Заголовок раздела «Переустановка эталонов для тестов на уровне байтов»

Замените проверки точных байтов проверками того, что действительно важно:

  • Вывод начинается с %PDF и поддаётся разбору (smoke-тест).
  • Отрисованный текст присутствует (извлеките текст и проверьте его).
  • Структурные свойства (количество страниц, размер страницы и наличие закладок) совпадают.

Эта разовая работа даст вам тесты, которые останутся работоспособными при будущих обновлениях движка.

После того как аудит в строгом режиме пройден, строгий режим отключён в производственной среде, а набор тестов проходит с обновлёнными эталонными проверками, удалите tecnickcom/tcpdf:

Окно терминала
composer remove tecnickcom/tcpdf

Запустите набор тестов снова. Если что-либо по-прежнему разрешается в реальный класс TCPDF, сработала оговорка о псевдонимах из этапа 1; исправьте оставшиеся места вызова, чтобы они явно импортировали адаптер.

Адаптер — средство перехода, а не постоянный слой. После того как TCPDF удалён, а движок проверен, постепенно отказывайтесь от адаптера:

  1. В каждом модуле замените new TCPDF(...) созданием современного NextPDF\Core\Document.
  2. Замените вызовы методов TCPDF современными эквивалентами (ориентируйтесь на вызовы getDocument(), которые вы уже добавили на этапе 4).
  3. Когда модуль больше не ссылается на адаптер, удалите его импорты совместимости.
  4. Когда ни один модуль не ссылается на адаптер, удалите nextpdf/compat-legacy из composer.json.

На этом этапе вы работаете с современным API PDF 2.0 без слоя совместимости.

  • nextpdf/compat-legacy установлен; интеграция с движком проверена.
  • Места вызова явно импортируют адаптер (либо включены псевдонимы, а настоящий TCPDF удалён из пути автозагрузки).
  • Полный набор тестов запущен с адаптером; сбои классифицированы.
  • Добавлена CI-задача для строгого режима; каждый пробел внесён в каталог.
  • Каждый пробел исправлен (удаление параметра / современный API / удаление вызова).
  • Проверки на уровне байтов перенастроены на содержимое и структуру.
  • tecnickcom/tcpdf удалён; набор тестов проходит успешно.
  • Отказ от адаптера выполнен модуль за модулем; зависимость удалена.
  • /integrations/tcpdf-compat/method-coverage/ — поведение каждого метода и рекомендации по замене
  • docs/TCPDF_COVERAGE.md — эталонная матрица, проверенная тестами
  • /integrations/tcpdf-compat/configuration/ — перенос конфигурации из глобальных констант
  • /integrations/tcpdf-compat/security-and-operations/ — шифрование и подписание во время перехода
  • /integrations/tcpdf-compat/troubleshooting/ — конфликт alias/real-TCPDF и другие ловушки