I may be missing something here, so apologies if this is an option I just haven't found.
Problem/Motivation
When a Feature module is reverted, no hooks are invoked on that module. hook_features_revert() is invoked on the components contained within that Feature module, but nothing on the Feature is called.
Let me explain my current use case to give you an example of how I would like to use this. I'm upgrading an existing D6 site to D7. Some of the stuff in the D6 site config was rolled into Features for D7, such as an events module that contains the Event node type, some views, menu items, etc. However, I need to move a menu item (User Group Meetups, lets say) underneath the Events menu item that's added by the View. Until the Feature module is enabled and reverted, that Events menu item doesn't exist in the DB, so I can't move the pre-existing (from D6) User Group Meetups menu item because there is no mlid from the Events menu item to use as the parent ID (plid) on the User Group Meetups menu item.
I sure hope that makes some kind of sense.
Proposed resolution
This problem and many others could be solved by invoking some hooks on the Feature module itself when actions are taken on it. _features_restore() runs revert, rebuild, enable, and disable, so it would make sense to invoke these hooks there.
foreach ($items as $module_name => $components) {
// Invoke pre hook
$pre_hook = 'pre_' . $restore_hook;
module_invoke($module_name, $pre_hook);
foreach ($components as $component) {
// ...yadda yadda yadda
}
// Invoke post hook
$post_hook = 'post_' . $restore_hook;
module_invoke($module_name, $post_hook);
}
This would make the following hooks available on Features modules only:
hook_pre_features_revert()hook_pre_features_rebuild()hook_pre_features_disable_feature()hook_pre_features_enable_feature()hook_post_features_revert()hook_post_features_rebuild()hook_post_features_disable_feature()hook_post_features_enable_feature()
Remaining tasks
- Determine if this can already be done and I've managed to overlook it.
Determine if these hooks should take any arguments.Implement the hook invokations that I sort of coded in the block above, and make sure they work. If so, roll them into a patch for community testing.
User interface changes
None
API changes
Eight new hooks available to module developers, listed above.
| Comment | File | Size | Author |
|---|---|---|---|
| #25 | features-add_pre_post_install_hooks-1782492-25.patch | 2.72 KB | duaelfr |
| #19 | features.module.patch | 1.9 KB | kholloway |
| #10 | features.patch | 3.13 KB | MarcElbichon |
| #4 | 1782492-4.patch | 3.59 KB | BrockBoland |
| #2 | 1782492-2.patch | 2.57 KB | BrockBoland |
Comments
Comment #1
davidburnsI support this decision! +1
Comment #2
BrockBoland commentedFirst pass attached. This adds the hooks I mentioned above and API documentation for them.
Comment #3
BrockBoland commentedThis might not work after all. Running
drush fraresults in calling_features_restore()once for each component, so the revert hooks would fire for every component, which is not what I had in mind.But, this might be OK: move the
module_invoke()inside of theforeach ($components as $component)loop, and pass the$componentto these new hooks as an argument. Not quite what I was going for, but it could do the job.Comment #4
BrockBoland commentedUpdated to move the call inside the loop, and add the $component to the API documentation.
Comment #5
mpotter commentedComment #6
hefox commentedLooking at the patch quickly but not actually reading the issue, I've wanted something like this at some point
Related/semi-duplicate of reallylongissue #981248: Allow a feature to execute a secondary install function after features components are created ?
Comment #7
BrockBoland commentedYeah, that is pretty similar (though to be honest I only looked at the patch and didn't read the discussion)
Comment #8
mpotter commentedThe patch in #4 seems to be working for me.
Comment #9
mpotter commentedCommitted to ce3863e!
Comment #10
MarcElbichon commentedI want to know where ALL components have been enabled.
Patch invoke pre and post hooks with no arguments before first and after last component.
Comment #11
BrockBoland commentedThat's an idea. Haven't tested the patch, but it looks good. Should we track that here or open a new issue for it?
Comment #12
bleen commentedI love #10 ... but I think that you should open a new issue and re-close this
Comment #13
Cauliflower commentedI created a seperate issue and patch for this, see http://drupal.org/node/1844566#comment-6749250
Comment #14
vinmassaro commentedCan I get an example of how to implement this? My feature creates a view with a block, and the block configuration is being exported using features_extra. Unless I manually revert the feature, the block configuration is not stood up and shows as overridden. I'm trying to revert the feature immediately after it is enabled.
Inside people_listing.module, I have:
The features_revert() bit works correctly from
drush php-eval, but does not seem to work from this hook. Thanks.Comment #15
BrockBoland commentedI'm not sure: I haven't tried calling
features_revert()directly, so I'm not sure about the arguments. Have you confirmed thatpeople_listing_post_features_enable_feature()is running, at least?Comment #16
vinmassaro commented@BrockBoland yes, it is running. I swapped out the features_revert() with a drupal_set_message() and it's outputting after I enable the people_listing feature. My features_revert() bit runs correctly from drush or a block.
Comment #16.0
vinmassaro commentedUpdated Remaining Tasks
Comment #17
kholloway commentedThis is great work. My only question is these hooks are more like listening hooks in that you are only passed read-only copies of what is about to happen.
It would be really nice if the hook (specifically alter hooks) could actually get more control of the process before it happens.
For example when a component is about to be reverted you can call the pre-hook to know exactly what component is about to be reverted (which gives you a nice way to figure out what is about to be changed) and there is a post-hook to know the change is complete but there is still absolutely no way I have figured out to stop or alter the change.
These hooks are great if you want to react to things you can't change in the flow of a feature but they don't seem like enough if you want to, for example stop a revert from happening at all depending on the component.
Of course if I have missed something please let me know :)
Comment #18
kholloway commentedRegarding my comment (#17) I added a new hook that allows you to alter the $items (components) list before a revert/alter/enable/disable is performed. The hook is called:
hook_features_restore_alter
I am open to suggestions on making this better but it was the missing link for me to be able to actually alter the components before the above 4 actions are performed. Without this hook you can only watch before they happen ;)
My hook api example shows one way to use it though there are of course many others.
Comment #19
kholloway commentedComment #20
kholloway commentedApologies. I uploaded the wrong file. Please see the latest file I uploaded.
Thanks
Comment #21
Growiel commentedHi,
Sorry to reopen this but I think it's the right place.
The hook_post_features_enable_feature() is called at the wrong time. Let me explain.
I have a Features module that creates some field_bases and field_instances and I need to change the permission on those (with the Field Permission module).
The problem is, when the hook_post_features_enable_feature() is called, the field are not yet created, and I get an error on my code to manage the permissions.
This hook needs to be called last, after everything has been imported and created, so the content is available to the module to alter it in anyways possible.
As a side note, if one day Features could auto export Field Permissions, it would be neat.
I hope I make sense.
Comment #22
kholloway commentedMoved my issue/solution (patch) to this new issue:
https://www.drupal.org/node/2341637
Comment #23
jastraat commentedI am wanting to add some default taxonomy terms to a vocabulary defined by a feature. Unfortunately, hook_post_features_enable_feature() does not work for this, and it seems like this would be a relatively clear use case for such a hook.
Suggestions?
Comment #24
jastraat commentedComment #25
duaelfrIt has been a long time I wanted to add these hooks into Features.
It includes 2 new hooks and their related documentation.
This patch does not introduce any side effect as it does not alter existing code nor change existing variables values.
Bonus: even if this patch has been made for 7.x-1.x, it also applies on 7.x-2.2
Comment #27
dinarcon commentedThe patch has not been applied to any of 7.x-1.x, 7.x-2.x, 8.x-3.x It cannot be found in the git log. After manually applying the patch, I could use it as described by @DuaelFr in #25
Comment #32
dgtlmoon commented+1 works well here, thanks! (2.x and 2.5 tested)
Comment #33
mpotter commentedNot sure why this got re-opened.
The OP was committed to Features back in Nov 2012 here: https://www.drupal.org/commitlog/commit/9184/ce3863e445fe07c47e79d6a82e9...
The comment in #26 was auto-generated by the drupal.org commit bot when the 8.x branch of Features was added.
Any additional requests or work on this issue such as in #25 need to be submitted to NEW issues (see #13). You should never re-open an old issue especially with a patch that was previously committed. Otherwise both the d.o testbot and other users get confused.
Comment #34
duaelfrSorry Mike, I didn't read the entire issue but just seen that it was still active.
I'll open a new one asap.
Thank you for your awesome work on this module.
Comment #35
dgtlmoon commentedOk so my confusion then - I wonder why the patch still applied cleanly?