API Reference

Auto-gegenereerd via Reflection — blijft altijd in sync met src/.

Filter: alleAppCacheCmsDbDebugDynamicEventsFilesFormHtmlHttpImageLogMediaSecuritySessionStdlibSupportView

CompositeRule

Framework\Form\Conditional\CompositeRule
final class

A composite conditional: multiple ConditionalRules combined with AND or OR.

Serialises to:
{"logic": "and", "rules": [{"field":"x","operator":"equal","value":"y"}, ...]}

Usage:
CompositeRule::all(
ConditionalRule::whenEqual('type', 'business'),
ConditionalRule::whenEqual('region', 'nl'),
)

4 public methods
static all(\ConditionalRule ...$rules = ?): self

All rules must pass (AND).

static any(\ConditionalRule ...$rules = ?): self

At least one rule must pass (OR).

toArray(): array
toJson(): string

ConditionalRule

Framework\Form\Conditional\ConditionalRule
final class

A single conditional rule: show/hide a field when another field's value
satisfies a comparison.

This value object serialises to the JSON format expected by form-enhanced.js:

{"field": "type", "operator": "equal", "value": "business"}

Usage:
ConditionalRule::when('type', RuleOperator::Equal, 'business')

__construct(string $field, \RuleOperator $operator, string $value)
4 public methods
toArray(): array

Serialise to the JSON structure expected by form-enhanced.js.

toJson(): string
static when(string $field, \RuleOperator $operator, string $value): self
static whenEqual(string $field, string $value): self

Shorthand for the most common case: show when field equals value.

RuleEvaluator

Framework\Form\Conditional\RuleEvaluator
final class

Evaluates ConditionalRule / CompositeRule against a flat values map.

Extracted from Form::process() so that ConditionalValidator (or any other
code that needs to test a rule against submitted values) can reuse the
exact same semantics without duplication.

1 public method
evaluate(\ConditionalRule|\CompositeRule $rule, array $values): bool

RuleOperator

Framework\Form\Conditional\RuleOperator
enum

Comparison operators for conditional field rules.

These values are serialised as strings in the data-conditional JSON
attribute consumed by form-enhanced.js on the client.

3 public methods
static cases(): array
static from(string|int $value): static
static tryFrom(string|int $value): ?static
Cases: Equal, NotEqual, Contains, NotContains, GreaterThan, LessThan, GreaterEqual, LessEqual

FormSchemaException

Framework\Form\Exception\FormSchemaException
final class

Thrown when a JSON form schema cannot be parsed or contains invalid data.

The message always describes which part of the schema is invalid so
CMS developers get actionable feedback.

__construct(string $message = '', int $code = 0, ?Throwable $previous = NULL)
5 public methods
static invalidJson(string $error): self
static missingKey(string $key, string $context = ''): self
static unknownOperator(string $operator): self
static unknownType(string $type, string $context = ''): self
static unknownValidator(string $type): self

AbstractField

Framework\Form\Field\AbstractField
abstract class

Base class for typed form field definitions.

A field is a pure data+metadata object — it carries no HTML knowledge.
The FormRenderer decides how to present each field (label placement,
wrapper elements, error styles, etc.).

Usage:
TextField::create('first_name')
->label('Voornaam')
->placeholder('Jan')
->required();

21 public methods
addValidator(\ValidatorInterface $validator): static
static create(string $name): static
defaultValue(string $value): static
disabled(bool $disabled = true): static
getConditional(): \ConditionalRule|\CompositeRule|null
getConditionalJson(): ?string

Serialise the conditional rule to the JSON format used by form-enhanced.js.
Returns null when no conditional is set.

getDefaultValue(): string
getHint(): string
getLabel(): string
getPlaceholder(): string
getValidators(): array
hasConditional(): bool
hint(string $hint): static

A short helper text shown below the field input.
Example: hint('Gebruik uw zakelijk e-mailadres')

isComposite(): bool

Composite fields hebben sub-inputs (`name[part]`) en eigen render-/validate-pad.
Default = false; CompositeFieldInterface-implementations overschrijven.

isDisabled(): bool
isRequired(): bool
label(string $label): static
placeholder(string $placeholder): static
required(bool $required = true): static
showWhen(\ConditionalRule|\CompositeRule $rule): static

Mark this field as conditionally visible.

Example — show only when another field equals a certain value:
->showWhen(ConditionalRule::whenEqual('type', 'business'))

Example — show when multiple conditions are met:
->showWhen(CompositeRule::all(
ConditionalRule::whenEqual('type', 'business'),
ConditionalRule::whenEqual('region', 'nl'),
))

validate(string $value, array $allValues = array ( )): array

Run all validators against $value.
Returns a list of error messages (empty = valid).

AddressField

Framework\Form\Field\AddressField
final class

Composite veld voor postadressen.
Submit-shape: `<name>[street]`, `<name>[number]`, `<name>[zipcode]`,
`<name>[city]`, en optioneel `<name>[country]`.

Default-opmaak: NL — postcode + plaats op één regel, daaronder straat + nr.

7 public methods
getDefaultCountry(): string
getIncludeCountry(): bool
getParts(): array
includeCountry(bool $on = true, string $default = 'NL'): static
isComposite(): bool
renderComposite(array $value = array ( )): string
validateComposite(array $value, array $allValues = array ( )): array

CheckboxField

Framework\Form\Field\CheckboxField
final class

A single <input type="checkbox">.

Het label naast de checkbox wordt gezet via {@see checkboxLabel()}. Dat
kan ofwel een plain string zijn (auto-escaped) ofwel een {@see NodeInterface}
(El, ElCollection, fragment) — handig om links in te bouwen, bv:

CheckboxField::create('terms')
->checkboxLabel(El::fragment()
->text('Ik accepteer de ')
->add(El::make('a', ['href' => '/voorwaarden'])->text('algemene voorwaarden'))
);

Voor het veelvoorkomende "tekst — link — tekst"-patroon is er de helper
{@see checkboxLabelWithLink()} zodat je geen El-builder hoeft te kennen.

3 public methods
checkboxLabel(\NodeInterface|string $label): static

Stel het label naast de checkbox in. String is plain-text (auto-escaped).
NodeInterface wordt rendered as-is — gebruik dat voor inline-links of formatting.

checkboxLabelWithLink(string $prefix, string $href, string $linkText, string $suffix = '', bool $external = true): static

Convenience: tekst met één inline-link (en optioneel een suffix).

->checkboxLabelWithLink('Ik accepteer de ', '/terms', 'algemene voorwaarden', '.')
→ Ik accepteer de [algemene voorwaarden](/terms).

`$external = true` voegt `target="_blank"` + `rel="noopener noreferrer"` toe.

getCheckboxLabel(): \NodeInterface|string

CompositeFieldInterface

Framework\Form\Field\CompositeFieldInterface
interface

Marker-interface voor velden die uit meerdere sub-inputs bestaan.

Een composite field heeft één naam in het schema (`klantnaam`) maar levert
server-side meerdere `<input>`-tags op (`klantnaam[first]`, `klantnaam[last]`,
etc.). De submit-data komt binnen als geneste array.

Form::process() en validators behandelen composites anders dan atomic-velden:
- $values[$name] is een array, niet een string
- validate() krijgt de array door, niet trim() of (string)cast

Render: composites leveren hun eigen `renderComposite(): string` die de
sub-inputs in één wrapper plaatst. FormRenderer delegeert daaraan.

3 public methods
getParts(): array

Returnt de sub-veld-namen + labels.

renderComposite(): string

Render de complete composite-input (sub-inputs in een wrapper).
Output is HTML-string die door FormRenderer rechtstreeks ingevoegd wordt.

validateComposite(array $value, array $allValues = array ( )): array

Validate sub-data (ipv één string-value). Returns lijst foutmeldingen.

Countries

Framework\Form\Field\Countries
final class

Centrale landen-lijst voor zowel het losse `country`-type
(CountryField via FormFactory) als de `address.country` sub-velden.

Sleutels = ISO-3166-1 alpha-2 codes (uppercase).
Labels = NL-talige landnaam.

Niet uitputtend — meest gebruikte landen + EU. Caller kan eigen lijst
opgeven via `options()` op SelectField of `salutationOptions()`-achtige
setters in andere fields.

2 public methods
static codes(): array
static defaults(): array

CreditCardField

Framework\Form\Field\CreditCardField
final class

Composite veld voor creditcard-invoer.

Submit-shape: `<name>[number]`, `<name>[expiry]`, `<name>[cvc]`.

Geen pretentie van PCI-compliance — bedoeld als front-end widget;
gevoelige data hoort sowieso niet door de eigen server te gaan, gebruik
een payment-provider tokenisatie. We valideren format (Luhn-check op
card-number, MM/YY-format, 3-4-cijfer cvc).

4 public methods
getParts(): array
isComposite(): bool
renderComposite(array $value = array ( )): string
validateComposite(array $value, array $allValues = array ( )): array

DateField

Framework\Form\Field\DateField
final class

Single-date field. Form-value is altijd ISO `YYYY-MM-DD` (of
`YYYY-MM-DDTHH:MM` als time enabled is). De zichtbare display
komt van de JS-component `public/modules/date-picker.js` en
volgt de actieve locale (of de format-override).

DateField::create('birthdate')
->label('Geboortedatum')
->min('1900-01-01')
->max(date('Y-m-d'))
->locale('nl-NL')
->months(1);

22 public methods
dataAttributes(): array

Bouw de data-attributen voor de wrapper-div (gebruikt door FormRenderer).

defaultPattern(?string $key): static
format(?string $token): static
getDefaultPattern(): ?string
getFormat(): ?string
getLocale(): ?string
getMax(): ?string
getMaxMonths(): int
getMin(): ?string
getMonths(): int
getMonthsMobile(): int
getPatterns(): array
getTimeStep(): int
isTimeEnabled(): bool
locale(?string $code): static
max(?string $iso): static
maxMonths(int $count): static
min(?string $iso): static
months(int $count): static
monthsMobile(int $count): static
patterns(array $patterns): static
withTime(bool $enabled = true, int $stepMinutes = 15): static

DateRangeField

Framework\Form\Field\DateRangeField
final class

Range-date field — twee form-velden (from + till) onder één UI.

DateRangeField::create('stay')
->from('checkin', 'Aankomst')
->till('checkout', 'Vertrek')
->min('2026-01-01')
->max('2027-12-31')
->locale('nl-NL')
->months(2)
->patterns([
['key' => 'weekend', 'label' => 'Weekend', 'anchor' => [5,6,0], 'nights' => 3],
['key' => 'week', 'label' => 'Week', 'anchor' => [5,6,0], 'nights' => 7],
]);

AbstractField->name wordt gebruikt voor de wrapper-id en als prefix voor de
input-namen wanneer from()/till() niet expliciet geset zijn.

28 public methods
dataAttributes(): array
defaultPattern(?string $key): static
format(?string $token): static
from(string $name, string $label = ''): static
getDefaultPattern(): ?string
getFormat(): ?string
getFromLabel(): string
getFromName(): string
getLocale(): ?string
getMax(): ?string
getMaxMonths(): int
getMin(): ?string
getMonths(): int
getMonthsMobile(): int
getPatterns(): array
getTillLabel(): string
getTillName(): string
getTimeStep(): int
isTimeEnabled(): bool
locale(?string $code): static
max(?string $iso): static
maxMonths(int $count): static
min(?string $iso): static
months(int $count): static
monthsMobile(int $count): static
patterns(array $patterns): static
till(string $name, string $label = ''): static
withTime(bool $enabled = true, int $stepMinutes = 15): static

EmailField

Framework\Form\Field\EmailField
final class
__construct(string $name)

MultiCheckboxField

Framework\Form\Field\MultiCheckboxField
final class

Een groep checkboxes — meerdere selecties tegelijk mogelijk.

Submit-shape: `<name>[]` (PHP-stijl array). FormResult slaat 'm op als
array van geselecteerde waarden, vergelijkbaar met een composite maar
platter (geen vaste sub-keys, alle items horen tot dezelfde lijst).

In het JSON-schema:
{ "type": "multicheckbox", "name": "talen", "options": {"nl": "Nederlands", ...} }

Niet `composite: true` — gebruikt z'n eigen render-pad maar de submit-data
is een homogene array van strings, niet een geneste struct met sub-keys.

2 public methods
getOptions(): array
options(array $options): static

PersonalNameField

Framework\Form\Field\PersonalNameField
final class

Composite veld voor persoonsnamen.

Submit-shape:
`<name>[first]`, `<name>[middle]`, `<name>[last]`
en optioneel `<name>[salutation]` als `includeSalutation()` aan staat.

Gebruik:
PersonalNameField::create('klantnaam')
->includeSalutation(true)
->required();

In het JSON-schema:
{ "type": "personalname", "name": "klantnaam", "includeSalutation": true }

8 public methods
getIncludeSalutation(): bool
getParts(): array
getSalutationOptions(): array
includeSalutation(bool $on = true): static
isComposite(): bool
renderComposite(array $value = array ( )): string
salutationOptions(array $options): static
validateComposite(array $value, array $allValues = array ( )): array

PhoneNumberField

Framework\Form\Field\PhoneNumberField
final class

Telefoonnummer — atomisch text-veld met `type=tel` en optionele
format-validatie per language. Geen composite (geen sub-velden); de
country-prefix is gewoon onderdeel van de tekstwaarde.

3 public methods
getLanguage(): string
language(string $code): static
validate(string $value, array $allValues = array ( )): array

RadioField

Framework\Form\Field\RadioField
final class

A group of <input type="radio"> buttons.

Example:
RadioField::create('type')
->label('Account type')
->options(['private' => 'Particulier', 'business' => 'Zakelijk']);

2 public methods
getOptions(): array
options(array $options): static

ReCaptchaField

Framework\Form\Field\ReCaptchaField
final class

Form-field voor Google reCAPTCHA. Drie modi:

ReCaptchaField::create()->siteKey('6Lc...')->mode(ReCaptchaMode::V2_CHECKBOX);
ReCaptchaField::create()->siteKey('6Lc...')->mode(ReCaptchaMode::V3)->action('contact');

De FormRenderer plaatst een placeholder-div (`.g-recaptcha`) en zorgt dat
de Google API geladen wordt. Server-side verificatie gebeurt apart via
{@see \Framework\Security\ReCaptcha\ReCaptchaVerifier} — dit veld zelf
doet alleen de UI.

De default `name` is `g-recaptcha-response` (Google's eigen veld).

13 public methods
action(string $action): static

v3-only — actienaam die je meegeeft aan grecaptcha.execute().

static create(string $name = 'g-recaptcha-response'): static
getAction(): ?string
getLocale(): string
getMode(): \ReCaptchaMode
getSiteKey(): string
getSize(): string
getTheme(): string
locale(string $locale): static
mode(\ReCaptchaMode $mode): static
siteKey(string $key): static
size(string $size): static
theme(string $theme): static

SelectField

Framework\Form\Field\SelectField
final class

A `<select>` field.

Default krijgt het veld de `data-mm-select` attribuut, waardoor
`public/modules/custom-select.js` 'm automatisch upgraded naar
een dropdown met search + keyboard navigation. Per veld uit te
zetten met `->customSelect(false)`.

SelectField::create('country')
->label('Land')
->options(['nl' => 'Nederland', 'be' => 'België'])
->placeholder('Kies een land…')
->searchMode('always') // 'auto' | 'always' | 'never'
->searchThreshold(8); // toon search vanaf N opties (mode auto)

8 public methods
customSelect(bool $enabled = true): static

Schakel de custom-select-upgrade in/uit voor dit veld.

getOptions(): array
getSearchMode(): string
getSearchThreshold(): int
isCustomSelect(): bool
options(array $options): static
searchMode(string $mode): static

'auto' | 'always' | 'never' — wanneer de search-input getoond wordt.

searchThreshold(int $n): static

Aantal opties vanaf waar 'auto' search toont.

TextField

Framework\Form\Field\TextField
final class
2 public methods
getType(): string
type(string $type): static

Override HTML input type (e.g. 'password', 'tel', 'url', 'search').

TextareaField

Framework\Form\Field\TextareaField
final class
2 public methods
getRows(): int
rows(int $rows): static

ZipcodeField

Framework\Form\Field\ZipcodeField
final class

Postcode-veld met optionele "afstand tot"-dropdown.

- Atomic mode: één tekstveld met regex-validatie per language.
- Composite mode (`withDistance(true)`): tekstveld + select met km-keuzes.

Submit-shape:
- zonder distance: `<name>` = "1234 AB"
- met distance: `<name>[code]` = "1234 AB", `<name>[distance]` = "10"

11 public methods
distances(array $km): static
getDistances(): array
getLanguage(): string
getParts(): array
getWithDistance(): bool
isComposite(): bool
language(string $code): static
renderComposite(array $value = array ( )): string
validate(string $value, array $allValues = array ( )): array
validateComposite(array $value, array $allValues = array ( )): array
withDistance(bool $on = true): static

Form

Framework\Form\Form
final class

A form definition — an ordered collection of fields and layout rows.

Usage with plain fields:
$form = Form::create('contact', '/contact/submit')
->add(TextField::create('name')->label('Naam'))
->add(EmailField::create('email')->label('E-mail'));

Usage with side-by-side layout:
$form = Form::create('registratie', '/submit')
->add(FieldRow::of(
SelectField::create('land')->label('Land'),
TextField::create('telefoon')->label('Telefoonnummer'),
))
->add(FieldRow::of($postcode, $plaats)->widths([1, 2]));

$result = $form->process($_POST);

6 public methods
add(\FormElementInterface $element): self

Add a field or a FieldRow (side-by-side layout).

static create(string $id, string $action = '', string $method = 'POST'): self
getElements(): array
getField(string $name): ?\AbstractField
getFields(): array
process(array $data): \FormResult

Validate submitted data against all field definitions.

Fields hidden by a conditional rule (given the submitted values)
are skipped entirely — their values are not validated.

FormElementInterface

Framework\Form\FormElementInterface
interface

Marker interface for anything that can be added to a Form.

Both AbstractField and FieldRow implement this, so Form::add()
accepts either without losing type safety.

FormFactory

Framework\Form\FormFactory
final class

Builds a Form from a JSON schema string (typically stored in the database
by the CMS form editor).

This is the bridge between CMS storage and the PHP Form Builder renderer.
The renderer knows nothing about JSON; the CMS knows nothing about PHP classes.

Usage:
$form = FormFactory::fromJson($jsonFromDatabase);
$html = (new FormRenderer())->render($form, $result);

Schema shape:
{
"id": "contact",
"action": "/contact/submit",
"method": "POST", // optional, default POST
"elements": [
{
"type": "field",
"field": { ... }
},
{
"type": "row",
"widths": [1, 2], // optional, CSS fr units
"conditional": { ... }, // optional, row-level
"fields": [ { ... }, ... ]
}
]
}

Field shape:
{
"type": "text|email|textarea|select|checkbox|radio",
"name": "field_name",
"label": "Label tekst", // optional
"placeholder": "...", // optional
"hint": "Hulptekst", // optional
"default": "standaard waarde", // optional
"required": true, // optional
"disabled": false, // optional
"options": {"value": "Label"}, // select / radio only
"rows": 4, // textarea only
"inputType": "password", // text only, overrides type attr
"checkboxLabel": "Ik ga akkoord", // checkbox only
"validators": [ ... ], // optional
"conditional": { ... } // optional, field-level
}

Validator shapes:
{"type": "required"}
{"type": "minLength", "min": 2}
{"type": "maxLength", "max": 255}
{"type": "email"}
{"type": "regex", "pattern": "/^[0-9]+$/", "message": "{label} mag alleen cijfers bevatten."}

Conditional shapes (single):
{"field": "type", "operator": "equal", "value": "zakelijk"}

Conditional shapes (composite):
{"logic": "and", "rules": [ {...}, {...} ]}
{"logic": "or", "rules": [ {...}, {...} ]}

2 public methods
static fromArray(array $data): \Form

Build a Form from an already-decoded array.
Useful when the JSON was decoded upstream (e.g. already fetched from DB).

static fromJson(string $json): \Form

Parse a JSON string and return a fully wired Form object.

FormRenderer

Framework\Form\FormRenderer
class

Renders a Form definition into an El tree.

The renderer is the only place where HTML presentation decisions are made.
Fields know nothing about HTML; FormRenderer knows nothing about validation
rules — it only reads field metadata.

1 public method
render(\Form $form, ?\FormResult $result = NULL): string

FormResult

Framework\Form\FormResult
final class

Immutable result of Form::process().

Usage:
$result = $form->process($_POST);

if ($result->isValid()) {
$name = $result->value('name'); // atomic veld
$email = $result->value('email');
$klant = $result->valueArray('klantnaam'); // composite veld
}

$errors = $result->errorsFor('email'); // string[]

__construct(array $values, array $errors)
7 public methods
allErrors(): array
allValues(): array
errorsFor(string $field): array
hasErrors(string $field): bool
isValid(): bool
value(string $field, string $default = ''): string

Returns een atomic-value als string. Voor composites: gebruik valueArray().
Composite-waarden vallen terug op `$default` als je ze als string leest.

valueArray(string $field, array $default = array ( )): array

Returns een composite-value als geneste array. Atomic-waarden vallen
terug op `$default`.

FieldRow

Framework\Form\Layout\FieldRow
final class

Groups fields side-by-side in a CSS grid row.

Basic usage — equal columns:
FieldRow::of(
SelectField::create('land')->label('Land'),
TextField::create('telefoon')->label('Telefoonnummer'),
)

Custom column widths (CSS fr units):
FieldRow::of($postcode, $plaats)->widths([1, 2])
// → "1fr 2fr" — postcode ≈ 1/3, plaats ≈ 2/3

The whole row can be conditionally hidden:
FieldRow::of($vat, $chamber)->showWhen(ConditionalRule::whenEqual('type', 'zakelijk'))

Responsive: on screens narrower than 640 px the columns collapse to a
single stack — no extra config needed, the CSS handles it.

7 public methods
getConditionalJson(): ?string
getFields(): array
getGridTemplateColumns(): string

CSS grid-template-columns value.
Falls back to "repeat(N, 1fr)" when no custom widths are set.

hasConditional(): bool
static of(\AbstractField ...$fields = ?): self

Create a row with equal-width columns.

showWhen(\ConditionalRule|\CompositeRule $rule): self

Hide/show the entire row based on another field's value.

widths(array $fractions): self

Set custom column proportions in CSS fr units.

Example: ->widths([1, 2]) produces "1fr 2fr"
(first column gets 1/3 of the space, second gets 2/3)

Must contain the same number of values as there are fields.

ConditionalValidator

Framework\Form\Validator\ConditionalValidator
final class

Decorator that wraps another ValidatorInterface and only delegates to it
when a `when`-rule evaluates true against the other submitted values.

This is what makes "verplicht als type=zakelijk" possible without changing
the inner validator. Used by FormFactory when a validator definition has
a `when`-clausule in its JSON-shape.

__construct(\ValidatorInterface $inner, \ConditionalRule|\CompositeRule $when, \RuleEvaluator $evaluator = \Framework\Form\Conditional\RuleEvaluator::__set_state(array( )))
1 public method
validate(string $value, string $label, array $allValues = array ( )): ?string

EmailValidator

Framework\Form\Validator\EmailValidator
final class
1 public method
validate(string $value, string $label, array $allValues = array ( )): ?string

MaxLengthValidator

Framework\Form\Validator\MaxLengthValidator
final class
__construct(int $max)
1 public method
validate(string $value, string $label, array $allValues = array ( )): ?string

MinLengthValidator

Framework\Form\Validator\MinLengthValidator
final class
__construct(int $min)
1 public method
validate(string $value, string $label, array $allValues = array ( )): ?string

ReCaptchaValidator

Framework\Form\Validator\ReCaptchaValidator
final class

Server-side validator voor een reCAPTCHA-token.

$form->add(ReCaptchaField::create()->siteKey($siteKey))
->validator('g-recaptcha-response',
new ReCaptchaValidator(
verifier: new ReCaptchaVerifier($secretKey),
remoteIp: $kernel->request->clientIp(),
));

Voor v3: geef `minScore` mee (default 0.5).

`remoteIp` is optioneel — Google accepteert het verzoek ook zonder, maar
met IP is de risk-scoring iets accurater. Geef 'm bij voorkeur door uit
`ServerRequest::clientIp()`.

__construct(\ReCaptchaVerifier $verifier, ?string $remoteIp = NULL, float $minScore = 0.5, string $message = 'Captcha-validatie mislukt.')
1 public method
validate(string $value, string $label, array $allValues = array ( )): ?string

RegexValidator

Framework\Form\Validator\RegexValidator
final class
__construct(string $pattern, string $message)
1 public method
validate(string $value, string $label, array $allValues = array ( )): ?string

RequiredValidator

Framework\Form\Validator\RequiredValidator
final class
1 public method
validate(string $value, string $label, array $allValues = array ( )): ?string

ValidatorInterface

Framework\Form\Validator\ValidatorInterface
interface

A field validator.

Returns null on success, or a human-readable error message on failure.

1 public method
validate(string $value, string $label, array $allValues = array ( )): ?string