Is something broken? If I stick this in a module (any module which doesn't already have an _init function);

function modulename_init() {
global $user;
if (!$user->uid) watchdog('modulename', 'test of hook_init');
}

Now I would expect seeing as the docs on Drupal API say;

Only use this hook if your code must run even for cached page views.

That to appear in my logs *every* time an anonymous user refreshes a page/ goes to a new page. But nope it doesn't...

...Well, my code *must* run even on cached pages and no using hook_init doesn't work as the docs say it should? Of course, it works if the page isn't already cached but once it is the next time you view the page the watchdog doesn't get written to again - just that first time? Obviously I'm setting the cache to NORMAL and not aggressive and obviously the minimum cache lifetime is set to none as that's irrelevant here.

Pobster

Comments

pwolanin’s picture

From the code in bootstrap.inc, it should work the way you expect:

/**
 * Initialize the caching strategy, which loads at different stages within
 * Drupal's bootstrap process.
 */
function _drupal_cache_init($phase) {
  require_once variable_get('cache_inc', './includes/cache.inc');

  if ($phase == DRUPAL_BOOTSTRAP_EARLY_PAGE_CACHE && variable_get('page_cache_fastpath', 0)) {
    if (page_cache_fastpath()) {
      exit();
    }
  }
  elseif ($phase == DRUPAL_BOOTSTRAP_LATE_PAGE_CACHE) {
    if ($cache = page_get_cache()) {
      if (variable_get('cache', CACHE_DISABLED) == CACHE_AGGRESSIVE) {
        drupal_page_cache_header($cache);
        exit();
      }
      elseif (variable_get('cache', CACHE_DISABLED) == CACHE_NORMAL) {
        require_once './includes/module.inc';
        bootstrap_invoke_all('init');
        drupal_page_cache_header($cache);
        bootstrap_invoke_all('exit');
        exit();
      }
    }
    require_once './includes/module.inc';
  }
}

However, I looked deeper at the code in module.inc, and I now see that only those modules with bootstrap = 1 in the system table will have hook_init called when page caching is turned on! See function module_list() Clearly this is, at the least, a bug in the code comments that should be filed (search the queue first). We should also add a note to the module developer's guide.

---
Work: BioRAFT

pobster’s picture

Hmmm okay that makes sense... I've had a search through the issues and there appears to be a whole lot regarding the way module_list() works, but none regarding that it doesn't do what the docs say it should do (well, unless bootstrap = 1)...

...So, anyways - I'm happy now - my code works fine, I don't think I'm going to bother filing a bug report about it - it seems like there's a whole lot of other issues with module_list() anyways...

Thanks,

Pobster

mooffie’s picture

I now see that only those modules with bootstrap = 1 in the system table will have hook_init called when page caching is turned on!

That's correct. It's not a bug. Some bookkeeping function (triggered by the admin/modules page, I think) sets the 'bootstrap' DB column for all modules that implement hook_init (and hook_exit). That's how Drupal know which modules to load. Modules not having this flag set are not loaded in the cache phase. They are loaded later.

The idea is to avoid loading _all_ modules on cached pages (and asking them one by one "are you implementing hook_init?"). If all modules are loaded then there's no point in using a cache.

It's possible that pobster's problem was because he didn't click the "submit" button on the modules page after he added his hook_init and thus the 'bootstrap' column for his module was not reevaluated.

BTW, in Drupal 6 this hook was renamed to "boot" and the meaning of the "init" hook has changed: it's now called for every loaded module. This is nice, because we no longer have to piggyback hook_menu($may_cache=FALSE).

pwolanin’s picture

I understand it's not a bug in the code, but it *is* a "bug" (or error) in the code comments which can only be fixed via a core commit.

---
Work: BioRAFT

mooffie’s picture

Some bookkeeping function (triggered by the admin/modules page, I think) sets the 'bootstrap' DB column for all modules that implement hook_init (and hook_exit).

OK, I tracked down this function. It is module_rebuild_cache(). It updates this 'bootstrap' field.

This function is called whenever we visit the q=admin/build/modules page. No need to press the "Submit" button.

I understand it's not a bug in the code, but it *is* a "bug" (or error) in the code comments which can only be fixed via a core commit.

Inline comments in the code? They wouldn't have helped pobster, because he looked at the doxygen for hook_init (it's in 'conrtib', not 'core').

(Some would say the 'bootstrap' column is an implementation detail and shouldn't be mentioned in the doxygen. Following your logic, btw, the doc for hook_menu() should remind us to clear the menu cache when we add/change an item. Hey, I'm all for it.)

pwolanin’s picture

Sorry- I wasn't paying close enough attention. Obviously one of us with CVS access can fix it directly if it's in the developer docs.

If what you say is correct- that this column should == 1 for all modules with hook_init()- I'd guess the problem was that the module was enabled during the development process before it implemented hook_init.

---
Work: BioRAFT

pobster’s picture

Nope I read it off http://api.drupal.org/api/5/function/hook_init and I do agree that the write up should be changed to make it clearer. YES it does work like it says it does, but only after 'bootstrap' is changed to '1' - I've spent countless hours faffing about over why my code seemingly didn't work properly, in fact my logotool module has been on and off broken for about a year simply down to the fact that I didn't know about this bootstrap requirement and I assumed it to be broken (I've moved the code which needed to be run from _init to _menu to simply being in the module without a function). If the instructions were clearer I could have saved myself an awful lot of time and an awful lot of bug reports...

Pobster