18

I am the author of the Date iCal module, and the new major version I'm working on (3.x) requires a two-part schema update for users who had 2.x installed. I've written the update hook that makes these changes, but if one of my users fails to run the database update script, they will get an error message relating to their iCal feeds importers.

The right solution is for them to run the update script... but if they just go in and manually change their importers to get rid of the message, their importers will remain permanently broken (because the second part of the schema update won't have been executed).

So is there any way to display a message to users who haven't run the update? Or somehow forcibly execute the update hook the first time a page load occurs when 3.x gets installed overtop of 2.x?

1
  • 2
    I would imagine you could do a variable_set() in your update function that sets a variable when it was successfully run that you could look at inside a _preprocess_page() but you'd be looking at it every time so not sure how performance friendly this would be.
    – Jimajamma
    Nov 12, 2013 at 20:07

6 Answers 6

4

extending on comment from Jimajamma:

do a variable_set() in your update function that sets a variable when it was successfully run that you could look at inside a _preprocess_page()

and instead of checking this on every page load do it only if browsing the admin area and if the installed version is 3.0 (3.1, 3.2, kill that check if you stop supporting the old version as an upgrade path).

Additionally make use of hook_requirements to provide feedback on the status report page:

Check installation requirements and do status reporting.
(...)
The 'runtime' phase is not limited to pure installation requirements but can also be used for more general status information like maintenance tasks and security issues.

21

There are few ways of forcing module update.

  1. Calling the update function directly.

    $sandbox = [];
    module_load_include('install', 'FOO');
    FOO_update_7001($sandbox);
    
  2. Resetting the schema version to the point of interest and run the updates again as usual.

    drupal_set_installed_schema_version('module_name', '7000');
    

    Or reset to re-run only the latest update schema:

    drupal_set_installed_schema_version('foo', drupal_get_installed_schema_version('foo') - 1);
    

    Notes:

    • This can be placed in hook_install, so during the update process all sequent update hooks would be executed.
    • In order to use this function outside of the installation file, you've to include Drupal install.inc first and installation file of the module, e.g.

      require_once DRUPAL_ROOT . '/includes/install.inc';
      module_load_include('install', 'foo');
      
    • Consider adding ini_set('max_execution_time', 0); for longer installation updates to prevent PHP timeouts.
  3. Using drush. Find below few examples:

    • drush eval 'module_load_include('install', 'foo'); $s = []; foo_update_7001($s);'
    • drush sqlq "UPDATE system SET schema_version = 7000 WHERE name = 'foo'" && drush -y updb
4
  • 1
    Oh nice, I didn't know about drupal_set_installed_schema_version(). That'd be super handy for debugging update hooks! Jul 22, 2015 at 18:18
  • 1
    So the main problem with putting it into hook_install() is running long batched (sandboxed) updates. In ideal situation, there should be a way to trigger updates in the same way as update.php does with restarting PHP thread to prevent timeouts. Ant ideas how to do that? Feb 1, 2017 at 9:22
  • @Alex.Designworks You can add ini_set('max_execution_time', 0); before triggering the updates.
    – kenorb
    Feb 1, 2017 at 10:13
  • Just want to add the this drush command example was clutch! Still works great on Drupal 9.3.x! drush eval 'module_load_include('install', 'foo'); $s = []; foo_update_7001($s);' Jun 15, 2022 at 19:28
1

You could "SELECT schema_version FROM system" to detect whether an update has been performed. If not, then refuse to run (with an error message).

3
  • Please reword your answer, and try to give a usage example. Nov 20, 2013 at 20:28
  • I'm afraid that won't work, because the functionality in question is a plugin for another module, and I can't prevent that module from letting users mess with their importers. Nov 21, 2013 at 2:04
  • You cannot check the schema version of the module which you intend to monitor for updates?
    – user18099
    Nov 27, 2013 at 16:08
0

I agree with the above suggestions - my only addition would be to investigate "Triggers and Actions" also - it seems that you need an action (notify user or run update) to occur when a trigger (user checks admin page, etc) is pulled. For use examples see the Examples module, there are both action and trigger example code. :)

0

function MYMODULE_install() { $functions = get_defined_functions(); foreach ($functions['user'] as $function) { if (strpos($function, 'MYMODULE_update_') === 0) { call_user_func($function); } } }

0

Using Drush you can force your hook to run

ddev drush eval 'module_load_include('install', 'module_name'); $s = []; module_hook_9001($s);'

Your Answer

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

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