Skip to content
getnextpdf.com

Pro edition

Template

NextPDF\Pro\Template parses a JSON template definition into a typed value object and binds an associative data array to its placeholders with type-aware formatting. It produces a structured binding result; it does not render a PDF itself.

This capability ships in NextPDF Pro (nextpdf/pro) and activates with a Pro-tier license envelope. A deployment without that entitlement does not load the capability’s classes. No additional runtime capability flag gates this module beyond the tier license. Compare editions and get a license.

Terminal window
composer require nextpdf/pro:^3

A template is a JSON document describing a page setup and a list of positioned placeholders. TemplateParser validates the JSON and produces an immutable TemplateDefinition. Validation is strict: it checks the page size against an allow-list (A3–A6, B4, B5, Letter, Legal, Tabloid), orientation (P or L), and each placeholder’s name, type, and numeric coordinates, and it rejects duplicate placeholder names.

TemplateDataBinder binds a data array (matched case-insensitively to placeholder names) and formats each value by PlaceholderType:

  • Text / Image / Barcode — value passed through as a string.
  • Date — formatted with the placeholder’s format (default Y-m-d), accepting strings, Unix timestamps, or DateTimeInterface.
  • Numbernumber_format with decimals from the format (default 2).
  • Currency — number formatted with the format string as a prefix (default $).
  • Conditional"true" or "false" based on truthiness.

The result is a BindingResult carrying the bound values, the list of missing required fields, and any formatting warnings. Turning bound values into a rendered PDF is the caller’s responsibility, using the Core document and writer APIs and the optional backgroundPdf reference.

The parser is the single authoritative gate. It turns untrusted JSON into an immutable, fully typed TemplateDefinition, and binding then runs as a pure function of that value. Every field that later reaches a formatting sink is allow-listed and length-bounded at parse time. Page size, orientation, number precision, and control characters all fail here, not mid-render. String dates are matched against a fixed set of canonical formats, so a value like now or +1 year cannot make output depend on the wall clock. The module stops deliberately at a BindingResult and leaves rendering, path resolution, and background compositing to the caller, which keeps the trust boundary explicit.

Design background: Invoices and e-invoicing.

  • Input. A JSON string (TemplateParser) and a data array (TemplateDataBinder).
  • Output. TemplateDefinition from parsing; BindingResult from binding.
  • Validation. validate() returns a list of human-readable errors and never throws; parse() throws InvalidArgumentException when validation fails.
  • Missing data. A placeholder with no data and an empty default is reported in missingFields; one with a non-empty default uses the default.
  • Determinism. Parsing and binding are pure functions of their inputs.
TypeKindKey members
NextPDF\Pro\Template\TemplateParserfinal classparse(string $json): TemplateDefinition, validate(string $json): list<string>
NextPDF\Pro\Template\TemplateDataBinderfinal classbind(TemplateDefinition $template, array $data): BindingResult
NextPDF\Pro\Template\TemplateDefinitionfinal readonly classstring $name, string $pageSize, string $orientation, array $placeholders, string $backgroundPdf, getPlaceholder(string $name): ?TemplatePlaceholder, requiredFields(): list<string>
NextPDF\Pro\Template\TemplatePlaceholderfinal readonly classname, PlaceholderType $type, coordinates, default, format
NextPDF\Pro\Template\BindingResultfinal readonly classarray $bindings, array $missingFields, array $warnings
NextPDF\Pro\Template\PlaceholderTypeenumText, Image, Barcode, Date, Number, Currency, Conditional; requiresFormatting(): bool
<?php
declare(strict_types=1);
use NextPDF\Pro\Template\TemplateDataBinder;
use NextPDF\Pro\Template\TemplateParser;
$json = '{"name":"Invoice","pageSize":"A4","orientation":"P","placeholders":'
. '[{"name":"total","type":"currency","x":400,"y":700,"width":120,'
. '"height":18,"format":"$"}]}';
$template = (new TemplateParser())->parse($json);
$result = (new TemplateDataBinder())->bind($template, ['total' => 1299.5]);
foreach ($result->bindings as $bound) {
echo $bound->placeholder->name, ' => ', $bound->formattedValue, "\n";
}
<?php
declare(strict_types=1);
use NextPDF\Pro\Template\TemplateDataBinder;
use NextPDF\Pro\Template\TemplateParser;
function bindOrReject(string $json, array $data): array
{
$parser = new TemplateParser();
$errors = $parser->validate($json);
if ($errors !== []) {
throw new InvalidArgumentException(implode('; ', $errors));
}
$template = $parser->parse($json);
$result = (new TemplateDataBinder())->bind($template, $data);
if ($result->missingFields !== []) {
throw new RuntimeException(
'missing required fields: ' . implode(', ', $result->missingFields),
);
}
return $result->bindings; // hand to the renderer
}
  • An unparseable date string produces a warning and the original string is kept, rather than throwing.
  • The currency format string is used as a literal prefix (for example "$" or "EUR "), not a locale identifier.
  • backgroundPdf is a path reference carried on the definition; this module does not open, validate, or composite it — that is the renderer’s job.
  • Placeholder names are matched case-insensitively; duplicate names in the JSON are a validation error.

Parsing is one JSON decode plus structural validation; binding is linear in placeholder count. See performance_budget.

JSON is decoded with JSON_THROW_ON_ERROR and validated against fixed allow-lists before a TemplateDefinition is constructed. The module performs no file or network I/O; the backgroundPdf path is not dereferenced here, so path handling and access control belong to the renderer.

This module has no direct PDF-specification surface: it parses a JSON template and formats values. The page-size and orientation vocabularies are NextPDF conventions, not normative PDF constructs.

There is no Core template-definition layer. For fully imperative document construction, use the open-source Core document and writer APIs directly. See /modules/core/document/.

This module defines and binds templates. It does not perform mail-merge orchestration, batch job scheduling, or rendering; those concerns are out of scope and are handled elsewhere.

This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.