Problem/Motivation
Configuration object wonderful.settings should be able to be like:
node:
article:
status: TRUE
wonderful: FALSE
page:
status: FALSE
wonderful: FALSE
user:
user:
status: TRUE
wonderful: TRUE
and schema:
wonderful.settings:
type: sequence
label: 'Entity type'
sequence:
- type: sequence
label: 'Bundle'
sequence:
- type: mapping
label: 'Wondeful settings'
mapping:
status:
type: boolean
label: 'Status'
wonderful:
type: boolean
label: 'Is it wonderful?'
Proposed resolution
Fix it so the above works. Otherwise we have to add a key like this:
entities:
node:
article:
status: TRUE
wonderful: FALSE
page:
status: FALSE
wonderful: FALSE
user:
user:
status: TRUE
wonderful: TRUE
and schema:
wonderful.settings:
type: mapping
label: 'Entities'
mapping:
entities:
type: sequence
label: 'Entity type'
sequence:
- type: sequence
label: 'Bundle'
sequence:
- type: mapping
label: 'Wondeful settings'
mapping:
status:
type: boolean
label: 'Status'
wonderful:
type: boolean
label: 'Is it wonderful?'
Remaining tasks
Review patch.
User interface changes
none
API changes
none
Comments
Comment #1
alexpottHere's a patch that makes
Drupal\config\Tests\DefaultConfigTestfail - got to love that test!Comment #2
alexpottWorking patch attached. Fixes this by pushing Mapping::get() up to ArrayElement::get() so that both Sequence and Mapping can sharing the ability to traverse config files if they are the root type. The documentation sets out the interesting interface / inheritance going on :)
Leaving at needs work because testbot is borked.
Comment #3
sunI'm confused. The summary talks about a sequence, but the example shows a mapping.
A sequence:
A mapping:
A mapping already works at the top-level.
A top-level sequence does not make sense to me. Much rather, it's a sign that configuration objects might be structured too granularly and the sequence should actually be located and merged into another object.
Comment #4
alexpottBots are back
Comment #5
alexpott@sun a mapping is where you know every key - if the top level is a list of entities available and then the next key are their bundles and then there is mapping then the top two levels are sequences - see #2224761: Add a generic way to add third party configuration on configuration entities and implement for field configuration for an example of this. Or even
rest.settings- the top level resources key is completely superfluous the only reason it exists is because schema can not traverse config properly if the top level is a sequence.Comment #7
sunIt's a double-edged sword:
By allowing this, we essentially assume that developers have a solid plan about their config requirements ahead of time and for the entire future. — Once you put a sequence at the top-level of (in particular) a
$module.settingsconfig object, it will not be safe to add a new top-level key to the config + schema later on. As in the examples here, the sequence key names can be any string that possibly exists.I doubt that even core has enough of a plan to be really sure. It's perfectly possible that
rest.settingsneeds some additional settings at some point later on. At that point, you either need a more complex module update or migration process, or you're forced to create and use a separate config object, which would have been unnecessary if there wasn't a sequence at the top-level and which is bad for performance.Even though it could be supported on technical grounds, it is good that we don't support it in my book, since it prevents people from running into a major trap.
Comment #8
alexpott@sun but otoh if a developer knows that the want to the root type to a sequence they can do this - and config will work just fine - until you try to create a schema for it. So saying we don't support it is not true.
A mapping is just a special form of sequence - in terms of the data structure they are both arrays.
Comment #9
alexpottFor example:
content_translation.settingsin HEAD works this way already. The top level key is a sequence and this only works because no one has tried to write a schema for it.Comment #10
sunGreat, so we already have the problem in HEAD:
What if a necessary change for Content Translation module has to add a setting to
content_translation.settings?We'll either have to rewrite
content_translation.settingsto use a sub-key for the sequence (API-breaking change), or we will have to use a new config object separate fromcontent_translation.settings, even though generic module settings are supposed to live in a$module.settingsconfig object and even though the entire problem could have been avoided by not using a sequence at the top-level in the first place.I understand that it's technically possible, but not everything that is technically possible is a good idea. :-)
Comment #11
alexpottFair enough but what if the configuration object was called
content_translation.entitiesComment #12
alexpottBasically, I just don't get why we just think we know best and restrict people in this way. Especially when they're not actually restricted.
Comment #13
sunRight, that's why I said that it's a double-edged sword:
If we do this, then there's a good chance that many developers will run into the trap.
If we don't do this, then we're essentially baby-sitting developers. (and yes, without an explicit protection/exception in the existing config schema validation in
Config::save(), that baby-sitting is not complete)IMHO, baby-sitting is a good idea here, since it's going to be exceptionally hard to recover from such a mistake later on.
Comment #14
alexpottBut there is no way of baby sitting developers here - in data terms there is not difference between a keyed sequence and a map. Unless we require schema. And people have been against that forever.
Comment #15
alexpottAlso I think it our job to design robust APIs that make it difficult break Drupal and easy to use. I don't think it is our job to prevent people making mistakes because (a) that is our opinion - do we really know better? (b) can lead to interesting new ideas (c) is it really the Drupal way to limit what people can do?
Comment #16
gábor hojtsyWe don't require schema, but its true that some schema limitations mandate some data structures if you do use schema, eg. a subkey with an identifier value to be used to identify dynamic data types (eg. views plugin ids). I don't have a strong feeling either way whether we should babysit shortsighted developers not using a mapping at the top. I think shortsighted developers will not care about schemas in the first place, and then config is a free form tree, so they will do whatever they like. So not really concerned that we could box them in somehow with an optional system...
Actual code review:
The first sentence is about config objects, the second is about the method which is very confusing. I only figured this out by reading the patch.
following?
This is confusing, why not implement that interface?
The two messages could use the same English. I know this is pre-existing in the moved code, but since we are doing this...
Comment #17
gábor hojtsyBTW I looked at config translation and there does not seem to be an assumption about a top level mapping implemented/hardcoded there.
Comment #20
gábor hojtsy#2212069: Non-English Drupal sites get default configuration in English, edited in English, originals not actually used if translated practically mandates that config objects are
sequencesmappings, it will add a langcode key on top level config objects. If they are defined as a sequence and the top level type is not a string, that will break schema validation.Comment #21
alexpottSo we've got an example in the wild! See #2635944: InvalidArgumentException' with message '$string ("") which was cause when we added a key to all configuration that is installed through the config installer in #2625258: LocaleConfigManager::updateConfigTranslations() deletes translations if a config object's name happens to match that of a shipped configuration object
Comment #34
mstrelan commentedIt seems like this is a bit contentious as to whether or not we should do it. Do we have any new perspective on this? There hasn't been any further comments in the past 7 years.
Comment #35
penyaskitoI think this is something we should allow. Probably didn't have any traction because of the existing workaround (as indicated on the OP by alexpott, an example of adding
entities:there as root), and we just got used to it.Last time I missed this was not possible: one week ago.
Comment #36
berdirThis is a won't fix at this point. We have a default config_object schema with multiple standard keys, the top-level must be a mapping. Having to group a list inside a key seems like a small price to pay.