UPDATE:
The suggested change has a design problem as explained in comment #4.
Idea (original text)
I would like to introduce a hook that is fired every time we see a change in the menu_router table.
This hook will replace the hardcoded call to _system_navigation_links_rebuild() during menu rebuild. The system navigation menu will become an optional feature, provided by an optional module (still shipped with core, if you want).
Suggested anatomy of the hook:
<?php
/**
* Implements hook_menu_router_update().
*
* @param $menu
* The full $menu array, as we know if from _menu_router_save() and friends, keyed by router path.
* @param $insert
* All newly inserted items, keyed by router path.
* @param $update
* All updated items, keyed by router path.
* @param $delete
* All deleted items, keyed by router path. (alternatively, just the paths)
*/
function systemnav_menu_router_update(array $menu, array $insert, array $update, array $delete) {
.. // use the given crud data to rebuild the system navigation menu.
}
?>
Obviously there is still space for design choices in here. For instance, we could unify the crud data into one argument, so it would be $crud['insert'], $crud['update'], $crud['delete'].
Dependencies:
This solution depends on the diff-based technique as in #512962-236: Optimize menu_router_build() / _menu_router_save(), which is all green and waiting for more reviews.
I am not going to produce a patch for this issue, until this other one has been committed.
Purpose:
- One step towards #653784: Separate out menu links from hook_menu. We might go further on this in the future, but I think it makes sense to start with this simple step.
- Making the costly and annoying system nav rebuild optional. Many sites need only a small subset of system nav, or none of it. (it is still needed for admin menu currently, but this can be avoided).
- Making the diff information from #512962-236 available to system nav rebuild and others, to allow for more performant rebuild algorithms. See also #593682: Optimize _menu_navigation_links_rebuild(). Such rebuild stuff is currently a major cause in slowing down some administration pages, such as form submit on content type or views configuration.
- Allow other modules to react to menu router changes. This would allow alternative implementations of system nav or admin menu, or it could be used to clean up broken links, etc.
Same idea in older posts:
This idea is not new. See
#550254-36: Menu links are sometimes not properly re-parented ("hook_menu_router_update")
#512962-216: Optimize menu_router_build() / _menu_router_save() ("hook_menu_router_built")
#653784: Separate out menu links from hook_menu ("hook_menu_rebuild")
Comment | File | Size | Author |
---|---|---|---|
#7 | 1170278_7-drupal_8_x-hook_menu_router_update.patch | 1.12 KB | donquixote |
Comments
Comment #1
donquixote CreditAttribution: donquixote commentedAnd as said, this thing is "pending" until #512962: Optimize menu_router_build() / _menu_router_save() is fixed.
Until then I will not produce any patches, and I don't want to see anyone else uploading one.
That said, we can already do some bikeshedding and "sub" and "+1".
Comment #3
donquixote CreditAttribution: donquixote commentedWe could make a first version of this thing, that takes the complete $menu array with all router items, instead of the $insert and $udpate and $delete.
We need this anyway, because in some cases we might not have the diff available. That is, if the menu_router table was corrupted, and or overly crowded, then we might prefer a clean rebuild from scratch, instead of the diff.
Comment #4
donquixote CreditAttribution: donquixote commentedWhat should be the modules that implement this hook?
Long-term (but still D8):
- "menu_links" module defines the menu_links table and infrastructure, and the blocks that render the menus (currently in "system" or core menu.inc).
- "menu_links_ui" module for the admin ui for menus based on menu_links (currently "menu" module).
- "navigation" module for the navigation menu.
Short-term:
- "menu" does what it already does.
- "navigation" module for the navigation menu.
- anything in core that depends on the navigation menu (breadcrumbs, tabs?), needs liberation from this dependency.
In both cases, it would be the "navigation" module that implements the hook_menu_router_update().
Very short-term:
- "menu" does what it already does.
- "system" implements hook_menu_router_update() to fill the navigation menu.
Comment #5
donquixote CreditAttribution: donquixote commentedI overlooked some details.
_menu_navigation_links_rebuild() does not only rebuild the navigation menu, it builds a whole bunch of menus.
Some key router items (such as 'admin') have a menu name set, which determines the menu for all their child items.
Thus, we can no longer follow the approach that one generated menu is "owned" by a specific module, and each of these modules could rebuild the menus that it owns, independently. This would be even slower than building them all at once.
Conclusion:
The refactoring approach suggested above does not make sense within the current system.
_menu_navigation_links_rebuild() shall remain in core for now.
But, this does not mean it cannot be optimized for a diff-based rebuild! And in general, a more reliable logic.
Going to postpone this for now, until someone else has an opinion.
Comment #6
donquixote CreditAttribution: donquixote commentedI'm goint to re-open this.
Re #5:
Yes, the "one generated menu is owned by a specific module" is not the approach to take.
But, we can still decouple _menu_navigation_links_rebuild() by introducing the hook.
D7 vs D8:
I expect that D8 will soon revamp this area altogether.
The new hook would still be useful for D7.
So, the plan could be:
1. Introduce the hook in D8.
2. Backport to D7.
3. Revamp this stuff in D8, which might kill the hook.
Comment #7
donquixote CreditAttribution: donquixote commentedHere is a minimal patch, which moves only this one operation from menu.inc into system.module as a hook implementation.
Profit:
- Modules can use hook_module_implements_alter() to kick system_menu_router_update().
- Modules can implement hook_menu_router_update() themselves for whatever they need it for.
Comment #8
donquixote CreditAttribution: donquixote commentedNote: I put this in system.module, not in menu.module, because menu.module is only supposed to provide the admin UI for menu links.
The menu_links table is defined in system_schema(), not in menu_schema().
Comment #9
moshe weitzman CreditAttribution: moshe weitzman commentedSeems like a reasonable first step.
Comment #10
moshe weitzman CreditAttribution: moshe weitzman commentedOops. The new menu_router_update hook needs to be added to menu.api.php
Comment #11
donquixote CreditAttribution: donquixote commented#10 yup.
if enough people want this, we do the homework.
what about a bit of bikeshedding on the hook name?
hook_menu_router_update()
hook_menu_router_updated()
hook_menu_router_rebuilt()
hook_menu_router_changed()
One idea was to use this past tense to indicate that something happened, instead of something currently happening or about to happen. Also, "rebuilt" is so awkward that it seems quite safe against nameclash :)
---------
Another thought.
I would like to move to a diff-based menu_router rebuild at some day. Once we are there, there will be two cases for this hook to fire: (1) full rebuild from scratch, if no previous data is available. (2) Rebuild with diff.
We could extend the hook like this:
or stuff those three extra arguments into an object / array.
The first argument would still be there, for implementors that cannot handle the diff.
The point is, we can add this extra magic as a follow-up, without breaking anything.
Comment #12
donquixote CreditAttribution: donquixote commentedAnother thing to bikeshed:
Which module should "own" the default hook implementation? System, as it is proposed in the patch?
Also, should the hook really be owned by menu? with menu.api.php?
In D7 at least, menu module only makes the UI, while menu_links are in system.
So... start in system/core, and move this stuff to a dedicated module as a follow-up?
Comment #13
Crell CreditAttribution: Crell commentedWhy are we adding a new feature to a system that is in the process of being replaced? We don't know what is happening with all parts of hook_menu, but the routing bits have already been pulled out to the new routing system.
Comment #14
donquixote CreditAttribution: donquixote commentedFirst: I want this in D7, too.
Second: The silence on #1835902: Allow modules to register links for menus, breadcrumbs and tabs (if not with hook_menu) makes me think of the underpants gnomes.
1. Collect underpants.
2. ?
3. Profit.
We could have made a lot of progress on the existing system, if it was not for this dark hole.
EDIT:
And seriously that's the same on IRC, noone really knows where this is heading.
If we officially knew the way that D8 is going to take beyond just "symfony does our routing", we could directly go to D7 with issues like this one.
Personally I can not think of anything that is not a DX regression compared to hook_menu().
Comment #15
Crell CreditAttribution: Crell commentedI have no opinion on adding this to D7. However, I replied in the linked issue. That does legitimately need more discussion and attention. Remember, just filing an issue doesn't mean people will pay attention to it. :-) Stop by the next WSCCI meeting and let's see if we can get it on the agenda.
Comment #15.0
Crell CreditAttribution: Crell commentedMention the design problem as in comment #4.
Comment #16
Crell CreditAttribution: Crell commentedThe issues under this meta are all implicit beta blockers. Peter Wolanin will fill in the appropriate child issues shortly.
Comment #17
Crell CreditAttribution: Crell commentedCrap, never mind, I updated the wrong issue. Ignore me.
Comment #18
donquixote CreditAttribution: donquixote commentedWould this still make sense for D8, in a different way?
We do have a route building on D8, and we could fire an event when this is finished, so dependent systems could do their own rebuild.