From a8f7081601dd28c80559dc9973e8a5e6f8e4d503 Mon Sep 17 00:00:00 2001 From: Michael Stenta Date: Mon, 13 Mar 2023 09:36:05 -0400 Subject: [PATCH] Add developer documentation for building configurable quick forms. --- docs/development/module/quick.md | 219 +++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) diff --git a/docs/development/module/quick.md b/docs/development/module/quick.md index d9b151c25..d5a5d5e77 100644 --- a/docs/development/module/quick.md +++ b/docs/development/module/quick.md @@ -222,6 +222,225 @@ Available traits and the methods that they provide include: given a name and vocabulary. If the term does not exist, a new term will be created. +## Configurable quick forms + +A "configurable" quick form is one that allows users to change how the quick +form behaves, by providing settings and a configuration form for customizing +them. + +To make an existing quick form configurable: + +1. Add `implements ConfigurableQuickFormInterface` to the quick form's class + definition. This indicates to farmOS that the quick form is configurable, + builds a router item for the configuration form, adds it to the UI, etc. +2. Add `use ConfigurableQuickFormTrait` to the quick form's class definition. + This adds default methods required by the `ConfigurableQuickFormInterface`. +3. Add a `defaultConfiguration()` method that returns an array of default + configuration values. +4. Add a `buildConfigurationForm()` method that builds a configuration form + with form items for each of the properties defined in + `defaultConfiguration()`. +5. Add a `submitConfigurationForm()` method that processes submitted values and + assigns configuration to `$this->configuration`. +6. Add a `config/schema/[mymodule].schema.yml` file that describes the + [configuration schema/metatdata](https://www.drupal.org/docs/drupal-apis/configuration-api/configuration-schemametadata). + +The following is the same "Harvest" example as above, with the new interface +and methods, followed by the schema file that describes the settings. + +```php + 100, + ]; + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, FormStateInterface $form_state, string $id = NULL) { + + // Date+time selection field (defaults to now). + $form['timestamp'] = [ + '#type' => 'datetime', + '#title' => $this->t('Date'), + '#default_value' => new DrupalDateTime('now', \Drupal::currentUser()->getTimeZone()), + '#required' => TRUE, + ]; + + // Asset reference field (allow multiple). + $form['asset'] = [ + '#type' => 'entity_autocomplete', + '#title' => $this->t('Assets'), + '#target_type' => 'asset', + '#tags' => TRUE, + ]; + + // Harvest quantity field. + $form['quantity'] = [ + '#type' => 'number', + '#title' => $this->t('Quantity'), + '#required' => TRUE, + '#default_value' => $this->configuration['default_quantity'], + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, FormStateInterface $form_state) { + + // Draft a harvest log from the user-submitted data. + $timestamp = $form_state->getValue('timestamp')->getTimestamp(); + $asset = $form_state->getValue('asset'); + $quantity = $form_state->getValue('quantity'); + $log = [ + 'type' => 'harvest', + 'timestamp' => $timestamp, + 'asset' => $asset, + 'quantity' => [ + [ + 'type' => 'standard', + 'value' => $quantity, + ], + ], + 'status' => 'done', + ]; + + // Create the log. + $this->createLog($log); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state) { + + // Default quantity configuration. + $form['default_quantity'] = [ + '#type' => 'number', + '#title' => $this->t('Default quantity'), + '#default_value' => $this->configuration['default_quantity'], + ]; + + return $form; + } + + /** + * {@inheritdoc} + */ + public function submitConfigurationForm(array &$form, FormStateInterface $form_state) { + $this->configuration['default_quantity'] = $form_state->getValue('default_quantity'); + } + +} +``` + +`config/schema/farm_quick_harvest.schema.yml`: + +```yaml +farm_quick.settings.harvest: + type: quick_form_settings + label: 'Harvest quick form settings' + mapping: + default_quantity: + type: integer + label: 'Default quantity' +``` + +### Methods + +The `ConfigurableQuickFormTrait` class add all the necessary methods required +by `ConfigurableQuickFormInterface` (which is used to designate a quick form as +"configurable"). Child classes can override these methods to customize their +behavior. At a minimum, most configurable quick form classes should override +`defaultConfiguration()`, `buildConfigurationForm()`, and +`submitConfigurationForm()`. + +Available methods include: + +- `defaultConfiguration()` - Provide an array of default configuration values. +- `buildConfigurationForm()` - Build the configuration form as an array using + [Drupal Form API](https://www.drupal.org/docs/drupal-apis/form-api/introduction-to-form-api). +- `validateConfigurationForm()` - Perform validation on the user input. +- `submitConfigurationForm()` - Perform logic when the form is submitted to + prepare the quick form configuration entity. This will not run if validation + fails. + +## Quick form configuration entities + +Each quick form that is displayed to the user in farmOS is represented as a +[configuration entity](https://www.drupal.org/docs/drupal-apis/entity-api/configuration-entity). +Each configuration entity specifies which quick form plugin it uses (aka which +PHP class that extends from `QuickFormBase`), along with other information like +label, description, help text, and configuration settings (used by configurable +quick forms). + +However, if a configuration entity is not saved, farmOS will try to provide a +"default instance" of the quick form plugin. From a module developer's +perspective, this means that the module does not need to provide any config +entity YML files in `config/install`. It can rely on farmOS's default quick +form instance logic to show the quick form. + +In the case of configurable quick forms, a config entity will be automatically +created when the user modifies the quick form's configuration and submits the +configuration form. + +Quick form configuration entities can also be used to override defaults, +including the label, description, and help text. They can also be used to +disable a quick form entirely by setting the config entity's `status` to +false. + +If multiple configuration entities are provided for the same plugin, multiple +quick forms will be displayed in the UI. This is useful if you want to create +a set of similar quick forms with pre-set configuration options. + +### Disable default instance + +In some cases, a plugin may not want a "default instance" to be created. +Instead, they may want to require that a quick form configuration entity be +explicitly created. For example, if a plugin requires configuration settings, +but there isn't a sensible default for that configuration and user input is +required, a "default instance" may not be possible. + +In that case, the plugin can add `requiresEntity = True` to its annotation, +which will tell farmOS not to create a default instance of the quick form. +The quick form will only be made available if a configuration entity is saved. + ## Quick form actions farmOS provides lists of logs and assets throughout its interface. Many of