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")

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

donquixote’s picture

And 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".

donquixote’s picture

We 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.

donquixote’s picture

What 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.

donquixote’s picture

Status: Active » Postponed

I 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.

donquixote’s picture

Status: Postponed » Active

I'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.

donquixote’s picture

Status: Active » Needs review
FileSize
1.12 KB

Here 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.

donquixote’s picture

Note: 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().

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

Seems like a reasonable first step.

moshe weitzman’s picture

Status: Reviewed & tested by the community » Needs work

Oops. The new menu_router_update hook needs to be added to menu.api.php

donquixote’s picture

#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:

function hook_menu_router_update($menu_router, $inserted = NULL, $updated = NULL, $deleted = NULL) {
  ..
}

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.

donquixote’s picture

Another 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?

Crell’s picture

Why 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.

donquixote’s picture

First: 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().

Crell’s picture

I 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.

Crell’s picture

Issue summary: View changes

Mention the design problem as in comment #4.

Crell’s picture

Priority: Normal » Major
Issue summary: View changes
Issue tags: +beta blocker

The issues under this meta are all implicit beta blockers. Peter Wolanin will fill in the appropriate child issues shortly.

Crell’s picture

Priority: Major » Normal
Issue tags: -beta blocker

Crap, never mind, I updated the wrong issue. Ignore me.

donquixote’s picture

Would 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.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.