NextPDF Artisan boot and discovery
At a glance
Section titled “At a glance”Artisan is a plain library that follows PHP Standard Recommendation 4 (PSR-4). It has no service provider, bundle, or framework auto-discovery manifest. It boots as soon as its classes are autoloadable. Discovery is Composer’s PSR-4 map, and nothing more.
How discovery works
Section titled “How discovery works”The package composer.json declares two PSR-4 roots: NextPDF\Artisan\ → src/Artisan/ and NextPDF\Parser\ → src/Parser/. It does not include extra.laravel, a Symfony bundle class, or a CodeIgniter registrar. Nothing scans, registers, or hooks during boot.
The integration point lives in nextpdf/core. Document (through the HasTextOutput concern) exposes writeHtmlChrome(), which checks class_exists() at runtime for NextPDF\Parser\PdfReader and NextPDF\Artisan\PageImporter. When the autoloader can resolve both classes, the Chrome path is available. When it cannot, core raises a layout exception instead of failing with a fatal error. Discovery therefore asks one question: are the Artisan classes on the autoloader? Composer answers that; no framework machinery is involved.
This is deliberate. The bridge is a capability that the core engine reaches across a package boundary, not a framework-managed service. You can use Artisan the same way in Laravel, Symfony, CodeIgniter, a command-line interface (CLI) script, or a queue worker, because none of those hosts are required.
Boot sequence
Section titled “Boot sequence”Artisan has no bootstrap kernel, command registration, or deferred-provider phase. The first writeHtmlChrome() call is the entire lifecycle entry.
Container bindings
Section titled “Container bindings”Artisan has no dependency injection (DI) container and registers no bindings. Its components are constructor-injected plain objects: build a ChromeRendererConfig, pass it to ChromeHtmlRenderer, and optionally inject a PSR-3 logger and a custom HtmlSecurityPolicyInterface. In a host container, register ChromeHtmlRenderer as a singleton yourself; see the example on /integrations/artisan/production-usage/.
Containerless service resolution
Section titled “Containerless service resolution”Some NextPDF capabilities, including Premium e-invoice contracts, usually resolve through a framework container. Artisan also runs in containerless environments, such as CLI tools, standalone scripts, and custom runners, so it ships EInvoiceServiceFactory:
| Method | Returns | When null |
|---|---|---|
makeEmbedder() | EmbedderInterface (Pro) | Pro tier not installed |
makeValidator() | ValidatorInterface (Enterprise) | Enterprise tier not installed |
makeDefaultProfile() | ProfileInterface (EN16931, Pro) | Pro tier not installed |
makeSchematronRunner() | SchematronRunnerInterface (Enterprise) | Enterprise tier not installed |
Each call returns a fresh instance. This use-once behavior matters because embed and validate calls own a mutable Extensible Markup Language (XML) parse context and must not share state. The factory is a convenience for the rare no-container case, not a service locator. The preferred pattern is still to compose objects at construction and pass them as constructor arguments. Returning null when a tier is absent mirrors the framework wrapper packages, so the same calling code runs with or without Premium. Source: src/Artisan/EInvoiceServiceFactory.php; integration-tested in tests/Integration/Artisan/EInvoiceServiceFactoryIntegrationTest.php.
Configuration resolution order
Section titled “Configuration resolution order”There is no configuration-file cascade. Configuration is exactly what you pass to ChromeRendererConfig:
- Constructor arguments you pass explicitly, or
ChromeRendererConfig::fromArray()from a host-provided array (snake-case keys; unset keys fall back to constructor defaults;chrome_binaryapplies only when it is a non-empty string).
The resolved configuration is immutable for the renderer’s lifetime. See /integrations/artisan/configuration/ for every key.
Diagnostics
Section titled “Diagnostics”- “Is the bridge discoverable?” — if
class_exists(\NextPDF\Artisan\PageImporter::class)istrue, Composer’s autoloader can find it, and core will use the Chrome path. - “Did it boot?” — there is no boot phase to fail; a missing dependency surfaces at the first
writeHtmlChrome()call as a typed exception, mapped on /integrations/artisan/troubleshooting/. - Containerless Premium check —
EInvoiceServiceFactory::makeEmbedder() === nullmeans the Pro tier is not installed; the open-source render path is unaffected.
See also
Section titled “See also”- /integrations/artisan/integration/
- /integrations/artisan/overview/
- /integrations/artisan/configuration/
- /integrations/artisan/production-usage/
- /integrations/artisan/troubleshooting/