Following up on #200931: Schema not available in hook_install/hook_enable, we fixed the fact that schema information is not available in hook_enable(), but it is still the case in D7 that the schema cannot be used in hook_install (see the issue for details).

This is a less serious bug, since there are workarounds for doing what you want to do in hook_install() in hook_enable() instead - just run a check first to make sure it was not already done before. For an example, see http://api.drupal.org/api/function/shortcut_enable/7

However, it ideally should still be fixed.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

David_Rothstein’s picture

manfer’s picture

You mention a workaround in hook_enable, but if I need to do a drupal_write_record in hook_install (not possible by now as schema is not available), is it wrong if I use a db_query in drupal 6 or a db_insert in drupal 7?

David_Rothstein’s picture

Yeah, doing a direct database query definitely works also, but it can sometimes be a pain, and for certain use cases it might be important to use an API function instead of a direct database query (if the API function also triggers other behavior)...

The workaround in hook_enable() is that you can use whatever code you wanted to run in hook_install(), just that you need to do a preliminary check first to make sure that it hasn't run before (i.e., that the module has not already been installed), and then effectively it's the same thing.

rszrama’s picture

I was tracking this one down for some time and tried several different ways to manually reset the schema cache and enabled modules list. I even tried implementing hook_modules_installed() on the module as a way to get around a workaround through hook_enabled(). In the end, I just used a db_insert(), but I'm a HUGE +1 to have this fixed. It seems to me that drupal_install_schema() should mean just that... the schema has been installed and is available for any drupal_write_record() after that.

David_Rothstein’s picture

Status: Active » Needs review
FileSize
12.84 KB

Tried to come up with a fix for this, and it's messier than I had hoped - it seems to be tied up to the entire way we do module installation.

Basically, right now we call hook_install() before doing anything else, so the module actually isn't "installed" yet in any meaningful way, and none of its hooks will work. To fix this essentially requires rewriting the internals of module_enable() to do this in what I think is a more sensible order:

  1. Turn on the first module.
  2. Install it.
  3. Enable it.
  4. (repeat steps 1-3 for other modules)
  5. Inform all modules about the list of modules that were newly-installed and newly-enabled.

And then, fixing some cache-clearing bugs along the way.

Let's see what the testbot thinks of this. Note that the patch also contains the obvious fix to the shortcut module so it uses this new capability - in theory that could be a followup patch, but it was useful for debugging this as I worked on it, and I'd really like to see what the testbot thinks of the entire thing.

David_Rothstein’s picture

Note that one side effect of this patch is that a fatal error in a module's hook_install() will leave the system in an odd state, where Drupal thinks the module is installed and enabled but it hasn't really been yet.

However, I believe the same is true for fatal errors in hook_enable() without this patch - and in some ways worse without this patch, since it could then affect a whole list of modules rather than isolating the problem to a single one. But I thought it was worth mentioning anyway.

David_Rothstein’s picture

Geez, the patch already no longer applies :)

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

My hard drive is litterred with half attempts at this same patch. I commend you on your skill and tenacity. This wasn't easy.

If you have enabled several modules at once with drush, you very well might have felt the pain of this bug. We need to fix it.

I reviewed the code and it looks good. The test is icing on the cake.

webchick’s picture

Status: Reviewed & tested by the community » Needs review
+++ includes/module.inc	15 Feb 2010 22:38:23 -0000
@@ -336,63 +336,73 @@ function module_enable($module_list, $en
     if ($existing->status == 0) {
+      // Load the module's code.
+      drupal_load('module', $module);
       module_load_install($module);

Question about this.

Let's say my module has in its hook_requirements() in mymodule.install that in order to use it, you need the external foodybar PHP library.

At the top of my .module file is the code require_once('/FoodyBar.baz.php');

Won't this code lead to a fatal error?

Powered by Dreditor.

David_Rothstein’s picture

I think it would... however, I don't think the patch changes that one way or another. That line of code was not added by the patch, but rather just moved around a bit - e.g., notice that there are also two lines in the patch file that look like this:

-      drupal_load('module', $module);

Also, I think as long as you're installing modules via the UI, the hook_requirements() will be checked beforehand so you can't get into this situation that way.

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

back to rtbc

moshe weitzman’s picture

#7: schema-hook-install-620298-7.patch queued for re-testing.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, schema-hook-install-620298-7.patch, failed testing.

David_Rothstein’s picture

Status: Needs work » Reviewed & tested by the community
FileSize
13 KB

Trivial reroll, so I'm setting straight back to RTBC assuming the testbot agrees.

Status: Reviewed & tested by the community » Needs work

The last submitted patch, schema-hook-install-620298-14.patch, failed testing.

David_Rothstein’s picture

Status: Needs work » Needs review
moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community

all green

Dries’s picture

Status: Reviewed & tested by the community » Needs work

Great job, David. The changes to install.inc and module.inc make sense and seem to stream-line the installation process some more. It is quite grokkable actually. While I think we're really close, I still have some feedback:

+++ includes/module.inc	25 Feb 2010 05:05:27 -0000
@@ -336,63 +336,73 @@ function module_enable($module_list, $en
+      // Check if node_access table needs rebuilding.
+      // We check for the existence of node_access_needs_rebuild() since
+      // at install time, module_enable() could be called while node.module
+      // is not enabled yet.
+      if (function_exists('node_access_needs_rebuild') && !node_access_needs_rebuild() && module_hook($module, 'node_grants')) {
+        node_access_needs_rebuild(TRUE);
+      }

I wonder if this could (and should) be moved to node module using the new _modules_installed() or _modules_enabled() hook? It would further clean-up and streamline the installer code. If not, maybe we can clarify the code comment to explain why we can't? The current code comment makes sense but at the same time, it doesn't. :P

+++ modules/shortcut/shortcut.install	25 Feb 2010 05:05:28 -0000
@@ -7,14 +7,9 @@
 /**
- * Implements hook_enable().
+ * Implements hook_install().
  */
-function shortcut_enable() {
-  if (shortcut_set_load(SHORTCUT_DEFAULT_SET_NAME)) {
-    // Quit out; this module has already been installed before.
-    return;
-  }
-
+function shortcut_install() {

I like this clean-up! Nice catch.

+++ modules/simpletest/tests/module.test	25 Feb 2010 05:05:28 -0000
@@ -126,13 +126,44 @@ class ModuleUnitTest extends DrupalWebTe
+   * Test that calls to drupal_write_record() work during module installation.

It would be good to explain why this test is useful. The help text lacks some context to help people understand the bigger picture. This seems to suggest that 'drupal_write_record()' is special but reading the patch it is not clear why.

Anyway, I think we should be able to commit this really soon.

David_Rothstein’s picture

Status: Needs work » Needs review
FileSize
4.06 KB
13.8 KB

That's a great idea about moving the node access stuff to the node module while we are in here cleaning up this function anyway... I did that in the attached patch. We should do the same thing with the node access checks in module_disable() too, but that looked a little more complicated (I think there might be a bug there) so let's save that for a followup.

I also rewrote the code comment for the test.

Finally, I realized that I had erroneously removed include_once DRUPAL_ROOT . '/includes/install.inc' in the previous patch (it's still needed here, just for a slightly different reason), so I've added it back with a new code comment.

Dries’s picture

Status: Needs review » Fixed

Looks good now. Committed to CVS HEAD. Thanks.

David_Rothstein’s picture

Trying to figure out how to get the node access code out of module_disable() reveals a bug in that function, and it seems like it's going to require a similar rewrite to what we did here in order to properly fix it. Initial work is here: #727876: Enabling modules one at a time works differently than enabling them all at once

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.