The standard site install consists of few default things, like filtered HTML input format and and taxonomy vocabulary 'Tags', so a vast majority of drupal installs *will* have these components, however some will not.
So if a contrib feature created module wants to include a tagging field, it's in a bind. It should not include the tag vocabulary as features is already defined (as it's presumption and asking for conflicts), but it cannot assume the tag vocabulary is there. (Features will currently try and include the tax vocabulary upon including the field).
This also butts into the issue is #1064472: separate fields from field instances (SemiDups: #1321176: Enable export of generic or abstract compontents (e.g., fields) that can be applied to multiple entity bundles #1277854: Faciliate altering features, e.g., export field display settings separate from field data structure). The current situation is not good for fields ( means duplicate code for the base field every instance of a field -- aah!) Consider the body field, which is automatically added to all node types on creation via the ui (right?). It has a base definition, which may have been customized for that site, and never have been provided via features. Imagine you got 8 fields features all from different sources, all with instances of the body field, all with separate code defining the base field, that may or may not conflict with the definition that site has. Now, assuming one of those patches go in, it's possible for only one definition, but where would it go?
I have some ideas, but none I particularly like yet.
Comments
Comment #1
Grayside commentedThe general concept I've come up with is a way of making some exported components optional. A component could be marked as requiring a decision via UI or programmatic configuration to determine whether it should be loaded. In this way, you could build systems that allow a sort of component "Select or Other" approach.
The hard part here is incorporating the necessary indirection of references to all exported components, so that Views (et al) will use the correct Vocabulary.
The first part (how to handle workflows of defaulting) could have an advanced behavior so that any conventions (perhaps defined by Kit) could be specified. E.g., "Define the 'featurename_tags' vocabulary only if we can't find the 'tags' vocabulary."
Taken a step further, and resolving both complexities, would be something like so:
In the case of a "fallback" status, it only installs "tags" if it doesn't already exist in the system. This would require some very careful handling to avoid conflicts and timing issues. Other implied statuses might be "disabled", in which the component is exported, but must be programmatically activated or reverted instead of automatically. (I've long thought an alternate syntax as in the first line above would be a great way to support building advanced workflows in contrib.)
Approach #2
An alternate approach entirely would be to build special support (probably in Features Overrides or similar) to allow any component to be mapped to another. Meaning your "tags" dependency in a shipped feature could be changed to "keywords" in a given site, and this override itself exported. Remapped components should be noted, and *not imported* by features.
Comment #2
hefox commentedI think it cannot be dependent on a decision via the UI; features need to be enabled and created via drush en and drush features-update (course, could add some decision in features update, but likely not features enable).
For features core itself, I do like the idea of components that are only installed if they don't exist. Ie, a features that uses tag feature would have the tag vocabulary exported, but would only install it if it didn't exist or wasn't provided by someone else -- ie a fallback. This is a concept that would have to be understood by exportable in general though, not just features (though it's mostly features provided exportables that run into this).
There's an issue queue somewhere about being able to rename/change component references. That's a good idea but don't think it's necessarily the default solution for this problem; good add on.
Comment #3
Grayside commentedActually, using the pre_command hook in drush you could introduce UI tweak the database, and have that modify the component import process.
But UI of either flavor is an awkward solution, just by virtue of complicating how Features work for site builders. Better to impact the strangeness on developers.
Comment #4
hefox commentedPeople creating features are not necessarily developers so they need a simply process also (I anticipate them coming across this issue easily, ie tags and field body, i.e. it's not a rare issue), or do you mean developers of features?
Comment #5
Grayside commentedRight, just saying the person installing the module should have an easier experience than the person building the module, if at all reasonable.
Comment #7
ezra-g commentedI'm experimenting with this issue for the Commons distribution. For example, http://drupal.org/project/commons_radioactivity wants, when enabled, to add a radioactivity field to several node types without becoming a dependency for the features that define those node types.
One approach I'm currently tinkering with is,
- with #1064472: separate fields from field instances applied
- to define a hook in the module that defines the field so that other modules who want the field added to their content type can say "Hi, please add an instance of this field to my content type."
- The defining module then implements hook_field_default_field_instances_alter(), wherein it defines this super simple hook.
- The super simple hook is invoked, and each implementing module returns the name of its content type(s) that should have the field added.
- The defining module adds a field instance to the content type by altering with hook_field_default_field_instances_alter().
So far this works well, but has these problems:
- The module which receives the field instance has the instance and the defining module added as a dependency (probably easy-ish to fix with hook_features_export_alter() or similar.
- The module which receives the field instance shows as overridden with a greyed out field definition, even though it successfully adds the field when removed from the receiving content type via the UI. Manually adding the field instance to that module's info file resolves the override.
I'll link to some code examples when I've got this proven to a point that it's not a "horrible approach" (tm).
Comment #8
hefox commented