Add developer documentation for building configurable quick forms.
This commit is contained in:
parent
de8a262685
commit
a8f7081601
|
@ -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
|
given a name and vocabulary. If the term does not exist, a new term will be
|
||||||
created.
|
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
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Drupal\farm_quick_harvest\Plugin\QuickForm;
|
||||||
|
|
||||||
|
use Drupal\Core\Datetime\DrupalDateTime;
|
||||||
|
use Drupal\Core\Form\FormStateInterface;
|
||||||
|
use Drupal\farm_quick\Plugin\QuickForm\ConfigurableQuickFormInterface;
|
||||||
|
use Drupal\farm_quick\Plugin\QuickForm\QuickFormBase;
|
||||||
|
use Drupal\farm_quick\Traits\ConfigurableQuickFormTrait;
|
||||||
|
use Drupal\farm_quick\Traits\QuickLogTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Harvest quick form.
|
||||||
|
*
|
||||||
|
* @QuickForm(
|
||||||
|
* id = "harvest",
|
||||||
|
* label = @Translation("Harvest"),
|
||||||
|
* description = @Translation("Record when a harvest takes place."),
|
||||||
|
* helpText = @Translation("Use this form to record a harvest."),
|
||||||
|
* permissions = {
|
||||||
|
* "create harvest log",
|
||||||
|
* }
|
||||||
|
* )
|
||||||
|
*/
|
||||||
|
class Harvest extends QuickFormBase implements ConfigurableQuickFormInterface {
|
||||||
|
|
||||||
|
use ConfigurableQuickFormTrait;
|
||||||
|
use QuickLogTrait;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function defaultConfiguration() {
|
||||||
|
return [
|
||||||
|
'default_quantity' => 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
|
## Quick form actions
|
||||||
|
|
||||||
farmOS provides lists of logs and assets throughout its interface. Many of
|
farmOS provides lists of logs and assets throughout its interface. Many of
|
||||||
|
|
Loading…
Reference in New Issue