跳到內容

NextPDF Artisan 的啟動與探索

Artisan 是一個純粹的 PSR-4 函式庫,沒有 service provider、沒有套件(bundle),也沒有 framework(框架)自動探索資訊清單。當它的類別能被自動載入的那一刻,就算完成「啟動」;所謂探索就是 Composer 的 PSR-4 對映表,僅此而已。

套件的 composer.json 宣告了兩個 PSR-4 根目錄——NextPDF\Artisan\src/Artisan/,以及 NextPDF\Parser\src/Parser/。這裡沒有 extra.laravel、沒有 Symfony bundle 類別,也沒有 CodeIgniter registrar。啟動時不會掃描、註冊或掛載任何東西。

整合點位於 nextpdf/core 這一側。Document(透過 HasTextOutput concern)對外提供 writeHtmlChrome(),它會在執行階段執行一次 class_exists() 檢查,檢查對象是 NextPDF\Parser\PdfReaderNextPDF\Artisan\PageImporter。當這兩者都能透過自動載入器 resolve(解析)時,就能使用 Chrome 路徑。當它們無法解析時,core 會丟出版面例外,而不是發生致命錯誤。因此,所謂「探索」就是:Artisan 的類別是否已掛在自動載入器上?這個問題由 Composer 回答——完全不涉及任何 framework 機制。

這是刻意的設計。這個橋接層是 core 引擎跨越套件邊界取用的一項能力,而不是由 framework 管理的服務。因此,Artisan 在 Laravel、Symfony、CodeIgniter、CLI 指令稿或佇列 worker 中都能以相同方式使用,因為這些都不是必要條件。

no

yes

Composer autoload (PSR-4)

Application constructs Document

Document::setChromeRendererConfig(config)

Document::writeHtmlChrome(html)

class_exists PdfReader

and PageImporter?

core raises layout exception

resolve ChromeHtmlRenderer

render → parse → import Form XObject

Diagram

這裡沒有核心啟動程序(bootstrap kernel)、沒有指令註冊,也沒有延遲 provider 階段。第一次呼叫 writeHtmlChrome() 就是整個生命週期的進入點。

Artisan 沒有 DI 容器,也不註冊任何繫結。各元件都是以建構式注入組成的純粹物件:建立一個 ChromeRendererConfig,把它傳給 ChromeHtmlRenderer,並視需要注入一個 PSR-3 logger 與一個自訂的 HtmlSecurityPolicyInterface。若使用宿主容器,請自行將 ChromeHtmlRenderer 註冊為單例——範例請見 /integrations/artisan/production-usage/.

NextPDF 的部分能力(Premium 電子發票合約)通常會透過 framework 容器解析。Artisan 也會在無容器的環境中執行——CLI 工具、獨立指令稿、自訂執行器——因此它隨附了 EInvoiceServiceFactory

方法回傳值何時為 null
makeEmbedder()EmbedderInterface(Pro 版)未安裝 Pro 層
makeValidator()ValidatorInterface(Enterprise 版)未安裝 Enterprise 層
makeDefaultProfile()ProfileInterface(EN16931,Pro 版)未安裝 Pro 層
makeSchematronRunner()SchematronRunnerInterface(Enterprise 版)未安裝 Enterprise 層

每次呼叫都會回傳一個 全新 的執行個體(採用用完即棄語意——embed 與 validate 呼叫各自擁有一個可變的 XML 剖析(parse)脈絡,不得共用狀態)。這個工廠(factory)是提供給少數無容器情境的便利手段,而不是一個 service locator。建議做法仍是在建構階段組裝物件,並把它們當作建構式引數傳入。這種「找不到就回傳 null」的行為與 framework 包裝套件一致,因此同一份呼叫端程式碼無論是否有 Premium 都能執行。來源:src/Artisan/EInvoiceServiceFactory.php;整合測試位於 tests/Integration/Artisan/EInvoiceServiceFactoryIntegrationTest.php

這裡沒有組態檔的層疊機制。組態就是你傳給 ChromeRendererConfig 的內容:

  1. 明確的建構式引數,或者
  2. ChromeRendererConfig::fromArray() 會從宿主提供的陣列建立組態(採 snake-case 鍵;未設定的鍵會回退到建構式預設值;chrome_binary 只有在是非空字串時才會套用)。

解析後的組態在 renderer(渲染器)的整個生命週期中都不可變。每個鍵的說明請見 /integrations/artisan/configuration 一節。

  • 「這個橋接層可被探索到嗎?」——若 class_exists(\NextPDF\Artisan\PageImporter::class)true,代表 Composer 的自動載入器已載入它;core 就會使用 Chrome 路徑。
  • 「它啟動了嗎?」——這裡不存在會失敗的啟動程序;缺少的相依套件會在第一次呼叫 writeHtmlChrome() 時以型別化例外浮現,其對映關係整理於 /integrations/artisan/troubleshooting/.
  • 無容器的 Premium 檢查——EInvoiceServiceFactory::makeEmbedder() === null 代表未安裝 Pro 層;開放原始碼渲染路徑不受影響。
  • 整合指南:/integrations/artisan/integration/
  • 總覽:/integrations/artisan/overview/
  • 組態:/integrations/artisan/configuration/
  • 生產環境使用:/integrations/artisan/production-usage/
  • 疑難排解:/integrations/artisan/troubleshooting/