Skip to content

NextPDF backport boot and discovery

Build tooling — NOT a runtime dependency. This page explains how the builder starts on a maintainer or continuous integration (CI) host. Downstream applications never load this code.

The builder does not use a framework, a dependency-injection container, or service-provider auto-discovery. Instead, PHP command-line interface (CLI) scripts are wired with require_once and Composer’s PSR-4 autoloader. Here, “discovery” has two specific meanings: which source repositories the merge stage reads, and how the orchestrator selects the Rector configuration for the target.

The orchestrator is scripts/build.php. It starts the build, then runs five stages in order. Each stage is gated, so the first failure stops the build:

  1. Merge sources — copy the source repositories into one tree.
  2. Run Rector downgrade — run one pass for PHP 8.1; run two passes plus fix-ups for PHP 7.4.
  3. Generate composer.json — write the generated package manifest with its replace map.
  4. Copy static assets — copy the license and a generated changelog.
  5. Validate output — count emitted PHP files; the authoritative syntax gate runs later in CI.

Verified against scripts/build.php (run(), step()). See /integrations/backport/configuration/ for rule-selection details and /integrations/backport/production-usage/ for the CI gate.

Source discovery is not manifest-driven. scripts/merge-sources.php uses a fixed map keyed by repository name and selected by the target.

For the PHP 8.1 target, the map includes nextpdf (core), nextpdf-Artisan, nextpdf-compat-legacy, nextpdf-Laravel, nextpdf-Symfony, nextpdf-CodeIgniter, and nextpdf-Pro when Pro is included. For the PHP 7.4 target, the map collapses to nextpdf only. The builder resolves each repository as a sibling directory under the --source-dir root. It validates every expected repository before copying anything. If one is missing, the merge aborts and reports its name and path. Verified against scripts/merge-sources.php (MergeSources::__construct(), run()).

The merge places core at src/ and each adapter under its namespaced subdirectory (src/Artisan/, src/Laravel/, and so on). Pro goes into a separate pro/src/ tree so the build can emit it as its own package. Verified against MergeSources (mergeCore(), mergeArtisan(), mergePro()).

  1. scripts/build.php runs under the CLI Server Application Programming Interface (SAPI). It require_onces merge-sources.php and adjust-composer.php.
  2. The CLI entry point reads options with getopt()--version, --source-dir, --output-dir, --target, --dry-run, --no-pro.
  3. A Build instance is constructed. The constructor validates --target against ['php74', 'php81'] and raises InvalidArgumentException for an invalid value before any work begins. For the PHP 7.4 target, it forces core-only output and disables Pro.
  4. Build::run() executes the five stages and exits with status 0 on success, or 1 on the first failure.

Verified against scripts/build.php (CLI entry point, Build::__construct(), run()).

Not applicable. The builder is a CLI tool. It has no dependency-injection container and no framework service container. Wiring uses explicit require_once calls, plus Composer PSR-4 autoloading of NextPDF\Backport\ (rules) and NextPDF\Backport\Scripts\ (scripts). Verified against composer.jsonautoload and the require_once statements in scripts/build.php.

There is no configuration file. Configuration comes from CLI flags resolved against the defaults baked into the script:

  1. The CLI flag, if provided.
  2. The default in the getopt() parsing block (for example, target defaults to php81, and version defaults to 2.0.0).
  3. Behavior that the constructor derives from the target (PHP 7.4 forces core-only and no Pro, regardless of --no-pro).

Verified against scripts/build.php (CLI entry point and Build::__construct()). The full flag reference is in /integrations/backport/configuration/.

The orchestrator provides its own diagnostics. Run a dry run (composer build:dry) to print the source repositories that would be read and each stage’s intent, without writing anything. Every stage prints a success check mark or a named failure. There is no separate diagnose subcommand and no bin/ entry point. The builder runs through scripts/build.php or its Composer-script aliases. Verified against scripts/build.php (step(), the dryRun branches), scripts/merge-sources.php (run() dry-run path), and composer.jsonscripts.

  • /integrations/backport/overview/ — what the builder is and what it produces.
  • /integrations/backport/integration/ — the build-host integration contract.
  • /integrations/backport/configuration/ — Rector configurations and the flag reference.
  • /integrations/backport/troubleshooting/ — stage-by-stage failure reference.