Problem/Motivation
Currently all feature bundles are saved to the features.bundles simple configuration value. This makes it impossible to export just a single feature bundle to code. You always have to export the whole setting containing all available bundles. It's also not consistent with parallel configuration management in core, which uses ConfigEntity.
Proposed resolution
Refactor the FeaturesBundle class to extend ConfigEntityBase. Since bundles have an associated plugin collection, this should also implement EntityWithPluginCollectionInterface. At a minimum, we'll need to override EntityWithPluginCollectionInterface::getPluginCollections().
class FeaturesBundle extends ConfigEntityBase implements FeaturesBundleInterface, EntityWithPluginCollectionInterface {
}
A fairly close parallel is FilterFormat. Like FeaturesBundle, it includes associated plugins that can be enabled, ordered, and configured.
We might want to consider changing the current interface to something close to a filter edit form, e.g., admin/config/content/formats/manage/restricted_html, which includes configuring the config entity and associated plugins on the same form.
Implementation notes
Add a class FeaturesBundlePluginManager:
class FeaturesBundlePluginManager extends DefaultPluginManager implements FallbackPluginManagerInterface {
}
(This assumes we use the current 'default' bundle as a fallback.)
Adapt or move most or all of the bundle handling methods from FeaturesAssignerInterface to FeaturesBundlePluginManager.
In line with the config entity conventions, rename the following bundle properties:
machineNamebecomesidnamebecomeslabel
Add a service corresponding to the bundle plugin manager:
plugin.manager.features_bundle:
class: Drupal\features\FeaturesBundle
parent: default_plugin_manager
Use the service in a method called by FeaturesBundle::getPluginCollections().
Remaining tasks
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #23 | features-bundle-entity-2569149-23.patch | 50.62 KB | nedjo |
| #23 | interdiff.txt | 26.82 KB | nedjo |
| #18 | 2569149-18.patch | 27.83 KB | mpotter |
| #17 | 2569149-17.patch | 25.55 KB | mpotter |
| #12 | interdiff.txt | 3.42 KB | dawehner |
Comments
Comment #2
mpotter commentedI'll give this some thought. We never thought about sharing individual bundles. Is there a reason your multiple developers just wouldn't share all the bundles for the project? Are you really changing a bunch of bundle assignment plugin settings that need to be shared?
Comment #3
hctomI just thought about it when playing around with bundles and that it would be a great way to create some sort of presets you may give to other developers, so they automatically have some predefined packaging presets that e.g. follow some kind of coding rules in a company or something similar.
And if you want to share these among projects that might not use the same contrib bundles (like
panopolyoroa) this would be hard, because you'd have to merge the external bundles with your own presets.Comment #4
mpotter commentedA bundle consists of both a namespace as well as assignment plugin config settings. The assignment plugin stuff is only needed if you plan to create *new* features within that bundle. So unless you were actually creating new modules for panopoly or oa, you wouldn't care about those bundles. Those bundles will get created automatically because of the "bundle" key in the module.info.yml file for modules that are part of those distros.
So again, I don't see that your devs would need different bundles across your projects. You'd have some company-specific or project-specific bundles that you'd share, and you'd include any other auto-detected bundles with their defaults. Or just put your company and project bundles into the features.bundles yml file for your site and let the others just get auto-detected. The features.bundles.yml file is just the initial config for your site and not the "active" config that CMI uses.
Honestly, this is one of those cases where you should probably just be using CMI to deploy your bundle configuration between your different environments, rather than storing the features.bundle.yml into it's own feature "module". The features.bundle file isn't part of any actual functionality that you might be creating in your features modules (like a Photo Gallery feature, etc). You shouldn't be thinking of using Features as CMI like it was in Drupal 7. Use CMI for deploying configuration and use Features for making modules of specific functionality (Features!)
Comment #5
hctomThank you for the wonderful session at DrupalCon and our little talk afterwards. So just to sum up what we discussed: It might really be useful to be able to export different bundles alone, because of their human-readable name and description. If you do not have these information the bundle would of course be autodetected on another site, but it wouldn't show up with the readable title/description, but only with the bundle's machine-name. So with having the opportunity to export a single bundle configuration (based on ConfigEntity), you may pass this information along with your bundled feature modules. Besides of that you can unify the UI by using ConfigEntities, because those already provide real good UI listing etc.
Did I forgot something?
Comment #6
nedjoSounds good. This change could also facilitate distro contributions in that a distro will be able to export and ship with its bundle settings (in e.g. a distroname_devel module) so that anyone wanting to contribute can access a standard set of plugin configuration for the distro.
Comment #7
nedjoPresumably we would remove our existing use of the variables features.assignment.yml and features.settings.yml as well as features.bundles.yml and replace all three with a single default bundle entity that we ship with. Then admins can clone that bundle to create their custom ones.
Comment #8
nedjoSketching in implementation notes.
Raising to major. We should complete this prior to a beta, since it will break backward compatibility.
Comment #9
mpotter commentedYep, this would change the API, so it's a beta blocker.
Comment #10
nedjoComment #11
dawehnerStarted to give it a try.
Comment #12
dawehnerJust a start of a test.
Comment #13
mpotter commentedShouldn't all these default plugins have "enabled: true"?
Shouldn't this be an integer value instead of string?
Overall this looks pretty good. And it's amazing how much cleaner it makes the code. At least we already had Bundles as an object!
Comment #14
mpotter commentedSo when this is applied we get errors on the site, even after doing a "drush cr". Specifically, it doesn't look like it's loading the default bundle. The code:
doesn't return any bundles.
Comment #15
mpotter commentedAhh, I have to uninstall Features and re-enable it. Should we bother with an update hook or just assume people using alpha versions can handle this?
Now, once Features is re-enabled, the error loading the site goes away, but on the Features page it no longer shows any auto-detected packages, even though I set the "enabled" flags to true. So my guess is there is still a missing refactor for handling the enabled plugins.
Comment #16
dawehnerThank you for providing some good feedback!
Yeah I guess this would be the easiest, good idea. Yeah I had the exact same problem locally and just could not bother dealing with it and reinstalled.
Will look into it and maybe wr
ite some basic UI test coverage for it? Can't be bad to do that ...
Comment #17
mpotter commentedOK, here is a new patch for people to try. Sorry I didn't do an interdiff.
Comment #18
mpotter commentedSorry, missed a file. Here is a better patch.
Comment #19
mpotter commentedNot sure "weights" is needed in the schema since each individual plugin has a weight propery
Comment #20
nedjoLooking good!
Testing the patch, I'm getting errors in creating a new bundle. Steps:
If instead I manually change the machine name from "default" to "test", I'm able to create a new bundle. However:
Stepping back briefly, on this form the functionality we're trying to retain is:
Suggested changes to achieve this:
Comment #21
nedjoI'm working on making the needed updates to
Drupal\features_ui\Form\AssignmentConfigureForm.Comment #22
dawehnerThat sounds like an actual better way to communicate what is going on, than what currently the UI implements. The concept of the default was really not clear for me,
when I first played around with it.
Comment #23
nedjoHere's an update addressing the issues in #2.
I've manually run through the basics of bundle creation and configuration and not found remaining issues.
Comment #24
nedjoNotes on a few of the changes:
In assignment plugin configuration form submit handlers, merge in changes to assignment plugin settings so as not to lose status and weight settings.
Add constant
AssignmentConfigureForm::NEW_BUNDLE_SELECT_VALUEand use this to designate the case where we're adding a new bundle.Change default values for bundle form such that they are empty for a new bundle. Also alter form generation logic to conditionally handle default bundle--for example, disable bundle label (name) form element for default bundle.
Move the default bundle constant from
FeaturesAssignertoFeaturesBundleInterfaceand use it whenever we are referring to the default bundle.Rename
FeaturesAssignerInterface::createBundle()to::createBundleFromDefault()and begin by cloning the default bundle. This ensures we start with the default settings, including assignment plugin configuration.Comment #26
nedjoTo clear the way for other issues, I've gone ahead and committed this. Thanks all! Any fixes can be done in follow-up issues.
I've moved further refactoring to potential followup in #2621658: FeaturesBundle should implement EntityWithPluginCollectionInterface.
The need for help text on bundles is already captured in #2490818: Add help to clarify purpose and usage of bundles.
Comment #29
dawehnerAwesome, thank you!
Comment #35
nedjo