- Issue created by @joachim
- 🇬🇧United Kingdom joachim
I've already built something similar for Module Builder, which automatically builds a FormAPI array from a data structure. So I could adapt that code.
What I'm stuck on is how to get the config schema for a particular config name.
- 🇬🇧United Kingdom jonathanshaw Stroud, UK
+1 for the idea.
Things like option values would still need to be provided in the form.
Maybe that's a limitation of the current schema that could be improved down the road.
- 🇬🇧United Kingdom joachim
> What I'm stuck on is how to get the config schema for a particular config name.
@james.williams pointed me in the right direction in Slack for how to do this -- please add credit for this!
> Maybe that's a limitation of the current schema that could be improved down the road.
Yup, having option values and labels would be necessary if we want to be able to make config forms based on a schema retrieved over REST which AFAIK is a goal.
- 🇬🇧United Kingdom james.williams
Hi, thanks Joachim. I've written up what I was up to https://www.computerminds.co.uk/articles/automatically-generate-forms-co... which was for a configurable block plugin in which I explored generating as much of the form as possible from the config schema. I've posted my code up at https://gist.github.com/anotherjames/bcb7ba55ec56359240b26d322fe2f5a5 . Here are a few thoughts from my early experiments with this...
My case was a configurable plugin form, whereas the original suggestion here is for forms extending ConfigFormBase. Can we help both cases, and maybe more? There is code currently in config_translation for automatically generating forms from config schema, such as
config_translation_config_schema_info_alter()
and the parts ofConfigTranslationFormBase::buildForm()
that fetch the schema and build form elements. So maybe the first step to achieve this feature request is to identify and refactor those parts out of the config_translation module to become more useful in other cases (including monolingual sites!). Of course having a concrete use case (like the suggestion for ConfigFormBase) might help pull that possibility along, and then facilitating other cases could be added.The config_translation approach uses a 'form_element_class' key in the schema; what other keys specific to this could be supported usefully? In my example, I added 'default' (which I then used in my plugin's
::defaultConfiguration()
method) and 'locked' (for#disabled
on the form elements). Maybe that's just scope creep, but it hints at the possibility of shifting the inherent definition of config data into the schema rather than form API.Things like option values would still need to be provided in the form.
Not necessarily! If a data item only has certain allowed values, those can (should?) be defined as constraints on it - e.g. using the Choice constraint → (and/or Enums?!). Then the form element could be automatically generated with its #options set from that. There will always be cases where it makes sense for a form element to be customised further (e.g. for things like #empty_option or #placeholder) which really are only about the form, not the inherent definition of the data. But that just means a form making use of this could just merge in those changes after calling the parent/trait method implementation that does the automatic form building.
Thanks for opening this issue and building some momentum around this idea! I thought maybe for now I was just on my own crazy island exploring this idea ;-)
- 🇬🇧United Kingdom AndyF
+1
having option values and labels would be necessary if we want to be able to make config forms based on a schema retrieved over REST which AFAIK is a goal.
Related: 🌱 Enhance config schema for richer default experiences Active
- 🇬🇧United Kingdom jonathanshaw Stroud, UK
From @wimleers #2949888-24: Enhance config schema for richer default experiences → :
Allowed values / enum
Already in core — see this for ckeditor5.plugin.ckeditor5_language for example:
Choice:
- un
- all - Assigned to joachim
- 🇬🇧United Kingdom joachim
> Already in core — see this for ckeditor5.plugin.ckeditor5_language for example:
Yes, but that's only the values. It doesn't have the option labels.
I'm making progress on this.
- 🇦🇲Armenia murz Yerevan, Armenia
There are several contrib modules that allow building configuration forms directly from the schema:
- https://www.drupal.org/project/schema_form →
- https://www.drupal.org/project/auto_config_form →
- https://www.drupal.org/project/schema_based_config_forms →
They work very good and significantly decrease the amount of boilerplate that needs to be written!
But the main issue is the strict format of the Drupal Schema format that misses the "description" property, which is crucial for most of the forms to provide good UI.
As a workaround, we can use the
third_party_settings
property that is already widely used in different parts of Drupal, so I created a feature request to add this property: ✨ Allow third_party_settings property in the Drupal Schema format to allow storing metadata and custom module-related data Active - please join ;-)So, maybe we can reuse the approach from one of those modules in Drupal Core?
- 🇬🇧United Kingdom joachim
I keep forgetting to push the work I did on this so far.
I converted a few of the core settings forms, and found that in most cases, the form's structure is rather different from the structure of the config, which requires some tweaking of the automatic form code. The Views settings form is particularly bad for this!
- 🇬🇧United Kingdom joachim
Pushed my WIP branch to a fork -- sandbox-3477363-automatic-config-forms
- 🇦🇲Armenia murz Yerevan, Armenia
I converted a few of the core settings forms, and found that in most cases, the form's structure is rather different from the structure of the config, which requires some tweaking of the automatic form code.
Faced the same issue, and I believe that extending the schemas with the form related metadata is the best way to resolve this issue.
So, by default - all configs will be rendered as they described, and some of them look great, for example - 'system.performance'.
But if you need to customize the form for a bad-looking config, you can put additional metadata directly to the schema, describing the required form design.
This approach with storing metadata in the "third_party_settings" property I use in the module Schema Form → to render the forms directly from the schema, without any custom PHP, an example:
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 '#weight': 42: '#attributes': class: - my-field
What do you think about this approach?
- Merge request !12016Draft: Issue #3477363: Add a way to automatically generate basic config forms → (Open) created by murz
- 🇬🇧United Kingdom joachim
element: '#description': Put here the main value. '#weight': 42 '#attributes': class: - my-field
Hmm I'm not keen on this -- it's overloading the schema with things that go beyond its designed intention, which is to declare the structure and format of config. I can see a case for adding a 'description' key to go alongside 'label', but things like weight and classes are too much I think.
- 🇬🇧United Kingdom james.williams
Thanks @murz for these contributions! Those modules look useful - I can see myself trying your schema_form one out for real, the next time I want to try generating forms from schema.
That said, I agree with @joachim's last comment. The schema should only really declare things that are inherent about the structure/definition of config. That's enough to generate the necessary stuff for form elements. But if the form wants to adjust things which are only really about the form element (especially the visual presentation, for example), the form class can still do so after the basic form elements have been generated (e.g. setting weights & attributes after the calls to
buildFormForConfig()
in your MR implementation) :<?php $form = $this->buildFormForConfig($form, 'my_module.my_config'); // Tweak properties of the generated element. $form['my_value']['#weight'] = 42; $form['my_value']['#attributes']['class'][] = 'my-field';
The line about what is "inherent about the structure/definition of config" might be slightly fuzzy though. Whilst weight & element classes are more clearly only for the form element, the approach I've taken added 'locked' and 'default' config keys which I mapped to
#disabled
and#default_value
respectively in the generated elements. These could be used beyond just the form elements, but could also been seen as overloading the schema to "go beyond its designed intention". I guess we'll need to find that line at some point - either as we explore solutions, or up front?The description is an interesting case - it seems a no-brainer to me, to support descriptions living in the schema - but not all existing
#description
strings will be specifically about the config definition. Some will be be about how to correctly enter the value in the widget offered by the UI - which I don't think should live in the schema. In those cases, I would expect the form to override / add to any description coming from the schema. - 🇬🇧United Kingdom joachim
> added 'locked' and 'default' config keys which I mapped to #disabled and #default_value
'locked' makes sense to have in schema too, yes.
But for 'default', surely the default value is already in config/install, so adding it to the schema violates DRY.
> Some will be be about how to correctly enter the value in the widget offered by the UI - which I don't think should live in the schema. In those cases, I would expect the form to override / add to any description coming from the schema.
Yup, agreed.
- 🇬🇧United Kingdom james.williams
The 'default' can be useful for things like plugin configuration or config entities that won't ship in /config/install . (e.g. The gist I linked to is for a block plugin which populates its implementation of
defaultConfiguration()
from the schema, not justblockForm()
.)I'm quite happy to park supporting specific keys like these though; let's get as far as we can without having to add too much to schema definitions or the TypedConfigManager, etc! Each possible addition could be its own separate follow-up to be considered on its own merits, without having to block progress on just being able to automatically generate form elements. Description is the only one I think we definitely agree on.