schema_form
This module automatically generates Drupal Forms directly from defined schemas, using the structure, labels and validation constraints from the schema definition.
It auto generates forms for configuration entities, config objects like module settings page, and for any other schema you want!
Simply put, to create a form page, you should only describe the data schema in a YAML schema file, and that's it. The form page will be generated automatically without custom code at all. But, if you need, you still can alter the form and add your customizations automatically on top of the auto-generated form.
Usage
Configuration forms
Let's imagine that you developed a custom API client that should store the API configuration and some options. So, you have to describe the schema in the file config/schema/my_module.schema.yml like this:
my_module.api_endpoint:
type: config_object
label: API Configuration
mapping:
endpoint:
type: uri
label: Endpoint
constraints:
NotBlank: []
username:
type: string
label: Username
constraints:
Regex:
pattern: /^[a-zA-Z0-9_]+$/
message: Only alphanumeric characters and underscores are allowed.
password:
type: string
label: Password
debug_logging:
type: boolean
label: Enable debug loggingAnd then - you usually have to create a form, where have to list again the same list of fields and labels manually, then validate them and save to configs.
But with this module, you do not need to spend time on this! Just describe a route with the config name like this:
my_module.my_api_config:
path: /admin/my-api-config
defaults:
_form: Drupal\schema_form\SchemaConfigFromRouteForm
_title: My API config
options:
_admin_route: TRUE
editable_config_names:
- my_module.my_api_config
requirements:
_permission: administer systemThe key part is the editable_config_names option where you can list one or more config names that should be exposed as a form. The rest will be done automatically by the module, you need just to open the configured url /admin/my-api-config and you will see the fully working form with all the fields, validation and configuration update functionality out of the box!
If you need to customize the page, create a simple class extending the Drupal\schema_form\SchemaConfigFormBase base class like this:
namespace Drupal\my_module\Form;
use Drupal\schema_form\SchemaConfigFormBase;
class MyConfigForm extends SchemaConfigFormBase {
public function getEditableConfigNames() {
return ['schema_form_test.my_config'];
}
}
and then you can declare your own function buildForm(), validateForm() or submitForm() where to put your custom logic, and call the parent function to do the rest.
You can find more working examples in the tests/modules/schema_form_test submodule.
Config Entity forms
If you created a custom config entity, there is no need to create and manage the form class for it, the module will do this automatically. All that you need to do is just choose the the SchemaFormEntityForm class as a handler for the entity add and edit form like this:
use Drupal\schema_form\Form\SchemaFormEntityForm;
#[ConfigEntityType(
id: 'my_custom_config_entity',
...
handlers: [
'form' => [
'add' => SchemaFormEntityForm::class,
'edit' => SchemaFormEntityForm::class,
'delete' => EntityDeleteForm::class,
],
],
...
)]And you can customize the form directly from the Drupal admin panel by creating a design on the page /admin/config/content/schema-form-design.
See a full example in the file src/Entity/SchemaFormDesign.php.
Regular forms
You can use this module not only for configuration forms, but for any form you want! So, instead of forming a long PHP array for the form, you just need to describe the schema and that's it. Here is an example:
my_module.my_feedback_form:
type: mapping
label: Send us your feedback
mapping:
first_name:
type: string
label: First name
last_name:
type: string
label: Last name
email:
type: email
label: Your email
constraints:
NotBlank: []
message:
type: text
label: Message text
constraints:
NotBlank: []
description: Please provide your feedback in this field.And then - just create a simple class, extending the SchemaFormBase:
namespace Drupal\my_module\Form;
use Drupal\Core\Form\FormStateInterface;
use Drupal\schema_form\SchemaFormBase;
class MyFeedbackForm extends SchemaFormBase {
public function getSchemaFormSchema(): string|null {
return 'schema_form_test.my_feedback_form';
}
public function processSubmittedValues(TraversableTypedDataInterface $values, FormStateInterface $form_state): void {
// Custom handling of already validated form submission typed values.
$valuesArray = $values->getValue();
$name = $valuesArray['first_name'] ?? NULL;
$this->messenger()->addMessage($this->t('Thank you, @name!', [
'@name' => $name ?? $this->t('Anonymous'),
]));
}
}
And that's it! You have a fully working feedback form, without any PHP array filled manually! And you can just process the already validated and typed submission data, without handling this manually.
Look for more demo examples in the submodule tests/modules/schema_form_test.
To install the schema_form_test module on your local website, you need to add this line to the settings.php:
$settings['extension_discovery_scan_tests'] = TRUE;
Customizing the form
Classic PHP way
You can customize the form as usual by adding additional properties to the form elements in PHP, for example:
class MyFeedbackForm extends SchemaFormBase {
...
public function buildForm(array $form, FormStateInterface $form_state) {
$form = parent::buildForm($form, $form_state);
$form['first_name']['#description'] = $this->t("We'll be glad to know your name.");
return $form;
}
...
}
Schema Form Design in the Drupal admin panel
In the Drupal Admin panel, go to the Configuration » Content authoring » Schema Form designs (URL /admin/config/content/schema-form-design) and click on the "Add Schema Form Design" button.
There, type the id and the label of your design, and in the "Schema name" field - type your custom schema name.
Then, in the "Design" textarea put a list of "mapping" elements, where you can add or modify form elements with any data you want.
Schema inline way
And you can provide additional metadata directly in the Schema YAML structure like this:
my_module.my_feedback_form:
type: schema_form
label: Send us your feedback
mapping:
...
first_name:
type: string
label: First name
description: We'll be glad to know your name.In this example, we added the description. Yes, the 'description' field is not part of the Drupal Schema, but it is not restricted to use any additional fields in Drupal Schema YAML files, so the module uses this trick to simplify customizing the form. If you don't want to use this trick, you can always return to the classic way by customizing the pre-generated form array using PHP.
To avoid conflicts with other modules, the module supports the third_party_settings property that takes priority over other values:
my_module.my_form:
type: mapping
mapping:
...
my_field:
type: string
label: My Field
third_party_settings:
schema_form:
element:
'#title': My Field Title
'#description': My field description
'#default_value': foo
'#attributes':
class:
- my-field
# And all other custom values for the form array element.And for more convenience, it supports a simpler declaration of the common properties (title and description), like this:
my_module.my_form:
type: mapping
mapping:
...
my_field:
type: string
label: My Field
title: My Field Title # Here is a custom title, if you want to overwrite the schema item label for the form element. If it is filled, but the description is empty, the label is used as description.
description: My field description # The field description text.See more examples in the submodule directory tests/modules/schema_form_test.
Actually, Drupal Schema JSON format doesn't support non-standard properties and even third_party_settings, but they work without any problems, because the check is not strict. But there are no ways to attach additional metadata to the schema items, therefore - please vote on this issue #3522197 to add support for this.
Separate form declaration file
The module also will support a separate YAML file to declare the form specific additions to the data schema, to not mix the schema and the form representation in one place.
But the work on this feature is still in progress, please join the development.
Similar projects
Automatic Configuration Form - implements the same idea, but targeted only at configuration forms. Does not use plugins, so support is limited to only built-in field types.
Schema Based Config Forms - targeted only at configuration forms, extendable by plugins and provides more field types out of the box.
If you use those modules, you can simply replace them with this module Schema Form without any change in your created schemas, because it supports form declaration formats from these modules too. Here is an example:
# And more formats to support schemas created for other similar modules
# without changes:
my_another_field:
type: string
label: My Another Field # Label from Drupal Core, priority: 4.
title: My Another Field Title # Module: auto_config_form, priority: 3.
description: My another field description # Module: auto_config_form, priority: 3.
'#title': My Another Field Title # Module: schema_based_config_forms, priority: 2.
'#description': My another field description # Module: schema_based_config_forms, priority: 2.
'#field_prefix': <div>
'#field_suffix': </div>
'#schema_form_hide': true
'#schema_form_plugin': my_custom_plugin
third_party_settings:
schema_form:
element:
'#title': My Another Field Title # The most relevant to this module, priority: 1.
'#description': My another field description # The most relevant to this module, priority: 1.
But if you use only this module to build forms, please stick to the recommended format described at the top.