Skip to content

FormControl

Viames Marino edited this page Feb 26, 2026 · 2 revisions

Pair framework: FormControl

Pair\Html\FormControl is the abstract base class for all Pair form controls (Text, Email, Select, Textarea, Checkbox, etc.).

It centralizes:

  • HTML attribute composition
  • value/label metadata
  • client+server validation flags (required, lengths, pattern)
  • common rendering helpers used by subclasses

Constructor

new FormControl(string $name, array $attributes = [])

Behavior:

  • If name ends with [], Pair strips the suffix and automatically enables array mode (arrayName = true).
  • Custom attributes passed in constructor are stored in $attributes and rendered later.

Core fluent API

Identity and metadata:

  • id(string $id): static
  • label(string $label): static
  • labelClass(string $class): static
  • description(string $description): static
  • caption(string $caption): static (only for Button, Meter, Progress, Textarea)

State:

  • required(bool $required = true): static
  • disabled(bool $disabled = true): static
  • readonly(bool $readonly = true): static
  • value(string|int|float|DateTime|null $value): static

Input rules:

  • minLength(int $length): static
  • maxLength(int $length): static
  • pattern(string $pattern): static
  • placeholder(string $placeholder): static
  • inputmode(string $mode): static
  • autofocus(bool $autofocus = true): static

Attribute helpers:

  • class(string|array $class): static
  • data(string $name, string $value): static
  • aria(string $name, string $value): static
  • title(string $title): static
  • form(string $formId): static
  • arrayName(): static

Output and validation:

  • render(): string (abstract, implemented by concrete controls)
  • validate(): bool
  • print(): void
  • printLabel(): void
  • __toString(): string (delegates to render())

Allowed/blocked method matrix

FormControl enforces some API restrictions.

caption(...) allowed only on:

  • Button
  • Meter
  • Progress
  • Textarea

pattern(...) allowed only on:

  • Text
  • Search
  • Tel
  • Email
  • Password
  • Url

placeholder(...) is blocked on:

  • Checkbox
  • Radio
  • File
  • Color
  • Range
  • Hidden

aria(...) is ignored (no exception) on:

  • Hidden
  • File
  • Image

inputmode(...) is ignored (no exception) on:

  • Button, Checkbox, Color, Date, Datetime, File, Hidden, Image, Month, Password, Select, Textarea, Time

Rendering internals used by subclasses

Protected helpers:

  • nameProperty(): string builds safe name="..." (with [] when array mode is active)
  • processProperties(): string appends common HTML attributes
  • renderInput(string $type): string builds default <input> markup for simple controls

processProperties() currently handles:

  • id, required, disabled, readonly, placeholder, pattern, CSS class
  • all key/value attributes in $attributes

required HTML attribute is not printed for Checkbox and Radio.

Label generation

getLabelText() behavior:

  • if label is not set, Pair derives it from field name (userEmail -> User Email)
  • if label is uppercase and longer than 3 chars, it is treated as translation key (Translator::do(...))
  • otherwise, raw label text is used

printLabel() adds:

  • <span class="required-field">...</span> when field is required and not disabled/readonly
  • optional tooltip icon when description(...) is set

Validation behavior

Default validate() checks POST value (Post::get($this->name)) and validates:

  • required not empty
  • min length
  • max length

Failures are logged through Logger and return false.

Concrete controls may override validate() (for example Email, Url, Number, Select, etc.).

Practical examples

Basic text field:

$title = (new \Pair\Html\FormControls\Text('title'))
    ->label('Title')
    ->required()
    ->minLength(3)
    ->maxLength(120)
    ->placeholder('Insert title')
    ->class(['form-control', 'form-control-lg']);

echo $title->render();

Array-style values:

$tags = (new \Pair\Html\FormControls\Text('tags[]'))
    ->arrayName()
    ->placeholder('Tag');

Button caption (allowed) vs text caption (not allowed):

$save = (new \Pair\Html\FormControls\Button('save'))->caption('Save');

// This throws AppException:
// (new \Pair\Html\FormControls\Text('name'))->caption('X');

Notes and caveats

  • class('a b') is treated as one class string; use class(['a', 'b']) to add multiple classes explicitly.
  • title(...) currently applies to all controls (the internal unsupported list is declared but not enforced).
  • __get() throws AppException when property does not exist (ErrorCodes::PROPERTY_NOT_FOUND).

See also: Form, FormControls, Post, Translator.

Clone this wiki locally