Hello,

I found an issue, where the loader function I defined in hook_menu() is called multiple times with no reason.

My loader function is called 4 times.
3 times before the callback, then the form is called, and then the loader function is called once again.

Here's my hook_menu :

function mymodule_menu() {
  $items['mymodule/cycle/%mymodule_cycle/edit'] = array(
    'title' => 'Edit cycle',
    'description' => 'Edit cycle.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('mymodule_cycle_form', 2),
    'access arguments'  => array('administer cycles'),
    'file' => 'mymodule.admin.inc',
  );
  return $items;
}

Is it a bug or a misuse?

Thank you!

Comments

damien tournoud’s picture

That looks slightly weird, and should probably be looked at in details.

But anyway, you are responsible to implement static in your menu loader function. The menu system itself doesn't do any caching of the loaded objects.

ludo.r’s picture

Ok I can implement static, but I can't figure out why this loader is called multiple times.

There's someone else having the same issue there : http://drupal.org/node/1425908

bmarcotte’s picture

Hi all,
just a note to say I'm seeing the same thing as dolo and gregfrith. 4 calls to the loader, 1 call to the calback. The callback occurs only after the first loader call. I only noticed it because I placed an echo to trace my code.

In my case, I was able to move my "loader code" into the callback to bypass this quirk. My "loader code" simply returns the argument: i.e. return $arg1; and then the system passes $arg1 onto the callback.

-Bob

 function usda_menu() {
  $items['usda/%usda_lookup'] = array( 
    'title' => 'Lookup Nutritional Information',
    'description' => 'Allows you to import the USDA source codes into Drupal.',
    'page callback' => 'usda_usda_foods', 
    'page arguments' => array(1),
    'access arguments' => array('access content'),
    'weight' => 1,
  );
 return $items;
}


function usda_lookup_load($arg1) { 
  echo 'here in usda_lookup_load', $arg1;
}
Alexander Matveev’s picture

Subscribing.

andyf’s picture

A question was asked about this on Drupal Answers. I was curious and tried it out on admin/structure/types/manage/%node_type. I grepped for node_type_load() and nothing seemed to be calling it directly, so I put a ddebug_backtrace() in the load function. I got 13 traces when visiting that path! 10 of these came from menu_local_tasks() which loops through the local tasks and calls _menu_translate() which calls _menu_load_objects() for each router item. The other two extra calls came via menu_set_active_trail() which also called _menu_translate(). So I guess it depends on your menu structure how many times a loader might be called. As far as I can tell the object's loaded only to check whether or not it can be (access is denied if it can't). I guess this just reinforces Damien's comment about implementing static caching in your loader.

If someone who knows can say this is by design (and confirm what I've said) I'd be happy to file a patch against hook_menu()'s documentation to mention that a loader function might be called multiple times and it's important to cache.

twardnw’s picture

I was seeing similar effects from menu_get_object. I had an access callback on a hook_menu, inside that access callback I needed to check a node for referenced user IDs, but due to this issue with menu_get_object my access callback was never returning TRUE or FALSE. I stuck a watchdog on either side of it, and only the 'before' one was triggered.

cameron tod’s picture

I just had a quick end-of-day debug on this, as it was effecting some stuff I am writing here.

Menu loader functions are called from _menu_load_objects, which is called (in my case) by _menu_translate 3 times, and by _menu_link_translate once. I think an easy band-aid patch is to cache the $return value of the loader function in _menu_load_objects - here's a link to the line in the 8.x branch.

I'll try to have a deeper look a bit later.

bmarcotte’s picture

Yes this issue is still out here....2 yrs later I re-found this problem
To help others:
I've been creating a custom entity and my hook_load looks like this:

/**
 * Implements hook_load().
 */
function mymodule_load($id) {
 static $r;  //save so we only load once
  if (empty($r) || $r->id !== $id) {
    $r = mymodule_loader_function($id); //does the actual loading steps
 }
   return $r;
}

the static variable $r saves the entity between all the excess calls from menu and/or anywhere else.

Fortunately for the general case, node_load loads through the entity.inc file. The controller there checks for a cached value to avoid a full db reload. It seems, the more menu items you include on a page, the more code spinning that goes on.

Version: 7.12 » 7.x-dev

Core issues are now filed against the dev versions where changes will be made. Document the specific release you are using in your issue comment. More information about choosing a version.

Status: Active » Closed (outdated)

Automatically closed because Drupal 7 security and bugfix support has ended as of 5 January 2025. If the issue verifiably applies to later versions, please reopen with details and update the version.