Problem/Motivation
For CMI 2.0 we worked on a new API for managing config, it is even better than config_filter, at the very least for the developer experience. See the change notice #3066005
Proposed resolution
The new API for config_distro could be simply Drupal\config_distro\DistroStorageTransformEvent.
We can make use of many of the other classes that come with 8.8 but initially we can just fork them to the config_distro namespace and then later use the one from core as that will never be part of the api of config_distro.
Remaining tasks
- Copy relevant code from what is currently in config_environment in 8.8.x
- Create new event (for now not extending the core event, just copy it so that it also works for Drupal 8.6)
- Create a DistroStorageManager in the image of the
Drupal\Core\Config\ExportStorageManager (yes it is not lost on me that we actually only do importing and that our storage manager has more the role of Drupal\Core\Config\ImportStorageTransformer But looking at both of those classes one can see that they basically do the same thing: take the storage and dispatch an event to transform it; This is precisely what we want to do, plus if we do the storage manager we can continue to provide the config_distro.storage.distro service.)
- Create a new
config_distro_filter submodule and enable it in an update hook in config_distro.
config_distro_filter then implements a event subscriber and does the config_filter magic with the existing config_distro plugins so everything works in a backwards compatible fashion. (see #3050529: Create 2.x branch using the new core api for inspiration)
User interface changes
None
API changes
Events instead of plugins
Data model changes
None.
Release notes snippet
New event based API inspired by CMI 2.0 replacing the config_filter plugins.
Comments
Comment #2
bircherComment #3
Anonymous (not verified) commentedAttached is a first attempt to backport
config_distroto use the Transform API. Would be good to know if this is on the good track. If not, feel free to say so.The submodule is named
config_distro_transforminstead. I think we should avoid the suffix_filter, because it makes me think aboutconfig_filterwhich is what is being replaced. Anyhow, naming could still be better.Comment #4
bircherHi,
Great work! you are on a good track!
We need only one event and only one event name because we don't import and export. We transform the active storage into a virtual storage and import that. You can think of the config distro storage as "How would my active storage look like if all the distro updates had been applied.
The new sub module I am asking to be created is not meant as a test module, and the name does not have filter in it by accident.
The module description could be: BC bridge to the previous config filter plugin api.
If we just change wholesale to a new API design then all existing sites will be broken and all the modules currently integrating will stop to work. So instead of having the old api still around we move it to a new module and install it in an update hook. this way if you update everything still works and if you install it new you only get the new api. Technically the other modules then depend on config_distro_filter but that is out of our hands here.
That said, we of course need tests too. But since we don't have any I am not insisting on that here.
Here some initial review.
probably doesn't need state or be an event subscriber itself see below.
This is added by drupal.org so we don't need it in our module code
Too much copy paste I guess
This is what I meant with getting inspired by the 2.x patch for config_filter. This should have as its arguments only @config_filter.storage_factory
You can do the thing that happens in the import transformation on the config_filter patch
Ie the storage form the DistroStorageTransformEvent is the "active" so you get a filtered storage for the event storage, then you copy the filtered storage into a temporary one and then the temporary one back to the event storage.
We don't care about the core events at all, just our new event that is inspired by it. Config Distro is doing something orthogonal.
We don't need to touch the controller in this patch at all since we keep the distro storage service.
too much copy paste, we don't need this at all. We might have one that describes the new event we are adding. but then it is definitely not related to the core one.
Too much copy paste, we don't need the import transformer because our distro storage is already doing that job.
yes the managed storage we copy from core, we may want to add a different todo though
I forgot in which Drupal version we added that I think 8.7, we can copy the trait too or make the minimal version 8.7
We don't need to do that conditionally, we dispatch the event every time the storage is needed. The managed storage only calls this once.
This is the wrong event name, I would use 'config_distro.transform'
Also make sure that the storage is either a memory storage or uses the config_distro table, we don't want to interfere with the internals of the core API.
No need to cache anything.
We will always keep this event in config_distro
We don't need to change the controller here. But if you want to check out some of my experiments for the new core module check out
#3048860: Create Config Environment API comment #4
We may want to complicate things too for config distro or have some more options, like selecting which "packages of updates" to include etc. But for a fist approach I would keep it simple.
Comment #5
bircherah another small comment..
we can make the config_distro_ignore depend on config_distro_filter and not change anything in that for now.
Then updating config_distro_ignore would become a example exercise on how to update modules to use the new api in a followup.
Comment #6
Anonymous (not verified) commentedThanks for reviewing! I've tried to take your comments into account.
onImportTransformthen? And rename it.config_environmentis using it? Could you explain what to change in the@todo?Comment #7
bircherYes looks very good!
I am just on my phone at the moment, so not an in-depth review, just some things I noticed even without dreditor.
1) I think it is much better, yes.
4) The following line is using the wrong storage name:
$filtered = $this->filterStorageFactory->getFilteredStorage($storage, ['config.storage.sync']);we want the distro storage, ie what plugins would annotate for, see the config_distro_ignore plugin.5) yea, to make it more readable it could be
onDistroTransform, that is internal code though so it would work with any name.9) yes we use it in the same way, but in config_environment the comment is about moving it to the right location, here we remove the class altogether when 8.8 becomes the minimal version we support. (provided the class gets to 8.8)
10) I think requiring 8.7 is ok. I think also the read-only storage was added in 8.7
15) The config_distro_ignore has now its core key commented out, it should instead depend on config_distro_filter
16) We also need an update hook enabling config_distro_filter
Comment #8
joegraduateThe attached patch is an attempt to incorporate the improvements outlined by @bircher in #7.
Comment #9
bircherCool!
Thanks for the patch, there are a few dependencies that need to be sorted out though.
This is just a very quick review, manual testing on a site that this module is used would be great too.
We don't want to depend on config_environment.
But instead of depending on cores config this module depends on config_filter
also don't depend on config_environment
config_distro_ignore should depend on both
we don't have or need a class alias, so this comment is not necessary
This comment also need to be updated. We can remove this class when 8.8 is the minimum supported version.
Comment #10
Anonymous (not verified) commentedThe attached patch is an attempt to incorporate the improvements outlined by @bircher in #9.
I've also tested on
8.8-beta1and got the expected message:Module config_distro cannot be enabled because it depends on the following modules which could not be found: config_environmentComment #11
joegraduate@wouter.adem, patch #10 appears to be incomplete, i.e. it is missing most of the files added by earlier patch versions.
Comment #12
Anonymous (not verified) commented@joegraduate Thanks for the catch. That happens if you try to do several things at the same time. My apologies.
Adding the correct patch now with @bircher's comments fixed.
Comment #13
joegraduateComment #14
bircherSome more remarks.
:D Of course we shouldn't add the patch file.
This new line is a super-nit-pick. We can also fix it on commit.
Sorry for not having noticed this earlier.
While of course config_distro_ignore now depends on config_filter through config_distro_filter, this update hook needs to be on the config_distro module. This is the best we can do to not disrupt current installations. Since all current modules that extend config_distro do so by means of config filter plugins. So we need this update hook to run regardless of config_distro_ignore but config_distro will not depend on this new module, so site builders are free to uninstall it again.
Comment #15
Anonymous (not verified) commentedThe attached patch is an attempt to incorporate the improvements outlined by @bircher in #15.
Comment #16
joegraduate@bircher, a couple of questions:
Comment #17
bircherRE #16:
Good questions!
Comment #18
kingdutchI think we should make a change for discoverability's sake.
line 65 of
DistroStorageManager.phpreads$this->eventDispatcher->dispatch('config_distro.transform', new DistroStorageTransformEvent($this->storage));Here the event name is hardcoded.
We should instead change this hardcoded string to
ConfigDistroEvents::TRANSFORMand add the string to that class. This is already done for the import event and avoids typoes in the event name.Comment #19
Anonymous (not verified) commentedAdding a fix as per the comment #18.
Removed an unused class.
Comment #20
joegraduateThe changes in #19 look good to me!
Comment #21
a.dmitriiev commentedHi, I am interested in these new features. Are there any plans to apply the patch from #19 and create a new stable version soon? It is also Drupal 9 coming in 2 weeks, it would be nice to have config_distro updated till then.
Thanks!
Meanwhile I am testing the patch, will get back soon with feedback.
Comment #22
nedjo@a.dmitriiev feedback on the testing the patch would be great. It's particularly of interest to see how the patch works in combination with any existing implementations using Config Distro, such as Configuration Synchronizer. You've been active recently in that module's issue queue (thanks!). Can you report on how it's working with this patch?
Comment #23
a.dmitriiev commentedPatch in #19 worked for me on Drupal 8.8.5. I did a real test run of `drush cd-update` command with 1 new field (field storage and field instance configs) and changes to form display and view display and bunch of changes in image styles configs.
Everything works as expected.
P.S. I am using config_sync module with all dependencies, including config_distro
Comment #24
a.dmitriiev commentedComment #25
a.dmitriiev commentedActually we are heavily using config_sync and config_distro in our projects and are very glad to have those modules in our distribution, because we control all config updates with them.
Thank you so much, all involved!
Comment #26
nedjoThanks all for the work in this issue.
Given where we are now - near the end of the 8.8.x release cycle - should we consider instead creating a 2.x branch where we don't need to bring forward compatibility for core 8.7.x? I'm thinking that doing so would mean modules that still rely on
config_filterfor integration withconfig_distrowould need to upgrade toconfig_filter2.x, but otherwise could be expected to keep working until they refactor to use the transformation API.And a detail in the current patch:
In the implementation we're replacing, we use a
GhostStoragethat wrapsconfig.storage. Presumably we should retain that rather than introducing a new database storage. If we stick with 8.7.x compatibility, doing so would mean either (a) retaining the current dependency onconfig_filteror (b) forkingGhostStorage(which hasn't gone into core) andReadOnlyStorage(which has, but only as of 8.8.x).Comment #27
nedjoI take that back, I hadn't looked at core's
ExportStorageManager, on whichDistroStorageManageris modeled and while I haven't spent enough time with that class to completely follow the logic I accept that the same considerations presumably apply here.This interface is no longer in sync with the core version, which throws an exception.
Should be a final class as its interface has a single public method.
This looks like it needs updating too. For parallelism with the core method presumably should attempt to get a lock and conditionally throw a
StorageTransformerException.Comment #28
nedjoThe problem here is we provide a
ConfigDistroFilterInterfaceand use the same in our own submodule,config_distro_ignore. So, yes, in the current 1.x branch we could drop core 8.7.x support and so avoid the need to fork some core code, but we can't skip straight to a version withoutconfig_filterand still maintain support for existing implementations, at least not without bringing forward some legacyconfig_filterintegration anyway, which would pretty much defeat the purpose of a 2.x branch.Comment #29
bircherRE #26 Yes we could use a MemoryStorage instead of a database, in core it is a database because of concerns with memory usage. We can not use the GhostStorage (can see but can't interact with) because we expect event subscribers to actually modify the storage.
RE #27 Yes we should also add a lock (and in general copy paste from core and use our storage database) +1 also for the final.
RE #28 Yes given where we are now we can drop support for 8.7, sites still on 8.7 do not get the security coverage and they can keep using the previous version of the module.
And since we have config_distro_filter that we enable in a update hook we kan keep this on 1.x, this way we have the backwards compatibility (yes modules using the filter plugins would now have to depend on config_distro_filter but we do that for config_distro_ignore here and we can follow up with third party modules providing these filters to either add a dependency on config_distro_filter (easy) or switch to the new API (more code). Since probably most of these modules are maintained by one of the people active in this issue I think we are fine with this too.
config_distro_filter works with both 1.x and 2.x of config_filter so once we remove config_distro_filter we cut 2.x in my opinion.
config_distro_filter is the bridge between the current config_distro and the api after this patch the same way config_filter 2.x is the bridge between config_filter 1.x and the new core API. (that is also why config_filter 1.x and 2.x have the same API but are different versions because the behaviour is different)
NB: I would remove the classes that are tagged in the patch to be removed, but crutially keep the event ours even if it looks very similar to the core event because then we can add stuff if we want later without a problem.
Comment #30
nedjo@bircher k, thx, I'll draft an updated patch.
Comment #31
nedjoHere's an untested draft of the changes outlined in #29.
Done.
Done.
Done.
@a.dmitriiev, might you be up for retesting (fixing up any obvious errors I've introduced as needed) and reporting back?
Comment #32
nedjoI did some testing with Configuration Synchronizer, not working so far. Steps and results:
/admin/config/development/configuration/distro. Result: "There are no configuration changes to import." This is as expected./core/modules/contact/config/install/contact.settings.yml, changing the lineuser_default_enabled: falseto read insteaduser_default_enabled: true. This simulates a configuration change coming with a new release./admin/config/development/configuration/distro. Result: The contact settings configuration item shows as having updates. This is as expected.Haven't yet tried debugging.
Comment #33
nedjoOops, forgot we'd added an update, so yeah, not running the update might break things ;)
I'll try to find time to retest. Meantime, adding in a couple more version constraints and such.
Comment #34
a.dmitriiev commentedI will do some testing today and tomorrow.
Comment #35
a.dmitriiev commentedok, I had to clean the caches after running update, because on Configuration Import page I've got this message:
After cleaning the caches, the message was gone and the configuration was imported properly.
Comment #36
nedjo@a.dmitriiev thx for testing and reporting back.
On the face of it that sounds like a bug internal to Configuration Syncrhonizer and not one in Config Distro.
Comment #37
nedjoDid some more testing, this is all looking good. I'll apply and cut another alpha release. That'll allow a corresponding Configuration Sychronizer release
To use in Drupal 9 with Configuration Synchronizer requires the patch from this core bug: #3152320: [backport] ExtensionInstallStorage::createCollection() produces error. Here are full steps for testing I used in Drupal 9. As soon as we have new releases for Config Distro and Configuration Synchronizer, steps 3 and 4 will no longer be needed and step 5 will use stable rather than dev releases.
/admin/config/development/configuration/distro. Result: "There are no configuration changes to import." This is as expected./core/modules/contact/config/install/contact.settings.yml, changing the lineuser_default_enabled: falseto read insteaduser_default_enabled: true. This simulates a configuration change coming with a new release.drush config:get contact.settings user_default_enabledto confirm the initial setting of the setting we edited. Expected result:'contact.settings:user_default_enabled':true./admin/config/development/configuration/distro. Result: The contact settings configuration item shows as having updates. This is as expected.drush config:get contact.settings user_default_enabledto confirm the updated setting of the setting we edited. Expected result:'contact.settings:user_default_enabled':false.Comment #39
nedjoCommitted, thx all!
Comment #40
nedjoAdding missed credits.