3

I added a *.module file to a custom module, to implement some hooks.

I found that the *.module was never included, even after cache clear (via devel menu "Cache clear". Even putting a "die()" statement at the top of the file did not crash anything.

Only after drush pmu + drush en, was the *.module file included in every request.

What am I missing? Is this a bug?

2
  • 1
    Do you have a module.info.yml?
    – mpdonadio
    Commented Aug 19, 2017 at 15:22
  • Yes I do. Otherwise I would not have been able to enable it :)
    – donquixote
    Commented Aug 20, 2017 at 11:44

3 Answers 3

6

Here are my own observations. It contains some details that were not mentioned in @kiamlaluno's answer.

Things that need rebuilding

There are two "caches" that need to be rebuilt, if a *.module file with hook implementations was just created, in a module that previously did not have such a file.

  1. The "container.modules" container parameter, which we can inspect with dpm(\Drupal::getContainer()->getParameter('container.modules'));.
    Each entry has a ['filename' => *] key, which can be either null or 'MODULENAME.module'.
    If it is null, then Drupal has not found the *.module file yet, and will not include it when looking for hook implementations.
  2. The hook implementations, which we can inspect with dpm(\Drupal::moduleHandler()->getImplementations($hook_name));.

Operations that rebuild those things - or not

The first part, the container parameter, is not rebuilt on devel cache clear, or on drush cr. This has been the real problem.

The second part, the module_implements cache, is not rebuilt on devel cache clear, but it is rebuilt on drush cr.

To rebuild the first part, the container parameters, one can, as suggested by @kiamlaluno, uninstall and re-enable the module with the new hooks. But this can be quite impractical, because uninstalling can cause data loss.

Solution:

Luckily there is an easier solution: Enable any other module that was previously not installed, and then uninstall it again.

E.g. for me it was "statistics" module. But can be any other.

drush pm-list | grep "Not installed"
drush en statistics
drush pmu statistics

EDIT: NOT SO FAST!

I have to correct myself, for now:

  • The above method of enabling and uninstalling any other module does fix the container parameter 'filename' setting, at first.
  • However, flushing the cache again afterwards removes the 'filename' setting again.

This means that this setting is stored in a more persistent place somewhere.

The reason: APCu file cache: cli vs web

ExtensionDiscovery uses a cache to store discovered extension files. In my case, this is Drupal\Component\FileCache\FileCache, with a Drupal\Component\FileCache\ApcuFileCacheBackend apcu backend.

The problem: The APCu cache has isolated realms for cli and for web. This means, if the file cache is cleared on cli, e.g. via drush, the entries in web are still there.

This problem seems to apply only to the file cache in ExtensionDiscovery. Other caches are not affected. Probably this is because this file cache sits on a lower level within Drupal bootstrap.

Another part of the problem, possibly, is that the file cache is never cleared completely. At least, I cannot find such a place. Instead, individual entries are deleted by key.

2
  • 2
    nice. worked well for me. if you want to clear apcu cache, you can use devel's execute php function and run apcu_clear_cache();, it will clear the cache for web realm
    – Eric Wong
    Commented Mar 7, 2019 at 3:02
  • Praise you! For me restarting the containers fixed it in the end.
    – leymannx
    Commented Feb 20, 2021 at 23:20
1

Drupal 8 is not different from Drupal 7: Both versions keep a list of hooks implemented from modules in a cache entry. If you edit the code of an enabled module, Drupal will not know there are new hooks, and they would not be invoked.

To make Drupal check again the hooks implemented by modules, you should clear the cache bin Drupal uses for that purpose, which is not cleared from the Clear cache link the Devel module provide, which uses the following code.

  /**
   * Clears all caches, then redirects to the previous page.
   */
  public function cacheClear() {
    drupal_flush_all_caches();
    drupal_set_message('Cache cleared.');
    return $this->redirect('<front>');
  }

drupal_flush_all_caches() doesn't clear the cache bin containing the list of all the hooks implemented by the modules.

Using only the Drupal UI, Drupal 7 will know there are new hooks implemented by a module you edited when you go to the modules page and disable a module, or enable a module (or both the operations, in any order).
Since Drupal 8 doesn't allow to enable/disable modules anymore, you just uninstall the module you edited, and then install it again. Possibly, you uninstall the module before editing its code.

If you want to do it programmatically, you need to clear the module_implements bin, which is the one used from ModuleHandler::getImplementationInfo(). Once Drupal is bootstrapped, the code to clear that bin is simply the following line.

\Drupal::moduleHandler()->resetImplementations();

As side note, keep in mind there are hooks that are invoked in specific cases, and not at every page request. If you create one of them, it's normal not seeing the module being invoked for every page request.

5
  • In both Drupal 7 and Drupal 8 it usually is sufficient to rebuild the cache to get new hooks. In general it should not be required to uninstall and reinstall it. Otherwise, what if you update a contrib module, and the new version has one more hook implementation? Just in this case it seemed to be not working for whichever reason.
    – donquixote
    Commented Aug 21, 2017 at 21:59
  • Updating an existing module is quite different from editing the code of an already installed module. Updating an existing module requires invoking update.php as one of the steps, but if you didn't do something more than just editing the module file, Drupal will not think your custom module has been updated. Also, there are cache bins that need to be expressly cleared, which not even drupal_flush_all_caches() would clear.
    – avpaderno
    Commented Aug 21, 2017 at 22:30
  • My observations are a bit contradictory to some of the statements in this answer. I am going to post my own answer, simply because it is too much for comments.
    – donquixote
    Commented Aug 23, 2017 at 4:15
  • I found some weird behavior in ExtensionDiscovery, see my answer.
    – donquixote
    Commented Aug 23, 2017 at 5:46
  • 1
    In my case, I try everything... nothing works, in the end, I just restart my VM then everything works fine. Since Drupal allow to create module without module file, then core should handle this case "adding module file later" in a better way.
    – Ziftman
    Commented Jan 3, 2021 at 9:56
0

I ran into this with the following steps:

  • Installed module from Contrib via composer require drupal/modulename
  • Enabled module via drush pm:enable <modulename>
  • modulename showed up as enabled at admin/modules
  • modulename.module was not being loaded on HTTP requests (eg I could insert die('x'); to that .module file and the site still loaded OK)
  • modulename.module was however being loaded via Drush (changes to the .module file were effective, but only via Drush)

I found the following workaround was effective:

  • Uninstall the module via Drush: drush pm:uninstall modulename
  • Visit admin/modules and enable the module via web UI

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.