Pro edition
Template — Deep Reference
At a glance
Section titled “At a glance”This deep reference documents the accepted JSON template schema, every validation rule, and the exact per-type formatting behavior of the data binder. The module parses a template definition, then binds caller data to typed placeholders. It emits formatted strings; it does not draw PDF objects.
Availability & licensing
Section titled “Availability & licensing”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 runtime capability
flag gates this module. Compare editions and get a license.
Public API surface
Section titled “Public API surface”The module exposes two entry-point services and four immutable value objects. Every symbol below is public and stable.
| Symbol | Parameters | Default behavior | Returns | Throws or fails with | Notes |
|---|---|---|---|---|---|
TemplateParser::parse | string $json | Validates, then builds the definition | TemplateDefinition | InvalidArgumentException when any validation error is present | Delegates to validate first. |
TemplateParser::validate | string $json | Collects all structural errors in one pass | list<string> (empty when valid) | Never throws; a JSON decode failure is returned as a message | Authoritative gate for length and precision bounds. |
TemplateDataBinder::bind | TemplateDefinition $template, array<string,mixed> $data | Matches placeholders case-insensitively and formats by type | BindingResult | Never throws; anomalies become warnings or missing fields | Uses a placeholder default value when the key is absent. |
TemplateDefinition::__construct | string $name, string $pageSize, string $orientation, list<TemplatePlaceholder> $placeholders, string $backgroundPdf = '' | Stores the parsed definition | TemplateDefinition | TypeError on an argument type mismatch | Final readonly value object. |
TemplateDefinition::getPlaceholder | string $name | Case-insensitive lookup by name | TemplatePlaceholder|null | No failure; returns null when absent | — |
TemplateDefinition::requiredFields | none | Collects names of placeholders that have no default value | list<string> | No failure | A non-empty default marks a placeholder optional. |
TemplatePlaceholder::__construct | string $name, PlaceholderType $type, float $x, float $y, float $width, float $height, string $defaultValue = '', string $format = '' | Stores one placeholder region | TemplatePlaceholder | TypeError on an argument type mismatch | Coordinates are points from the top-left. |
TemplatePlaceholder::matches | string $key | Case-insensitive name comparison | bool | No failure | — |
BindingResult::__construct | list<BoundPlaceholder> $bindings, list<string> $missingFields, list<string> $warnings | Stores the binding outcome | BindingResult | TypeError on an argument type mismatch | Final readonly value object. |
BindingResult::isComplete | none | Reports whether every required field was bound | bool | No failure | True when missingFields is empty. |
BindingResult::count | none | Counts successfully bound placeholders | int | No failure | — |
BoundPlaceholder::__construct | TemplatePlaceholder $placeholder, string $formattedValue, mixed $rawValue | Pairs a placeholder with its formatted value | BoundPlaceholder | TypeError on an argument type mismatch | Final readonly value object. |
PlaceholderType | enum cases Text, Image, Barcode, Date, Number, Currency, Conditional | String-backed placeholder taxonomy | enum instance | ValueError from from() on an unknown value | tryFrom() returns null instead. |
PlaceholderType::requiresFormatting | none | Reports whether the type consumes a format string | bool | No failure | True for Date, Number, Currency. |
final class TemplateParser{ public function parse(string $json): TemplateDefinition; public function validate(string $json): array;}final class TemplateDataBinder{ public function bind(TemplateDefinition $template, array $data): BindingResult;}Behavior contract
Section titled “Behavior contract”Accepted JSON shape:
{ "name": "string (required, non-empty)", "pageSize": "A3|A4|A5|A6|B4|B5|Letter|Legal|Tabloid", "orientation": "P|L", "backgroundPdf": "optional path string", "placeholders": [ { "name": "string", "type": "text|image|barcode|date|number|currency|conditional", "x": number, "y": number, "width": number, "height": number, "defaultValue": "optional", "format": "optional" } ]}Validation rules, all surfaced by validate as messages and aggregated by
parse into one exception:
- Missing or empty
name. pageSizeoutside the allow-list, ororientationnotPorL.- Missing
placeholders, or a non-array value. - Per placeholder: missing or empty name; invalid type; missing or non-numeric
x,y,width,height; duplicate name (case-insensitive). defaultValue: non-string, longer than 4096 bytes, or carrying an ASCII control character.format: non-string, longer than 256 bytes, or carrying an ASCII control character.- A
numberplaceholderformatthat is not a non-negative integer, or that exceeds 30.
Binding semantics (TemplateDataBinder::bind):
- Data keys are lower-cased for case-insensitive matching against placeholder names.
- An absent key with a non-empty default binds the default; an absent key
without one is reported in
missingFields. - Text, image, and barcode values are cast to string unchanged.
- Date binding accepts a
DateTimeInterface, an integer Unix timestamp, or a string in one of four explicit formats. The default output format isY-m-d. - Number binding uses
number_format(value, decimals, '.', ','). The decimal count comes fromformat, defaults to2, and is bounded to the range 0 through 30. - Currency binding prefixes the formatted number with
format, defaulting the prefix to$. - Conditional binding emits
"true"or"false"from a boolean cast.
Edge cases & failure modes
Section titled “Edge cases & failure modes”backgroundPdfis never opened or dereferenced by this module. It is an opaque string handed to the renderer.- A non-numeric value bound to a Number or Currency placeholder produces a warning; the value is string-cast, not rejected.
- Date strings are parsed strictly. Relative and natural-language tokens (“now”, “+1 year”, “tomorrow”) match no accepted format, so they warn and the raw value passes through unchanged.
- An integer date value is read as a Unix timestamp via the
@epoch form. - A Number
formatprecision outside 0 through 30 that reaches the binder is rejected with a warning; the binder falls back to the default precision of 2. - No cryptographic operation occurs in this module, so there is no FIPS-mode specific behavior.
Conformance
Section titled “Conformance”No direct PDF-specification surface exists. Page-size and orientation
vocabularies are NextPDF conventions, and the module emits formatted values,
not PDF objects. The strict string-date allow-list accepts the Internet
date/time profile of ISO 8601 defined in RFC 3339 §5.6, alongside a
Y-m-d calendar date and two local date-time forms. NextPDF documents the
capability to read these formats; it claims no certification against RFC 3339
or ISO 8601.
Development notes
Section titled “Development notes”TemplateParserandTemplateDataBinderare stateless. A single instance is reusable and safe to share across bindings.- The four value objects are
final readonly; construct them through the parser rather than by hand for production input. validatereports every structural error in one pass, whileparsecallsvalidatefirst and throws on the aggregated message. Usevalidatefor form-style feedback andparsefor fail-fast ingestion.- The length and precision bounds are enforced at the parser as the
authoritative gate.
TemplateDataBinderre-checks the number precision as a sink-side guard againstnumber_formatmemory amplification.
Publication boundary
Section titled “Publication boundary”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.