Problem/Motivation
In #2098119: Replace config context system with baked-in locale support and single-event based overrides we baked language support into the heart of the configuration system. This was so we could efficiently preload language configuration overrides. Language overrides are using configuration with name format with language.config.XX.configuration_object_name in order to sort the overrides per langcode (XX is the langcode). Configuration translation access is managed with language module and config factory, writing is in locale module and config translation.
This approach still raises a number of problems for us:
- Config file explosion leading to unmanageable configuration stored in files - even if active moves to the DB we still want to have a sensible file structure in staging or a git repository.
- Filename length - we need to keep this less than 255 adding this whooping great prefix on the front does not help
- Because the language override configuration objects have different names schema don't automatically apply #2168609: Move config translations (language.config.[langcode]) in to new location
- Depending on how the language configuration is accessed configuration events sometime do fire and sometimes don't. In the configuration translation UI it is accessed both directly though configuration storage and through the config factory.
- Because language is special cased it is hard for other modules to do the same, domain language module would not be able to override the language values, because they are baked in with highest priority. Also there is no real implementation of overrides (outside of tets), so contrib has no real example to follow.
Proposed resolution
Language configuration overrides should have exactly the same name as the configuration they are overriding. They should be subject to schema validation. They just need to reside in a different directory from active configuration. The patch moves them to a subdirectory language/XX. Language override configuration should only be accessible through a LanguageStorage service. It should not involve the configuration factory since it is not overridable itself.
The patch completely removes all reference to language from the configuration system. Instead we add a CompilerPass to add objects with implement the ConfigOverrideInterface to the factory. During a loadMultiple the override objects are asked for overrides. All module overrides use the same mechanism (the event has been removed). The compiler pass is better than the events, because on English only sites, then no events are fired, and the compiler pass requires explicit registration, so that will only be added/invoked if needed, not all the time. Reading is performance critical, so this is good. Also, if there is no language, we don't need to handle the special case NULL language is ConfigFactory.
The result is a simpler config factory, replaceable config overrides, cleaner config directories, a real implementation of the config override system, there will only be one way to do overrides and the schema checking will be applicable.
Remaining tasks
- Cache key length is still an issue, the prefixing is still happening there.
- Make config imports also import the overrides.
- Consider implementing a LanguageConfigOverride class that is similar to Config separate, so it can provide CRUD but no language override for example.
User interface changes
None
API changes
(more to detail in writing)
| Comment | File | Size | Author |
|---|---|---|---|
| #24 | 9-24-interdiff.txt | 79.82 KB | alexpott |
| #24 | 2201437.24.patch | 135.48 KB | alexpott |
| #20 | Config overrides and language.png | 89.71 KB | gábor hojtsy |
| #9 | 3-9-interdiff.patch | 17.92 KB | alexpott |
| #9 | 2201437.9.patch | 105.46 KB | alexpott |

Comments
Comment #1
gábor hojtsyComment #2
sunNote that I already made very good progress over in:
#2190723: Add a KeyValueStore\FileStorage to replace e.g. ConfigStorage
In essence, it replaces the custom storage engines of the configuration system with regular key/value store implementations.
In the key/value architecture, a "subdirectory" is just simply a "collection".
The most important aspect: Stop coupling the config storage to the filesystem or a specific serialization format.
All of these will work to instantiate storage service for language-specific overrides:
Comment #3
alexpottPatch attached move language configuration into subdirectories and implements what is currently proposed in the issue summary.
However just before uploading I discovered that cache cids are also limited to 255 characters as well so the reuse of cache_config and add a prefix to the cache key will encounter the same issues as adding the prefix to the filename. So we either need to ensure config names are less then a certain length or use separate cache bins.
@sun and #2 we need to be able to listAll - until key value stores have that built in an assured then it's not a solution.
Comment #4
alexpottComment #5
alexpottComment #7
gábor hojtsyAll right, elevating to critical beta blocker in light of #2168609: Move config translations (language.config.[langcode]) in to new location. The sheer extent of API changes suggested is clearly beta blocking. Will close down #2168609: Move config translations (language.config.[langcode]) in to new location as duplicate.
Comment #8
gábor hojtsyInteresting stuff. Here are some code review comments. I'll keep digesting the changes for a while, there are lots of changes and I don't fully understand yet how all pieces fit.
Negotiators?
Woah, so these would be now services instead of event listeners? (That at least answers my puzzled mind from above where I've seen you removed the module override event).
I see why you changed $name to $extension_name to avoid confusion with config names. But this is not consistently done in the uninstall code. And nonetheless seems unrelated?
typo
So why do these need to be services now compiled to the container?
This is distinctively harder to do / more ugly looking.
typo
Woo, its own storage, fancy :)
Fancy! This actually looks more understandable.
Not sure where else would be possible?
Why both a const and a method?!
Comment #9
alexpottSo whilst writing the following comment:
I realised that of course langcodes can be longer than 5 characters. I think we need to reduce Config::MAX_NAME_LENGTH which at the moment in 250. The question of course is to what. @sun's work on moving config storage to a key value store will help here since a collection is not part of the key. The alternative to do implementing either of the former solutions is to have a cache bin for each language :(
Comment #11
alexpottComment #12
gábor hojtsyIt would be great to see a before/after architecture comparison (IMHO would be great as figures). If nobody else comes around to this, I may be able to do this late this week (I'll hopefully be able to sync up in person with Alex Pott too in London in the meantime).
Comment #13
xjmComment #14
Anonymous (not verified) commentedthis doubles the storage calls for multi-lingual sites. i have no words.
Comment #15
alexpottBut adding an arbitrary prefix to the configuration object name to denote overrides breaks schema and will fall foul of the max config name length. Let alone the impracticalities of dumping everything into the same folder. We can not have everything. If you want to run a high performance multilingual site you are going to need to cache your configuration in something other than the DB. And in fact I would argue the same for a high performance fullstop.
Comment #16
catchI'm not that bothered about the extra cache i/o from language overrides. The main problem we have with cache i/o in CMI is pre-loading of configuration objects. So at the moment this might mean 2 x 25 cache hits which is pretty bad. With pre-loading implemented we're looking at more like 2 x 1 or 2 x 5 or whatever, which is going to be better than the monolingual case now.
It'll also be better than i18n language overrides in Drupal 7 where there's a parallel variables table iirc + locale/t() integration for configuration entities now - or at least not worse.
Comment #17
gábor hojtsyIt is definitely better than Drupal 7 and also more flexible than current Drupal 8 with support for swapping out by eg. language domain or other alternate implementations as needed.
Comment #18
vijaycs85Comment #19
gábor hojtsyJust had a discussion about this at DrupalCamp London. Here are the raw notes:
Also updated issue summary with better versions of the summaries (not just copied the raw notes :D).
Comment #20
gábor hojtsyHere is a visual summary to help us move forward. Also adding to the issue summary. Editable at https://docs.google.com/drawings/d/1TiSqEVGUFoi3zMtK7fHop_wfyLJZ_ddl-vXe...
Comment #21
gábor hojtsyComment #22
gábor hojtsyComment #23
Anonymous (not verified) commentedi don't like this patch, i'd prefer we address the limitations listed in #19 in smaller patches. however, i'm not gonna work on that, so i'm happy to help this land.
alexpott++
GaborHojtsy++
Comment #24
alexpottSo I've spent the weekend working on this and scope creeps.
Aims of the patch
Aim 2 has impacts on Configuration synchronisation since how can we know about the new storage directories if language is not yet enabled? Furthermore, even if language is enabled the current ConfigImporter it not built to handle multiple storages.
So the question is could we go back to the patch in #2168609: Move config translations (language.config.[langcode]) in to new location? I don't think so because of the issues with the length of config object name - the only way around it might be shorten the max length and special case language config. However langcodes can be up to 7 characters long so the max needs to be shortened to 227 and the config prefix needs to be checked for in ValidateName and max allowed increased to 250. However in my opinion this type of solution is exactly the type of thinking that has got us into this mess. Special casing and hacking language into CMI is going to lead more of this.
Way forward? (each step could be a separate issue)
Comment #25
gábor hojtsyI think this starts to reach into way too many areas. We should maybe start by breaking out the compiler pass and the wrapping of overrides into its own issue, get that in and then continue forward... The extent of changes in this patch and the reach it has far and wide makes it hard to believe people would agree on all fronts at once :/
Comment #26
xjmComment #27
gábor hojtsyWe agreed on breaking this up. Here is one of the items: #2215503: Use services instead of event subscribers for config module overrides. I believe Eli-T is working on another part.
Comment #28
eli-tPart 1 split in [#8561409-24] has passed tests and is awaiting review under #2215413: Split the Config class into StorableConfigBase and ConfigBase. Make ThemeSettings inherit from ConfigBase.
Comment #29
gábor hojtsy- #2215503: Use services instead of event subscribers for config module overrides is green and ready for review.
- #2215413: Split the Config class into StorableConfigBase and ConfigBase. Make ThemeSettings inherit from ConfigBase. only has a minor review feedback to fix but otherwise looks good :)
Comment #30
xjmSince this is a meta, let's make it active so we can get continued architectural input here.
Comment #31
gábor hojtsyI'm hard at work on #2219499: Generalize language config override responsibility which will break out the language override features. It will NOT introduce its own storage, so diffs, deployment/install/uninstall/sync are still not affected. There is considerable code here still to handle that, so this issue will still not be fully solved, but that is a well rounded problem space we can cover.
Comment #32
gábor hojtsy#2219499: Generalize language config override responsibility now has the config language refactoring and its only a 70k patch. Much nicer to review :) Feedback welcome there.
Comment #33
jessebeach commentedComment #34
gábor hojtsyThe final(?) sub-issue then is #2224887: Language configuration overrides should have their own storage :) We still have some code from @alexpott above to put in there :)
Comment #35
gábor hojtsyComment #36
gábor hojtsy#2224887: Language configuration overrides should have their own storage has all the remainder of this one, so closing this down as duplicate. Will update the issue summary there to carry over all remaining info that applies.
Comment #37
gábor hojtsyYay for only one issue left.