- Issue created by @wim leers
- ๐ง๐ชBelgium borisson_ Mechelen, ๐ง๐ช
Wim Leers โ credited borisson_ โ .
- ๐บ๐ธUnited States effulgentsia
Wim Leers โ credited effulgentsia โ .
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
Added a working PoC implementation to the IS ๐
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
- Open on Drupal.org โEnvironment: PHP 8.2 & MySQL 8last update
about 1 year ago Not currently mergeable. - @wim-leers opened merge request.
- Assigned to wim leers
- Status changed to Active
about 1 year ago 6:59am 4 September 2023 - ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
โจ Add optional validation constraint support to ConfigFormBase Fixed is in!
- Issue was unassigned.
- Status changed to Needs review
about 1 year ago 8:44am 4 September 2023 - ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
Did what I said in #6.
Observations:
- we do need transformation methods like @effulgentsia originally proposed, because for example:
- in
MediaSettingsForm
,iframe_domain
must either be a valid URI ornull
, NOT the empty string - in
BookSettingsForm
,#type => checkboxes
is used, and that results in'0'
in form values for the unchecked checkboxes โฆ so it MUST be filtered away
- in
- In
BookSettingsForm::submitForm()
there was some weird logic from almost exactly a decade ago ( #1933548: Book allowed_types settings repetitive and in under certain conditions can change unexpectedly โ ) โฆ that I was able to remove by specifyingorderby: key
instead (see #2361539: Config export key order is not predictable for sequences, add orderby property to config schema โ ). BookSettingsForm::validateForm()
cannot be deleted here yet because it needs that validation logic to be converted to a validation constraint. That'd be too much out of scope here. So I'd say we should either revertBookSettingsForm
changes or create a follow-up and point to that.
Curious what y'all think.
- we do need transformation methods like @effulgentsia originally proposed, because for example:
- last update
about 1 year ago 30,136 pass - Status changed to Needs work
about 1 year ago 7:15pm 7 September 2023 - ๐บ๐ธUnited States phenaproxima Massachusetts
I like the concept here, but I have some questions about the implementation...
- last update
about 1 year ago 30,164 pass - Status changed to Needs review
about 1 year ago 10:21am 18 September 2023 - ๐บ๐ธUnited States phenaproxima Massachusetts
I spent most of the day thinking about this issue and, long story short, I think we should change the approach here and go for syntax like this (proposed in another issue, but I'm not sure which):
$form['security']['iframe_domain'] = [ '#type' => 'url', '#title' => $this->t('iFrame domain'), '#size' => 40, '#maxlength' => 255, '#config_target' => 'media.settings:iframe_domain', '#description' => $this->t('Enter a different domain from which to serve oEmbed content, including the <em>http://</em> or <em>https://</em> prefix. This domain needs to point back to this site, or existing oEmbed content may not display correctly, or at all.'), ];
(This example comes from
MediaSettingsForm
.) Let me explain more about how this could work:When loading the default value from config:
ConfigFormBase::buildForm()
could recursively loop through all the form's elements, and load the config value for any element which has a#config_target
key, but not a#default_value
key. Most (?) config forms callparent::buildForm()
, so they would be automatically opted into this behavior.When saving the value to config: We could loop through the entire form recursively (starting from
$form_state->getCompleteForm()
), and for any element which defines a#config_target
key, we could use the element's#parents
property to get the submitted value from$form_state->getValue()
. Then we could set that value in the specified config object and property path.But what if we need to transform the value before saving? Well,
#config_target
would make an allowance for that. It could either be a string, if there is no transformation to be done:'#config_target' => 'media.settings:iframe_domain'
Or, if there is a transformation needed, it could be an array whose second element is the name of a string callable which will transform it:
'#config_target' => ['media.settings:iframe_domain', '::nonEmptyStringOrNull']
It could be a fully-qualified static callable as a string:
'#config_target' => ['media.settings:iframe_domain', HelperClass::class . '::transformationMethod']
If it was not fully qualified, as in the first example, we would expect it to be the name of a trusted callable. That would be enforced by DoTrustedCallbackTrait.
I think that this approach, although old-school, will have these benefits:
- The goal of this issue is to make it super-duper drop-dead easy to adopt config validation. To that end, I think we want to minimize the effort it takes contrib to adopt it. Core will adopt what it needs to, but contrib is the challenge here. Adding a new FAPI property, even though it's kind of old-school, is a very familiar pattern for contrib and custom module/theme developers. The value of the property is relatively simple (at least if there's no transformation needed). There's no need for an arcane syntax in a static array. So, to me, this approach greases the slide to contrib adoption, and that's the main reason to do it.
- But if you're not convinced, there's another reason: this means we can easily support hook_form_alter (and all of its variations). Yes, some modules want to alter other modules' config forms to add additional properties -- Automatic Updates is an example of this. It's a common pattern. Using a static array of the form class is un-alterable, and would leave all modules which need to alter another module's config forms out in the cold.
- Since the priority is to get people to use config validation, I think that adopting the more old-school FAPI property with relative "ease of understanding" and broad compatibility is an appropriate trade-off. When everybody's using config validation for their config forms, we can talk about deprecating the new FAPI property and moving to something more modern.
- Assigned to phenaproxima
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
The value of the property is relatively simple (at least if there's no transformation needed).
This is a fairly big assumption. Transformations will be necessary in many cases. So it will be more complex than presented here in many cases.
It's a common pattern.
It's not common for simple config forms though. Even more so because the only reasons for contrib modules to alter a simple config form are to:
- inject a form to add third party settings to the edited simple config
- inject a form whose values are saved elsewhere (in which case itโs completely irrelevant anyway)
- do cosmetic changes
But you're right it MUST be supported! ๐
Automatic Updates is an example of this.
Except that it's not a good example ๐ , because it applies the second pattern I mentioned above: it alters the form provided by
UpdateSettingsForm
forupdate.settings
, but stores its values inautomatic_updates.settings
! So โฆ config validation is irrelevant in that case anyway, since\Drupal\update\UpdateSettingsForm::getEditableConfigNames()
says:protected function getEditableConfigNames() { return ['update.settings']; }
(The only way it could add config validation is to subclass
UpdateSettingsForm
, addautomatic_updates.settings
to that and override theupdate.settings
route definition. Which is fine โฆ except that it then prevents other modules from doing the same! Horizontal extensibility bites once again!)Based on a private Slack between you, @effulgentsia and I, AFAICT @effulgentsia is on board with this change in direction. The primary reason being: if it's a static array, contrib form alters become impossible to support.
Tagging for that.
Should we make this a non-blocker and do ๐ [PP-1] Update all remaining ConfigFormBase subclasses in Drupal core to use config validation Active first?
- last update
about 1 year ago 30,168 pass - @phenaproxima opened merge request.
- last update
about 1 year ago 30,168 pass - last update
about 1 year ago Custom Commands Failed - last update
about 1 year ago 30,161 pass, 3 fail - last update
about 1 year ago 30,163 pass, 2 fail - last update
about 1 year ago 30,168 pass - Status changed to Needs work
about 1 year ago 2:21pm 25 September 2023 - last update
about 1 year ago 30,363 pass - last update
about 1 year ago 30,363 pass - last update
about 1 year ago 30,363 pass - last update
about 1 year ago 30,363 pass - last update
about 1 year ago 30,363 pass - Assigned to wim leers
- Status changed to Needs review
about 1 year ago 4:14pm 26 September 2023 - last update
about 1 year ago 30,351 pass, 4 fail - last update
about 1 year ago 30,363 pass - last update
about 1 year ago 30,363 pass - last update
about 1 year ago 30,363 pass - Status changed to Needs work
about 1 year ago 12:31pm 3 October 2023 - ๐ง๐ชBelgium borisson_ Mechelen, ๐ง๐ช
Looking at the implementations in the last few commits, this seems like such a simple DX, works very well.
I had one remark on the pull request, but it might not be something we often do.I don't see the link to the comment, so https://git.drupalcode.org/issue/drupal-3382510/-/commit/8e4abd89e594877...
Other than that small remark, I think this is good to go, waiting for rtbc on an answer on that comment. I'm happy if we feel like that goes too far.
- Assigned to phenaproxima
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
I have a bit more than one remark ๐
But: excellent work here, @phenaproxima! ๐
- The issue summary does not say that this is removing
mapConfigKeyToFormElementName()
, which โจ Add optional validation constraint support to ConfigFormBase Fixed added during the10.2.x
cycle (and which we're still in). So it's fine to remove, but we need to articulate why. We arrived at that solution after long and careful debate. - The changes in
core/modules/update/src/UpdateSettingsForm.php
make this really convincing. FAR less code! And yay for the test coverage that was added in the previous issue, that means I am immediately confident this works correctly for sequences too ๐ฅณ - I really like how this gives you one more reason to update your config forms, even if you do not yet have validation constraints: your MR shows that we'll be able to remove most
::submitForm()
overrides! ๐คฉ - But โฆ other concerns I raised at
#2408549-178: There is no indication on configuration forms if there are overridden values โ
still stand:
โ we could ensure this by validating that each#config_target
value points to a config name that actually exists and is one of thegetEditableConfigNames()
and its property path actually exists in the schema- Related: it now is suspicious when a
::submitForm()
override exists. Most of the time you should not need that. As is the presence of#default_value
.
โ this is now no longer true. But ideally we'd be able to adopt the same pattern for config entity forms, although then it wouldn't be something like'#config_target' => 'node.settings:key'
, but something like'#config_target' => 'node.type.*:key'
. Could we do a brief PoC to verify that this would be possible? ๐
- This issue AFAICT introduces a regression/BC break: see my comment on
NegotiationSessionForm.php
- This makes deprecation of the form-based validation (see ๐ [PP-2] Follow-up for #3364506: add deprecation once all simple config forms in core implement Postponed ) still possible to detect: the complete absence of
#config_target
is a certain indicator. - The issue summary does not say that this is removing
- last update
about 1 year ago Custom Commands Failed - ๐บ๐ธUnited States phenaproxima Massachusetts
Updated the issue summary to explain the rationale for removing
copyFormValuesToConfig()
from the API. - ๐บ๐ธUnited States phenaproxima Massachusetts
ideally we'd be able to adopt the same pattern for config entity forms
I could be wrong, but my knee-jerk reaction is that this will not fly.
Config entity forms are backed by config entities, which are fundamentally different beasts than simple config. Simple config is a fairly dumb key-value map, but config entities can have all sorts of specialized logic in and around them, which isn't the case with simple config. We can't just dump a form element's value into a config entity's key, optionally through some transformation callback; we'd need to map those elements' values to methods of config entities -- and that would mean somehow encoding the proper invocations for those methods.
Sure, we could use
ConfigEntityInterface::set()
and::get()
...but that can bypass all kinds of very important logic that may need to run for the entity to be coherent/valid. Doing it that way is a recipe for disaster (and frankly it would probably fail many tests right off the bat). - last update
about 1 year ago 30,392 pass - ๐บ๐ธUnited States phenaproxima Massachusetts
I updated the change record to explain how to use this.
- Assigned to wim leers
- Status changed to Needs review
about 1 year ago 1:57am 11 October 2023 - Assigned to phenaproxima
- Status changed to Needs work
about 1 year ago 12:22pm 15 October 2023 - ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
I think this is 99% done. The one thing that is "iffy" to use @phenaproxima's words (the bidirectional transformation methods) actually suggests we should keep
copyFormValuesToConfig()
available as an escape hatch for more complex use cases.Note: once ๐ Configuration schema & required values: add test coverage for `nullable: true` validation support Fixed lands, we could not only remove
#default_value
, but also#required
๐ - last update
about 1 year ago 30,397 pass - Assigned to wim leers
- Status changed to Needs review
about 1 year ago 6:17pm 15 October 2023 - ๐บ๐ธUnited States phenaproxima Massachusetts
I think โฆ that perhaps this is fine. It helps keeps things simple for the 99% case, and for the remaining 1%, you'd just have to implement copyFormValuesToConfig() instead of using #config_target. WDYT about that?
That'd be good to incorporate in the change record.
Makes sense to me. Tagging this issue for post-commit change record updates (since there are already change record updates needed, and I can't go edit the revision that has the required changes).
Committers, please note that this should be set to "needs work" post-commit, so that I can make the change record explain when one should override
copyFormValuesToConfig()
. - Issue was unassigned.
- Status changed to RTBC
about 1 year ago 8:39am 16 October 2023 - ๐ฌ๐งUnited Kingdom alexpott ๐ช๐บ๐
Wim Leers โ credited alexpott โ .
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
Note that @alexpott first proposed this solution ~6 years ago in #2408549-82: There is no indication on configuration forms if there are overridden values โ , with a first implementation at #2408549-85: There is no indication on configuration forms if there are overridden values โ .
- ๐ฌ๐งUnited Kingdom longwave UK
I am not convinced that the transformer function should be bidirectional; per single responsibility principle, a function should generally only have one purpose - here the transformer has two depending on the type of the argument. Because form API is not currently strictly typed (numeric inputs arrive as strings, for example) then I think it might end up being tricky detecting the direction of transformation - especially if the config value is also a string. If we don't want to declare two functions should each transformer be a class that implements an interface with two methods?
- ๐บ๐ธUnited States phenaproxima Massachusetts
What if we added a new param to the transform function --
bool $is_saving
? That way the function would have more to go on than just "how does the argument look".I agree that it sort of flies in the face of the single responsibility principle, but IMHO that's a sacrifice worth making in the name of keeping the DX as simple as possible.
- ๐ท๐ดRomania claudiu.cristea Arad ๐ท๐ด
Maybe we can replace that array/string with a very light class:
class ConfigTarget { public function __construct( public readonly string $configTarget, public readonly array|string $transformOnLoadOrSave, public readonly array|string|null $transformOnSave = NULL, ) { // @todo:: prepare callbacks to do a proper check. \assert(is_callable($transformOnLoadOrSave)); \assert(transformOnSave === NULL || is_callable($transformOnLoadOrSave)); } }
If
$transformOnSave
is missing,$transformOnLoadOrSave
is bidirectional.Then we have:
<?php
$form['foo'] = [
...
'#config_target' => new ConfigTarget(
'media.settings:iframe_domain',
'::nullIfEmptyString',
[SomeOtherClass::class, 'transformOnSave'],
),
...
]; - last update
about 1 year ago Custom Commands Failed - last update
about 1 year ago 30,412 pass - Status changed to Needs review
about 1 year ago 4:35pm 16 October 2023 - ๐บ๐ธUnited States phenaproxima Massachusetts
Now that I made the separation between save and load callbacks explicit, this needs review again.
- Status changed to RTBC
about 1 year ago 8:40am 17 October 2023 - ๐ง๐ชBelgium borisson_ Mechelen, ๐ง๐ช
I agree that there are usecases where the saving and loading are different, and it is a pattern that we also use in different places.
The argument that this is now a single responsibility instead of doing both ways is a good argument as well.I looked at the changes made in the last commit and they make sense as well, discussed this with @lauriii at drupalcon.
Does this still need subsystem maintainer review?
- Status changed to Needs work
about 1 year ago 9:24am 17 October 2023 17:29 0:21 Running53:40 14:45 Running- ๐ฌ๐งUnited Kingdom alexpott ๐ช๐บ๐
Discussed with @Wim Leers and @longwave. The callbacks - save_callback and load_callback are tricky to name. They are not loading or saving anything. As the new document says they are for transforming the value between the config and the form system.
We discussed several ideas...
1. Add a new
ConfigTransformer
class & interface that hastoForm()
and toConfig()
as static methods.So the code to use this becomes
'#config_target' => [ 'target' => 'book.settings:allowed_types', 'transformer' => '\Drupal\Namespace\ConfigTransformer', ],
The advantage of this is that the transformers are reusable and well documented. The disadvantage of this is that the transforms are moving away from the config form class and we'll have more and more classes.
2. Add a new
ConfigTarget
value objectThe code to use this becomes
'#config_target' => new ConfigTarget( 'update.settings:notification.emails', '::loadEmailsFromConfig', '::storeEmailsInConfig', ),
The advantage of this is that we're not building on the massive ArrayPI of forms so it is easy to discovery what is possible and documenting what the callbacks do is much simpler. Ie. the class would have a method like
ConfigTarget::getFormToConfigTransform()
which in the above instance would return'::storeEmailsInConfig'
3. Should these transforms happen using the Form API?
The form API already has
#value_callback
that transforms input to an expected format. That's what we're doing here. However there's no API for manipulating#default_value
so we'd need to add that. Also using#value_callback
would mean that if we use a Checkboxes element we'd become responsible for calling\Drupal\Core\Render\Element\Checkboxes::valueCallback()
which does not feel right. So#value_callback
is happening at the incorrect level.4. Come up with better names for save_callback and load_callback
Maybe something like
While writing this comment I realised that option 3 is untenable and thought that there is an option 4 so I'll add that. This option was not discussed with the others.config_to_form_transform()
and form_to_config_transform()
I think I prefer option 1 or 2 but could live with 4 is other agree.
- ๐ท๐ดRomania claudiu.cristea Arad ๐ท๐ด
I'm for 4., which is more or less what I've proposed in #36, because:
- Not a blind array that we should know how the build the sequence
- It's typed
- It's documented
- Just a tiny class
- Easier in IDE
- ๐บ๐ธUnited States phenaproxima Massachusetts
Here's another idea: what if we introduce two new protected functions to ConfigFormBase (I'm not married to these specific names):
protected function configValueToFormValue(string $config_name, string $property_path, mixed $value): mixed { // Default implementation -- no transformation. return $value; } protected function formValueToConfigValue(string $config_name, string $property_path, mixed $value): mixed { // Default implementation -- no transformation. return $value; }
If you need to do transformations, you can override one or both of these methods. This way, all the complexity of
#config_target
disappears: it's no longer an ArrayPI; you don't need to write a bidirectional transformation function; and it's very clear how to do a transformation in either direction.Since transformations are a relatively "advanced" use case, I think we can rely on developers to grok this.
- ๐ฌ๐งUnited Kingdom longwave UK
Transformer functions are hopefully the exception rather than the rule and for good DX given the rest of form API lives in a single class we want to try and keep the transformers in the same class as well. Can we use (or perhaps abuse) PHP attributes so transformer methods can live in the same class?
public function buildForm(array $form, FormStateInterface $form_state) { $form['update_notify_emails'] = [ '#type' => 'textarea', '#title' => $this->t('Email addresses to notify when updates are available'), '#rows' => 4, '#config_target' => 'update.settings:notification.emails', ]; } #[FromConfig('update.settings:notification.emails')] public static function fromNotificationEmails(array $value): string { return implode("\n", $value); } #[ToConfig('update.settings:notification.emails')] public static function toNotificationEmails(string $value): array { return array_map('trim', explode("\n", trim($value))); }
Multiple config keys can share the same transformer functions if they need to. If there is no method tagged with the attribute no transformation is done.
Not sure how to scale this when we want to share transformers between forms though.
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
Ohhh! I think I like that? The major downside to that (besides new syntax nobody is familiar with) is I think that it becomes a very abstract, relatively disjointed DX, where you have to remember the various moving parts. I do think we could add logic to check that if a "from" exists, the "to" must also exist, and vice versa?
throw new \LogicException()
if either is missing? ๐คNot sure how to scale this when we want to share transformers between forms though.
In cases like these, reuse is IMHO not very important. Just copy/paste these snippets? Otherwise all of these need to become APIs too. This approach would mean it's not actually a public API, but โฆ if the need arises, we could have a
CommonConfigFormTransformers
utility class that one could reuse? - ๐ท๐ดRomania claudiu.cristea Arad ๐ท๐ด
...we want to try and keep the transformers in the same class as well
I don't think so. For example
strtolower()
is also a transformer. Why creating a method just to do that? Then[\Drupal\Component\Utility\Bytes::class, 'toNumber']
is also a transformer. Could we use it directly but still allow::transform()
(which is in the class)? - ๐บ๐ธUnited States phenaproxima Massachusetts
I do think we could add logic to check that if a "from" exists, the "to" must also exist, and vice versa?
๐ I don't recommend this. Of the cases where transformations have to be done in this MR, only one of them needs both to- and from- transformations. The rest of them only need to be changed when the value is being saved.
What if we allowed the attributes to reference other callables (like
strtolower()
), if they needed to?So for example, if you do this, you are saying that
stringToArray()
is the transformation callback forupdate.settings:notification.emails
:#[ToConfig('update.settings', 'notification.emails')] public function stringToArray($value) {...}
But you could also do this, on
buildForm():
#[ToConfig('system.site', 'name', callback: 'strtolower')] public function buildForm($form, $form_state) {...}
In this case, you're saying "I want to use
strtolower()
as the transformer for thesystem.site:name
config property." This would be a very advanced use case but it would address what @claudiu.cristea points out in #45. - ๐ฌ๐งUnited Kingdom alexpott ๐ช๐บ๐
I'm not that keen on #46 and the attribute stuff because I think that have attributes + #config_target in form array feels odd and hard to get used to.
I think #42 might be okay especially if we encourage the use of match. But I think I've come up with a reason why attributes and #42 won't work in the long run. Form alters. How is dblog_form_system_logging_settings_alter() or something similar able to use these. Therefore I think we need this information in the form array.
@longwave and I discussed whether or not we could use schema for this. This is kind of how config translation works - see
config_translation_config_schema_info_alter()
. This method adds a newform_element_class
to config schema. The problem putting the transformer information into schema is that this will tie schema and fomr stuff together. So I don't think this is correct.I think of all the options is something like #36 (sorry @claudiu.cristea for not crediting you with the idea in #40 is the best. It can be used by form alters, it can use both functions on the form and functions anywhere else and the very light class can clearly document with the transformers do.
42:45 55:57 Running- Status changed to Needs review
about 1 year ago 1:16pm 18 October 2023 - ๐บ๐ธUnited States phenaproxima Massachusetts
Okay, I took a shot at implementing this with a ConfigTarget value object.
To keep things frictionless for simpler cases, I made it so that you can still have #config_target be a string, and it will automatically be converted to a ConfigTarget object for you. These objects can be serialized, so they can be stored directly in the config-key-to-form-element map without trouble.
For advanced cases (that is, if you need a transformation in either or both directions), I think we can expect people to call
ConfigTarget::create()
. - last update
about 1 year ago 30,381 pass, 23 fail 28:22 59:49 Running- last update
about 1 year ago Custom Commands Failed - last update
about 1 year ago Custom Commands Failed - last update
about 1 year ago 30,418 pass, 1 fail - last update
about 1 year ago 30,418 pass, 1 fail - ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
That is looking very encouraging! Thanks for the fast turnaround time ๐
Curious what @longwave & @alexpott think ๐
- last update
about 1 year ago 30,418 pass, 1 fail - last update
about 1 year ago 30,418 pass, 1 fail 29:06 1:10 Running- last update
about 1 year ago Custom Commands Failed - last update
about 1 year ago 30,421 pass, 1 fail - last update
about 1 year ago Custom Commands Failed 47:04 43:36 Running- Assigned to phenaproxima
- Status changed to Needs work
about 1 year ago 3:17pm 24 October 2023 - ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
I did a very thorough review, and could barely find anything to complain about.
This looks great. It's _almost_ a net-zero diff ๐ฎ
A few more nits fixed, and I'll confidently RTBC ๐
- last update
about 1 year ago Custom Commands Failed - last update
about 1 year ago Custom Commands Failed - Assigned to wim leers
- Status changed to Needs review
about 1 year ago 3:23pm 24 October 2023 - ๐บ๐ธUnited States phenaproxima Massachusetts
Back to you for final review!
- last update
about 1 year ago 30,436 pass - Assigned to phenaproxima
- Status changed to RTBC
about 1 year ago 1:36pm 25 October 2023 - ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
Zero remarks left.
Issue summary clarified (and slightly updated, it was slightly wrong/stale).
@phenaproxima: you previously created a change record revision โ with the then-up-to-date
#config_target
stuff, can you update it? ๐ - Assigned to wim leers
- Issue was unassigned.
- ๐บ๐ธUnited States phenaproxima Massachusetts
Crediting myself for writing the current approach, Wim for reviewing it, and @claudiu.cristea for suggesting the approach we ultimately used.
- ๐บ๐ธUnited States phenaproxima Massachusetts
Oh, and @longwave for review.
- last update
about 1 year ago 30,439 pass - last update
about 1 year ago 30,439 pass - last update
about 1 year ago 30,457 pass, 1 fail - last update
about 1 year ago 30,466 pass - last update
about 1 year ago 30,485 pass - ๐จ๐ญSwitzerland bircher ๐จ๐ฟ
re my comment on the MR: simpler is good so that was not meant to hold up anything.
I much prefer this over the unshipped API so +1 for RTBC.
The issue summary update looks good too now. Maybe the CR could mention the more complex example with the class and not just the string. - ๐ฌ๐งUnited Kingdom alexpott ๐ช๐บ๐
Creditting @bircher as they were involved in the conversations at Drupalcon that led to the current API.
- ๐ฌ๐งUnited Kingdom alexpott ๐ช๐บ๐
Spent lots of time discussing this at Drupalcon. I think the new API is the easiest way forward for now. I do wonder if something else will come up as we go forward and I have ideas for two follow-ups but I think doing them will only change internal implementation details so I'm not worried about that.
The two ideas are:
- Do not require the config in #config_target to be listed in
getEditableConfigNames()
- this would make doing form alters like dblog_form_system_logging_settings_alter() really easy as you would not need dblog_logging_settings_submit() - Allow all callables in ConfigTarget - instead of saving ConfigTarget objects to the map we could save the location in the form array instead so we can get the config target from the form array
Committed e1c95b2 and pushed to 11.x. Thanks!
I'm going to ask the RMs if we can backport this to 10.2
- Do not require the config in #config_target to be listed in
- Status changed to Downport
about 1 year ago 2:17pm 2 November 2023 -
alexpott โ
committed e1c95b2f on 11.x
Issue #3382510 by phenaproxima, Wim Leers, alexpott, longwave, claudiu....
-
alexpott โ
committed e1c95b2f on 11.x
-
alexpott โ
committed 77945942 on 10.2.x
Issue #3382510 by phenaproxima, Wim Leers, alexpott, longwave, claudiu....
-
alexpott โ
committed 77945942 on 10.2.x
- Status changed to Fixed
about 1 year ago 3:00pm 2 November 2023 - ๐ฌ๐งUnited Kingdom alexpott ๐ช๐บ๐
Discussed with @catch and we agreed to backport this.
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
Yay! ๐ฅณ
RE: Follow-ups
- I contemplated this too. But I think it'd be valuable to keep the extra guardrails around for the 99% use case where a
ConfigFormBase
subclass is not being altered. And I think I see a way how: i) use::getFormId()
to determine if there any form alters for this form, ii) if no form alters exist: inform the developer that this config target does not make sense, iii) if they do exist: allow arbitrary targetsNote: this MR did not introduce any validation of the
#config_target
property! It only is not going to validate or save config targets outside of:: getEditableConfigNames ()
(I think we discussed verifying the
#config_target
makes sense, but it was not considered required, because Form API in general has very few guardrails. ) - I like this!
Unblocked ๐
- #3384790-8: Update all remaining ConfigFormBase subclasses in Drupal core to use config validation โ โ @phenaproxima has already started pushing commits! ๐๏ธ
- #3384782-5: [PP-1] Follow-up for #3364506: add deprecation once all simple config forms in core implement โ (still blocked on the above)
- ๐ Introduce a new #config_target Form API property to make it super simple to use validation constraints on simple config forms, and adopt it in several core config forms Fixed โ this is now pretty much โฆ trivial ๐
- Last but not least: adopting this in a contrib module where the UI does not map 1:1 to underlying config: #3394172-4: Adopt Drupal core 10.2 config validation infrastructure โ โ that has made it clear that for cases where the UI does not match the underlying config at all, that we need additional docs in the change record.
- I contemplated this too. But I think it'd be valuable to keep the extra guardrails around for the 99% use case where a
- ๐ญ๐บHungary Gรกbor Hojtsy Hungary
I think this should be part of a config validation related release highlight segment :) Feel free to identify more bits to include in that.
- ๐ฌ๐งUnited Kingdom alexpott ๐ช๐บ๐
I've created ๐ Do not require the config in #config_target to be listed in getEditableConfigNames() Active - I disagree with
extra guardrails around for the 99% use case
- I'm not sure why they need to exist and what they are for. Let's debate on the issue.
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
This introduced a regression: ๐ Follow-up for #3382510: FormStateInterface::setErrorByName() needs not #name but a variation Closed: duplicate . ๐
- ๐ง๐ชBelgium wim leers Ghent ๐ง๐ช๐ช๐บ
One more thing: this massively improved DX, at one important cost: it hardcoded the assumption that UI/form elements map 1:1 to config property paths (and hence violations for property paths).
This makes better UIs (that present things in the user's mental model) impossible in some cases: ๐ ConfigFormBase + validation constraints: support composite form elements Needs review .
- ๐ฌ๐งUnited Kingdom alexpott ๐ช๐บ๐
Opened ๐ Allow all callables in ConfigTarget Fixed to address #62.2
Automatically closed - issue fixed for 2 weeks with no activity.
- Status changed to Fixed
4 months ago 7:48pm 25 July 2024 Is there any documentation about how `#config_target` should/can be used?