Architecture¶
The package is built from a few parts, each with one job. Knowing them helps when you extend it.
Form ─────────── holds the data, runs validation, owns the errors
├─ fields ───── a flat list, by name: definitions, no data, no HTML
├─ layout ───── a tree of rows and fieldsets that refers to fields by name
├─ Renderer ─── turns fields and layout into HTML using a theme's views
└─ Config ───── settings and themes (app/Config/Forms.php)
Schemas ──────── SchemaLoader builds a Form from data, checked by a SchemaPolicy;
SchemaExporter turns a Form back into data
Forms¶
Form is the object your controllers and views use. It knows its fields and
layout, holds the data it works with (the submission, old input, filled data),
runs validation and keeps the errors. A form class is simply a Form whose
define() adds fields.
Fields¶
A field only describes itself: its name, label, rules, options and attributes. It holds no submitted value and produces no HTML. This keeps fields small, easy to test and easy to write yourself.
Fields implement FieldInterface, and optional interfaces add abilities:
| Interface | Gives a field |
|---|---|
ChoiceFieldInterface |
Strict option checking against getAllowedValues() |
FileFieldInterface |
Upload handling: never in validated(), makes the form multipart |
PresentableFieldInterface |
A readable display of stored values for present() |
SchemaConfigurableInterface |
Extra keys in schemas, and their export |
Extending Field or InputField gives a custom field the common behaviour
and PresentableFieldInterface.
Layout¶
Fields are kept in one flat list, so values, validation, validated() and
field('name') never depend on where a field appears. Rows and fieldsets form
a separate tree that refers to fields by name, and only the renderer reads it.
Changing a form's layout can never change what it accepts.
Rendering and themes¶
The Renderer prepares everything a field needs (its value, errors, classes
and escaped attributes) and passes it to the active theme's view for that
field type. Views contain only markup, which is why they are easy to copy and
change.
A template is looked up in the active theme's folder, then in the package's bundled copy of a theme with the same name, then the same for the theme it extends. This is how published views keep working after an upgrade adds new templates, and how a theme can override only the templates it changes.
Schemas¶
SchemaLoader builds a form from a schema in two passes. First it builds the
whole schema on a scratch form, collecting every error with its location; only
when there are none does it build the real form. Validation and building run
the same code, so they cannot disagree, and a schema with errors never produces
part of a form.
SchemaPolicy decides what a schema may contain. SchemaExporter turns a form
back into a schema, and FormSchema::describe() reports what a policy allows,
using the loader's own lists of keys.
Support classes¶
| Class | Job |
|---|---|
RuleParser |
Splits CodeIgniter rule strings, keeping | inside brackets |
FieldTypes |
Maps type names to field classes, built-in and registered |
OptionProviders |
Checks and calls registered option providers |
ViewPublisher |
Copies theme views into an app for forms:publish |