파이프라인 모델
Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 Evidence: Code-backed
한눈에 보기
섹션 제목: “한눈에 보기”NextPDF 문서는 하나의 불투명한 단계에서 생성되지 않습니다. 몇 개의 명시적인 단계를 거칩니다. 의도를 기록하는 파사드, 그 의도를 모델로 변환하는 콘텐츠 계층, 그리고 그 모델을 규격에 맞는 PDF로 직렬화하는 작성기입니다. 이 페이지는 그 구조와 그렇게 설계된 이유를 설명합니다.
이것이 중요한 이유
섹션 제목: “이것이 중요한 이유”PDF 파일 형식 자체는 헤더, 객체 본문, 상호 참조 테이블, 트레일러로 이루어진 계층화된 구조이며, 작성기는 이 모든 요소를 일관되게 조립해야 합니다. 이를 만드는 엔진이 하나로 뒤엉킨 절차라면 모든 변경이 모든 출력을 위험에 빠뜨립니다. 그러면 확신을 얻는 유일한 방법은 문서 전체를 렌더링해 눈으로 검사하는 것뿐이고, 이는 느리고 뒤늦게 확인되며 설득력도 약합니다.
명시적인 파이프라인은 이 상황을 뒤집습니다. 각 단계는 하나의 작업과 타입이 지정된 경계를 가지므로, 파일 끝에서만이 아니라 변경이 닿는 단계에서 바로 변경을 추론하고 테스트할 수 있습니다. 이 아키텍처는 무엇보다 테스트 가능성과 확장성을 위한 결정입니다.
간략한 버전
섹션 제목: “간략한 버전”- 공개 진입점은 Document 파사드입니다. 이는 어떻게 직렬화할지가 아니라 무엇을 원하는지를 기록하는 플루언트하고 일회용이며 워커 안전한 빌더입니다.
- 파사드는 약 스물네 개의 집중된 관심사 트레이트(텍스트 출력, 그리기, 페이지, 보안, 내비게이션 등)에 위임합니다. 하나의 거대한 클래스가 아니라, 각 트레이트가 하나의 책임을 맡습니다.
- 콘텐츠는 두 가지 경로 중 하나를 통해 들어옵니다. 직접 그리기(그래픽 프리미티브) 또는 HTML/CSS 엔진입니다. 둘 다 동일한 내부 문서 모델을 생성합니다.
- 전용 PDF 작성기가 PDF 1.4 / 1.7 / 2.0 전략을 선택하여 그 모델을 직렬화합니다. 유효한 파일 구조를 만드는 책임은 오직 이 단계에 있습니다.
- 수명이 긴 상태(폰트 및 이미지 레지스트리)는 프로세스 범위에서 공유됩니다. 요청별 상태(문서)는 새로 생성되며 절대 재사용되지 않습니다. 경계가 명시적이며, 바로 이것이 워커 런타임을 안전하게 만듭니다.
NextPDF가 접근하는 방식
섹션 제목: “NextPDF가 접근하는 방식”이 모델을 가장 깔끔하게 이해하는 방법은 호출부터 바이트까지 문서를 따라가 보는 것입니다.
- Document facade Fluent, use-once builder; records intent via concern traits.
- Content production Direct drawing or the HTML/CSS engine — both build one document model.
- Document model Accumulated pages, content, and resources held as typed state.
- PDF writer Serialises the model; selects a PDF 1.4 / 1.7 / 2.0 strategy.
- Conforming PDF Header, object body, cross-reference table, trailer.
두 가지 설계 선택이 이 구조를 단순한 다이어그램 이상의 것으로 만듭니다.
파사드는 단일체가 아니라 조합되어 있습니다. Document는 모든 기능을 직접 구현하지 않습니다. 각 영역을 전용 관심사 트레이트, 즉 텍스트 출력, 그리기, 페이지, 보안, 타이포그래피, 내비게이션, 트랜잭션 등에 위임합니다. 새로운 문서 메서드는 파사드 자체가 아니라 해당 영역을 소유한 트레이트에 속합니다. 호출하는 클래스는 작게 유지되고, 책임은 분리된 상태로 유지됩니다.
작성기가 파일 구조를 독점적으로 소유합니다. 콘텐츠 생성은 어떤 마크와 객체가 존재하는지 결정합니다. 작성기는 어떤 버전 전략을 적용할지를 포함해, 그것들이 어떻게 유효한 PDF 파일이 되는지 결정합니다. 이 분리는 아키텍처 규칙으로 강제됩니다. 레이아웃과 콘텐츠 코드는 최종 파일 구조를 내보내지 않고, 작성기는 레이아웃 결정을 내리지 않습니다. 이점은 “출력이 유효한 PDF인가?”라는 질문을 테스트할 곳이 정확히 한 군데뿐이라는 점입니다.
수명 경계는 나중에 덧붙인 것이 아니라 모델의 일부입니다. 폰트 및 이미지 레지스트리는 프로세스가 살아 있는 동안 유지되며 요청 간에 공유됩니다. 문서, 해당 렌더링 컨텍스트, 작성기는 요청별로 생성되고 폐기됩니다. 워커 런타임에서 이 구분은 안전한 재사용과 요청 간 손상의 차이를 만듭니다. 그래서 이는 개발자 규율에 맡겨지지 않고 아키텍처에 명시되어 있습니다.
증거가 말하는 것
섹션 제목: “증거가 말하는 것”이 페이지는 Evidence: Code-backed 로 뒷받침됩니다. 이 단계들은 코어 저장소의 실제 구조에 대응됩니다.
- 파사드와 그 위임 구조는
src/Core/Document.php와src/Core/Concerns/의 관심사 트레이트에 대응됩니다(텍스트 출력, 출력, 그리기, 페이지, 보안, 타이포그래피, 내비게이션, 트랜잭션 등 — 각각 하나의 책임). - 두 콘텐츠 경로는 HTML/CSS 엔진(
src/Html/)과 직접 그리기(src/Graphics/)이며, 둘 다 내부 모델에 공급됩니다. - 직렬화와 PDF 버전 전략은
src/Writer/(PdfWriter.php, 명시적인 PDF 1.4 / 1.7 / 2.0 전략 클래스 포함)에 있습니다. - 프로세스 수명과 요청별 경계는 아키텍처 개요에 기록되어 있으며, 함께 제공되는 워커 팩토리 예제가 워커 안전 설계를 입증합니다. 이 예제는 각
Document를 새로 생성하면서 요청 간에FontRegistry와ImageRegistry를 공유합니다.
목적지는 형식이 정합니다. 작성기의 출력은 헤더, 객체 본문, 상호 참조 테이블, 트레일러여야 하며, 다음을 따라야 합니다 Spec: ISO 32000-2, §7.5 ISO 32000-2 §7.5 . 이 의무를 한 단계에 집중시키면 엔진의 나머지 부분은 파일 구조를 조립하는 대신 콘텐츠에 집중할 수 있습니다.
실용적인 예제
섹션 제목: “실용적인 예제”파사드의 역할은 의도가 말 그대로 의도처럼 읽히게 하는 것입니다. 콘텐츠 경로와 작성기는 호출 지점에서 드러나지 않습니다.
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone(); // facade$doc->setTitle('Quarterly Report'); // metadata concern$doc->addPage(); // pages concern$doc->setFont('helvetica', 'B', 16); // typography concern$doc->cell(0, 12, 'Summary', newLine: true); // text-output concern$doc->writeHtml('<p>Generated in-process.</p>'); // HTML content path$doc->save(__DIR__ . '/report.pdf'); // writer stage각 호출은 서로 다른 관심사에 닿습니다. 서로 다른 두 콘텐츠 경로는 동일한 모델로 공급됩니다. 정확히 한 단계, 즉 save()만 모델을 파일 바이트로 변환합니다. 호출 지점에서는 상호 참조 테이블이 어떻게 구성되는지 알 필요가 없습니다.
흔한 오해
섹션 제목: “흔한 오해”자주 발생하는 오해는 “파이프라인”이 Unix 파이프처럼 단계별로 연결하는 스트리밍 푸시 API를 뜻한다고 보는 것입니다. 그렇지 않습니다. 여기서 파이프라인은 아키텍처적 분해입니다. 단일 책임과 타입이 지정된 경계를 가진 단계들의 구성입니다. 여전히 플루언트한 파사드를 대상으로 프로그래밍합니다. 이 단계들은 손으로 조립하는 전송 수단이 아니라 엔진이 빌드되고 테스트되는 방식입니다.
관련된 또 다른 실수는 파사드가 곧 엔진이라고 가정하는 것입니다. 파사드는 진입점입니다. 실제 작업은 관심사 트레이트, 두 콘텐츠 경로, 작성기에 걸쳐 분산되어 있습니다. 바로 이 분산 구조가 하나의 기능 변경이 모든 출력을 위험에 빠뜨리지 않는 이유입니다.
한계와 경계
섹션 제목: “한계와 경계”이 페이지는 개별 단계의 내부 API가 아니라 파이프라인의 구조를 설명합니다. 정확한 관심사 트레이트 목록, 작성기 전략 선택 규칙, 콘텐츠 모델 필드는 이 설명이 아니라 코드와 레퍼런스가 정의합니다. 정확한 트레이트 개수는 모델을 바꾸지 않고도 달라질 수 있는 구현 세부 사항입니다. 이 페이지는 HTML 엔진의 내부 단계(별도 주제)나 작성기의 스트리밍 및 메모리 동작(역시 별도 주제)을 다루지 않습니다. 구조에 관한 주장은 이 페이지의 검토일 기준으로 정확합니다. 권위 있는 출처는 코어 저장소의 src/Core/, src/Html/, src/Graphics/, src/Writer/입니다.
파이프라인 모델은 모든 에디션에서 동일합니다. 에디션은 새로운 단계가 아니라 기존 단계 내에 기능을 추가합니다.
| Edition | Availability |
|---|---|
| Core | Core는 전체 파사드 → 콘텐츠 → 작성기 파이프라인을 구현합니다. |
| Pro | Pro는 새로운 단계가 아니라 기존 단계 내에 기능을 추가합니다. |
| Enterprise | Enterprise는 새로운 단계가 아니라 기존 단계 내에 기능을 추가합니다. |
관련 문서
섹션 제목: “관련 문서”- 메모리와 스트리밍 — 작성기 단계가 메모리를 제한된 범위 안에 유지하는 방식.
- HTML 파이프라인 — HTML 콘텐츠 경로의 내부 단계.
- 모든 곳에 엄격한 타입 — 각 단계를 독립적으로 테스트할 수 있게 만드는 타입이 지정된 경계.
용어집
섹션 제목: “용어집”- 파사드 — 공개
Document진입점입니다. 의도를 기록하고 관심사 트레이트에 위임하는 플루언트하고 일회용인 빌더입니다. - 관심사 트레이트 — 파사드가 조합하는 집중된 PHP 트레이트이며, 각각 하나의 기능 영역(텍스트 출력, 그리기, 페이지, 보안 등)을 소유합니다.
- 콘텐츠 경로 — 콘텐츠가 모델로 들어가는 두 가지 방법 중 하나입니다. 직접 그리기 또는 HTML/CSS 엔진이 여기에 해당합니다.
- 문서 모델 — 직렬화 전에 페이지, 콘텐츠, 리소스를 타입이 지정된 형태로 누적한 엔진의 내부 구조입니다.
- 작성기 단계 — PDF 1.4 / 1.7 / 2.0 전략을 선택하여 모델을 유효한 PDF로 직렬화하는 구성 요소입니다.
- 워커 안전 — 프로세스 수명 상태는 안전하게 공유하고 요청별 상태는 새로 생성해 절대 재사용하지 않도록 설계한 특성입니다.