Skip to content

NextPDF Artisan boot and discovery

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.

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.

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

Artisan has no bootstrap kernel, command registration, or deferred-provider phase. The first writeHtmlChrome() call is the entire lifecycle entry.

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/.

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:

MethodReturnsWhen 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.

There is no configuration-file cascade. Configuration is exactly what you pass to ChromeRendererConfig:

  1. Constructor arguments you pass explicitly, or
  2. ChromeRendererConfig::fromArray() from a host-provided array (snake-case keys; unset keys fall back to constructor defaults; chrome_binary applies 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.

  • “Is the bridge discoverable?” — if class_exists(\NextPDF\Artisan\PageImporter::class) is true, 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 checkEInvoiceServiceFactory::makeEmbedder() === null means the Pro tier is not installed; the open-source render path is unaffected.
  • /integrations/artisan/integration/
  • /integrations/artisan/overview/
  • /integrations/artisan/configuration/
  • /integrations/artisan/production-usage/
  • /integrations/artisan/troubleshooting/