TCPDF 6.x에서 NextPDF로 마이그레이션
한눈에 보기
섹션 제목: “한눈에 보기”마이그레이션은 명확한 순서대로 진행합니다. 먼저 가능한 한 작은 변경으로 NextPDF 엔진으로 전환합니다. 이미 동작하는 부분을 입증하고, 동작하지 않는 부분을 점검합니다. 호출 지점마다 하나씩 수정합니다. 그런 다음 어댑터를 제거합니다. 호환성 계층은 2 단계부터 4 단계까지를 지원하지만, 최종 목적지는 아닙니다.
이 페이지에서는 전략을 다룹니다. 개별 메서드의 정확한 동작은 /integrations/tcpdf-compat/method-coverage/와 저장소의 권위 있는 매트릭스인 docs/TCPDF_COVERAGE.md를 함께 확인하십시오.
마이그레이션 모델
섹션 제목: “마이그레이션 모델”애플리케이션은 모든 단계에서 출시 가능한 상태를 유지합니다. 모든 것을 한 번에 전환하는 일괄 컷오버는 전혀 필요하지 않습니다.
1 단계 — 의존성 교체
섹션 제목: “1 단계 — 의존성 교체”nextpdf/compat-legacy를 설치합니다(/integrations/tcpdf-compat/install/ 참조). 아직 tecnickcom/tcpdf를 제거하지 마십시오 — 둘을 모두 유지하면 비교 테스트를 실행할 수 있습니다.
레거시 호출 지점에서 클래스를 어떻게 해석할지 선택합니다:
- 권장: 각 파일에서
use/require를use NextPDF\Compat\Tcpdf\TCPDF;로 변경합니다. 명시적이며 grep으로 찾기도 쉽습니다. - 아직 호출 지점을 건드릴 수 없을 때: 부팅 시 한 번
LegacyBootstrap::enableAliases()로 옵트인 전역 별칭을 활성화합니다(/integrations/tcpdf-compat/boot-and-discovery/ 참조). 이렇게 하면\TCPDF와 네 개의 헬퍼 클래스가 어댑터로 해석됩니다.
두 전략은 실무에서 상호 배타적입니다. 실제 TCPDF 라이브러리가 여전히 오토로드 가능하고 전역 별칭을 활성화하면,
\TCPDF클래스가 이미 존재할 때 별칭이 건너뛰어집니다. 그러면 의도치 않게 레거시 TCPDF를 계속 사용하게 될 수 있습니다. 1 단계 동안에는 파일별 임포트를 선호하여 각 호출 지점이 정확히 어떤 클래스를 사용하는지 명확히 하십시오. 참조: /integrations/tcpdf-compat/troubleshooting/.
2 단계 — 기존 스위트를 변경 없이 실행
섹션 제목: “2 단계 — 기존 스위트를 변경 없이 실행”다른 코드 변경 없이 어댑터를 대상으로 전체 테스트 스위트를 실행합니다. 위임된 메서드 대부분(조사한 약 120 개 중 94 개)은 호환 방식으로 동작합니다. 다음 두 가지 유형의 예측 가능한 실패가 예상됩니다:
- 바이트 수준 단언. 정확한 PDF 바이트를 비교하는 테스트는 엔진이 별도의 구현이므로 실패합니다. 이는 결함이 아니라 예상되는 결과입니다. 이러한 테스트는 4 단계로 미룹니다.
- 반환값 분기. 일부 메서드는 계산된 값 대신 호환성 플레이스홀더를 반환합니다 — 가장 대표적으로
MultiCell()은1을 반환하고,Write()는0을 반환합니다. 이러한 반환값에 따라 분기하는 코드는 조정이 필요합니다.
모든 실패를 목록화합니다. 각 실패를 byte-baseline, return-value, 또는 진짜 동작 격차 중 하나로 분류합니다.
3 단계 — 엄격 모드 점검
섹션 제목: “3 단계 — 엄격 모드 점검”이 단계는 마이그레이션을 안전하게 만드는 핵심입니다. 엄격 모드를 활성화한 상태로 스위트(또는 대표적인 프로덕션 경로)를 실행합니다:
<?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 작업으로 실행하십시오. 핵심은 격차를 드러내는 것이지, 프로덕션에서 예외가 발생하게 하는 것이 아닙니다.
4 단계 — 호출 지점 수정
섹션 제목: “4 단계 — 호출 지점 수정”각 격차에 대해 비용이 가장 낮은 올바른 수정 방법을 선택합니다:
| 격차 패턴 | 수정 |
|---|---|
무시된 매개변수가 중요하지 않은 경우(e.g. 의존한 적 없는 TCPDF $align) | 매개변수를 제거합니다. 호출은 그대로 호환됩니다. |
무시된 매개변수가 중요했던 경우(e.g. 클릭 가능한 Image() 링크) | 최신 API로 다시 표현합니다. 이미지를 그린 다음, 해당 사각형 위에 Document::link()를 추가합니다. |
메서드가 구현되지 않은 경우(setSignature(), endPage()) | endPage() / Open(): 호출을 제거합니다. 서명: /integrations/tcpdf-compat/security-and-operations/ 참조 — 상용 에디션이 필요합니다. |
해당 없는 메서드(setPDFVersion(), setUserRights()) | 제거합니다. 출력은 항상 PDF 2.0 입니다. user-rights는 PDF 2.0 에서 더 이상 사용되지 않습니다. |
| 반환값 분기 | 값을 직접 계산하거나, 해당 로직을 최신 API로 옮깁니다. |
TCPDF API 표면으로 표현할 수 없는 항목에는 모두 이스케이프 해치를 사용합니다:
<?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로 시작하며 파싱됩니다(스모크 수준). - 렌더링된 텍스트 콘텐츠가 존재합니다(텍스트를 추출해 단언).
- 구조적 속성(페이지 수, 페이지 크기, 아웃라인 존재 여부)이 일치합니다.
이는 일회성 비용이며, 향후 엔진 업그레이드 후에도 유지되는 테스트를 만들어 줍니다.
5 단계 — TCPDF 의존성 제거
섹션 제목: “5 단계 — TCPDF 의존성 제거”엄격 모드 점검이 통과하고, 프로덕션에서는 엄격 모드를 끈 상태로 유지하며, 재기준화된 단언으로 스위트도 통과하면, tecnickcom/tcpdf를 제거합니다:
composer remove tecnickcom/tcpdf스위트를 다시 실행합니다. 여전히 실제 TCPDF 클래스로 해석되는 호출이 있다면 1 단계의 별칭 주의사항이 적용된 것입니다 — 남은 호출 지점이 어댑터를 명시적으로 임포트하도록 수정하십시오.
6 단계 — 어댑터 폐기
섹션 제목: “6 단계 — 어댑터 폐기”어댑터는 마이그레이션 보조 도구이지, 영구 계층이 아닙니다. TCPDF가 사라지고 엔진 동작이 입증되면, 어댑터를 점진적으로 폐기합니다:
- 각 모듈에서
new TCPDF(...)를 최신NextPDF\Core\Document생성으로 교체합니다. - TCPDF 메서드 호출을 동등한 최신 API로 교체합니다(4 단계에서 이미 추가한
getDocument()호출이 그 예입니다). - 모듈이 더 이상 어댑터를 참조하지 않으면, 해당 호환성 임포트를 삭제합니다.
- 어떤 모듈도 어댑터를 참조하지 않으면,
composer.json에서nextpdf/compat-legacy를 제거합니다.
이렇게 하면 호환성 계층 없이 최신 PDF 2.0 API 위에서 동작하게 됩니다.
마이그레이션 체크리스트
섹션 제목: “마이그레이션 체크리스트”-
nextpdf/compat-legacy설치됨; 엔진 연결 확인됨. - 호출 지점이 어댑터를 명시적으로 임포트함(또는 별칭을 활성화하고 오토로드 경로에서 실제 TCPDF를 제거함).
- 어댑터를 대상으로 전체 스위트를 실행함; 실패를 분류함.
- 엄격 모드 CI 작업을 추가함; 모든 격차를 목록화함.
- 각 격차를 수정함(매개변수 제거 / 최신 API / 호출 제거).
- 바이트 수준 단언을 content/structure로 재기준화함.
-
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 충돌 및 기타 함정