Use folder structure instead of underscores in filenames
[GitHub/WoltLab/woltlab.github.io.git] / docs / php / api / form_builder-validation_data.md
1 # Form Validation and Form Data
2
3 ## Form Validation
4
5 Every form field class has to implement `IFormField::validate()` according to their internal logic of what constitutes a valid value.
6 If a certain constraint for the value is no met, a form field validation error object is added to the form field.
7 Form field validation error classes have to implement the interface `IFormFieldValidationError`.
8
9 In addition to intrinsic validations like checking the length of the value of a text form field, in many cases, there are additional constraints specific to the form like ensuring that the text is not already used by a different object of the same database object class.
10 Such additional validations can be added to (and removed from) the form field via implementations of the `IFormFieldValidator` interface.
11
12
13 ### `IFormFieldValidationError` / `FormFieldValidationError`
14
15 `IFormFieldValidationError` requires the following methods:
16
17 - `__construct($type, $languageItem = null, array $information = [])` creates a new validation error object for an error with the given type and message stored in the given language items.
18 The information array is used when generating the error message.
19 - `getHtml()` returns the HTML element representing the error that is shown to the user.
20 - `getMessage()` returns the error message based on the language item and information array given in the constructor.
21 - `getInformation()` and `getType()` are getters for the first and third parameter of the constructor.
22
23 `FormFieldValidationError` is a default implementation of the interface that shows the error in an `small.innerError` HTML element below the form field.
24
25 Form field validation errors are added to form fields via the `IFormField::addValidationError(IFormFieldValidationError $error)` method.
26
27
28 ### `IFormFieldValidator` / `FormFieldValidator`
29
30 `IFormFieldValidator` requires the following methods:
31
32 - `__construct($id, callable $validator)` creates a new validator with the given id that passes the validated form field to the given callable that does the actual validation.
33 `static validateId($id)` is used to check if the given id is valid.
34 - `__invoke(IFormField $field)` is used when the form field is validated to execute the validator.
35 - `getId()` returns the id of the validator.
36
37 `FormFieldValidator` is a default implementation of the interface.
38
39 Form field validators are added to form fields via the `addValidator(IFormFieldValidator $validator)` method.
40
41
42 ## Form Data
43
44 After a form is successfully validated, the data of the form fields (returned by `IFormDocument::getData()`) have to be extracted which is the job of the `IFormDataHandler` object returned by `IFormDocument::getDataHandler()`.
45 Form data handlers themselves, however, are only iterating through all `IFormDataProcessor` instances that have been registered with the data handler.
46
47
48 ### `IFormDataHandler` / `FormDataHandler`
49
50 `IFormDataHandler` requires the following methods:
51
52 - `addProcessor(IFormDataProcessor $processor)` adds a new data processor to the data handler.
53 - `getFormData(IFormDocument $document)` returns the data of the given form by applying all registered data handlers on the form.
54 - `getObjectData(IFormDocument $document, IStorableObject $object)` returns the data of the given object which will be used to populate the form field values of the given form.
55
56 `FormDataHandler` is the default implementation of this interface and should also be extended instead of implementing the interface directly.
57
58
59 ### `IFormDataProcessor` / `DefaultFormDataProcessor`
60
61 `IFormDataProcessor` requires the following methods:
62
63 - `processFormData(IFormDocument $document, array $parameters)` is called by `IFormDataHandler::getFormData()`.
64 The method processes the given parameters array and returns the processed version.
65 - `processObjectData(IFormDocument $document, array $data, IStorableObject $object)` is called by `IFormDataHandler::getObjectData()`.
66 The method processes the given object data array and returns the processed version.
67
68 When `FormDocument` creates its `FormDataHandler` instance, it automatically registers an `DefaultFormDataProcessor` object as the first data processor.
69 `DefaultFormDataProcessor` puts the save value of all form fields that are available and have a save value into `$parameters['data']` using the form field’s object property as the array key.
70
71 !!! warning "`IFormDataProcessor` should not be implemented directly. Instead, `AbstractFormDataProcessor` should be extended."
72
73 !!! info "All form data is put into the `data` sub-array so that the whole `$parameters` array can be passed to a database object action object that requires the actual database object data to be in the `data` sub-array."
74
75
76
77 ### Additional Data Processors
78
79 #### `CustomFormDataProcessor`
80
81 As mentioned above, the data in the `data` sub-array is intended to directly create or update the database object with.
82 As these values are used in the database query directly, these values cannot contain arrays.
83 Several form fields, however, store and return their data in form of arrays.
84 Thus, this data cannot be returned by `IFormField::getSaveValue()` so that `IFormField::hasSaveValue()` returns `false` and the form field’s data is not collected by the standard `DefaultFormDataProcessor` object.
85
86 Instead, such form fields register a `CustomFormDataProcessor` in their `IFormField::populate()` method that inserts the form field value into the `$parameters` array directly.
87 This way, the relevant database object action method has access to the data to save it appropriately.
88
89 The constructor of `CustomFormDataProcessor` requires an id (that is primarily used in error messages during the validation of the second parameter) and callables for `IFormDataProcessor::processFormData()` and `IFormDataProcessor::processObjectData()` which are passed the same parameters as the `IFormDataProcessor` methods.
90 Only one of the callables has to be given, the other one then defaults to simply returning the relevant array unchanged.
91
92
93 #### `VoidFormDataProcessor`
94
95 Some form fields might only exist to toggle the visibility of other form fields (via dependencies) but the data of form field itself is irrelevant.
96 As `DefaultFormDataProcessor` collects the data of all form fields, an additional data processor in the form of a `VoidFormDataProcessor` can be added whose constructor `__construct($property, $isDataProperty = true)` requires the name of the relevant object property/form id and whether the form field value is stored in the `data` sub-array or directory in the `$parameters` array.
97 When the data processor is invoked, it checks whether the relevant entry in the `$parameters` array exists and voids it by removing it from the array.