Skip to main content

Field behavior

Behavior beyond a static value is declared on the field itself: a dynamic default, validation and a value transform, each a closure right in the form:

use DrevOps\Tui\Handler\Context;

$p->text('name', 'Produce name')
->default(fn(Context $c): string => basename($c->directory))
->validate(fn(mixed $v): ?string => is_string($v) && trim($v) !== '' ? NULL : 'A name is required.')
->transform(fn(mixed $v): mixed => is_string($v) ? trim($v) : $v);

Reusable validators and transformers live as public static methods on a class in your code. Reference one explicitly with a first-class callable - ->validate(Ripeness::validate(...)) - or let the engine discover it: register a namespace (new Tui($form, handler_namespaces: ['App\\Handler'])) and the engine resolves the class by field id (red_apple -> RedApple), using its static validate()/transform() whenever the field declares none. When both exist, the field declaration wins.

The TUI only collects. It presents answers and never applies them - writing files, renaming directories, acting on the answers is your job. A consumer that processes answers defines its own processor interface, keeping the form for collection and the processors for side effects; one class per field can carry both its process() and the reusable static behavior. (This is exactly what a consumer CLI does.)

Both declaration styles are runnable in playground/06-field-behaviour-*.

Discovery

In update mode, ->discover() rules detect defaults from an existing project directory: a .env key (new Dotenv('SEASON')), a JSON dot-path (new JsonValue('basket.json', 'name')), a path check (new PathExists('harvest.csv')), a directory scan (new Scan('baskets', type: ScanType::Dir)), or a custom fn(Context $c): mixed closure:

$p->text('name', 'Produce name')->discover(new JsonValue('basket.json', 'name'));
$p->confirm('inseason', 'In season?')->discover(new PathExists('harvest.csv'));

Discovered values are badged in the summary, and explicit input (prompts or environment) always beats discovery:

Discovery summary with provenance badgesDiscovery summary with provenance badges

Every rule type runs against a bundled sample project in playground/07-discovery.php.