Ricardo Sanz
Drupal Developer y DevOps
Open/Free Software and weird music
drupal.org/u/tunic
- The Form API
- Simplified workflow
- Form API stages
- Cache / Persistence
- AJAX requests
- Complete workflow
- Key points
- An abstraction of HTML forms
- Handles submit, persistence, altering and rendering
- Security!
- Handles AJAX in forms
- Allows alterations
- Safety!
- Build custom forms
- "form_builder" service handles forms
- Many classes involved: FormBuilder, FormValidator, FormBase, etc.
- A class that implements
\Drupal\Core\Form\FormInterface
- Usually extends
Drupal\Core\Form\FormBase
- A form array (usually $form)
- A form state (usualy $form_state)
- PHP array
- Structure and behavior
- Not exactly a Render Array
- Available during all Form API stages
- It is changed during stages
- Usually a Drupal\Core\Form\FormState instance
- Implements Drupal\Core\Form\FormStateInterface
- Contains state of the form
- Available during all Form API stages
- It is changed during stages
- form_id: the form (like a class)
- form_build_id: the specific form build (like an instance)
- Token: ensures form was previously requested
Simplified Form API workflow diagrams
On each request new form element appears
Response can be:
- Markup
- Redirection
- A rebuilt form
- A form with errors
- Whatever submits decide
- How Drupal handles security?
- How Drupal keeps track of data between requests?
- How is AJAX handled?
- Validation in detail
- Submission in detail
- Rebuilding in detail
- Workflow details
Form API stages
Retrieve and prepare (1/5)
- Form build function
- Dynamic elems depends on $form_state
- On rebuild: form is built again here
- Build id added
- Security token added for registered users (prevent CSRF)
- Alter hooks!
- First place to customize an existing form
- A built form
- All dynamics elements in place
- All altertions in place
- This is the unprocessed form
Form API stages
Recursive building (2/5)
- Goals
- Get a renderable array
- Collect input values (defaults or sent by user)
- Detect triggering button (if any)
- Detect which validate handler to run
- Last chance to modify/tweak the form
- Process callback
- After build callback
- Not standard alters!
- Called top-bottom
- Allow for elements to expand to multiple elements
- More than 100 uses in core
- You may need, specially for custom elems
- Example: adding JS conditionally on field value
- Called bottom-to-top
- Less than 10 uses in core
- Unlikely you need it
- Example: removing elements after file disk check
Validation
- Button pressed
if not then
- Form-level validate
Submit
- Button pressed
if not then
- Form-level submit
Form API stages
Validation (3/5)
Form is checked (security and valid values)
- Check token (prevents CSRF)
- Validate all elems bottom-to-top
- Call elem's validate, if any
- Validate form (button or form handler)
- Can change $form or $form_state for next rebuild
- Can enable rebuilding
- Errors are added to rendered form
- Submit handlers are skipped
- Rebuilding is forbidden
Form API stages
Submit (4/5)
Form is executed, running any needed actions
- Run submit handlers (button or form)
- Return response, if any
- Usually a redirect or markup is delivered
- Can change $form or $form_state for next rebuild
- Can enable rebuilding
Form API stages
Rebuild (5/5)
Rebuilding allows for complex forms
- Multi-step forms
- Dynamic elements (adding, removing, etc)
- AJAX calls that modifies form
- Runs building steps (retrieve, prepare and actual building)
- Changes in $form and $form_state allow form changes when rebuilt
- Named "cache" but it is persistence + cache
- Allows for AJAX, mutistep and dynamic elements
- Usually Drupal takes care of it (auto-enabled)
- You may need to deal with it in special cases
- $form and $form_state are saved
-
$form_state only given set of properties (see FormState::getCacheableArray)
- Use FormState's functions to CRUD data that will be cached/persisted
- They follow the same workflow
- They return what #ajax_callback returns
- They need cache/persistence (auto-enabled)
- They can also return one or more AJAX commands
- Element triggers an AJAX request
- Form is build, validated and executed
- During submit, some values are changed and rebuild enabled
- During rebuild, these changed values cause the form to undergo changes (e.g.: more or less elements)
- #ajax_callback returns changed part of the form, the form or AJAX commands
- JS layer takes reponse and processes it (e.g: inserts markup into the HMTL)
- Don't change $form during #ajax_callback
- #ajax_callback is not a submit, it is a result gatherer!
- Any change should be done during rebuilding
The complete workflow illustration
Not the whole picture
- Batch and programmed forms are not covered
- Subforms
- Details
- How HTML id are handled
- Some edge cases
- Security details
- More details
- Form's build function and alters for big changes
- Process and after builds callbacks for adjustments and tweaks
- Use the rebuilding loop for dynamic forms
- Use FormSate to store your own variables
- Use #ajax_callback to return response, not to change the form
- Check Drupal Examples module!