Problem/Motivation

When we run update after upgrade to 7.x-2.4 from 7.x-2.2, getting below update_Ns:

Wysiwyg    7201  Update enabled font plugin buttons to default plugin in       
                  TinyMCE profiles.                                             
 Wysiwyg    7202  Update internal names of settings.                            
 Wysiwyg    7203  Add primary index to {wysiwyg_user}.      
 Wysiwyg    7204  Remove empty editor profiles and update existing profiles.    
 Wysiwyg    7205  Check for profiles without add_to_summaries settings.
Do you wish to run all pending updates? (y/n): y

Ran up to 7203 successfully. After throws fatal error:

Performed update: wysiwyg_update_7201                                [ok]
Performed update: wysiwyg_update_7202                                [ok]
Performed update: wysiwyg_update_7203                                [ok]

Fatal error: Class name must be a valid object or a string in includes/common.inc on line 8048
Drush command terminated abnormally due to an unrecoverable error.   [error]
Error: Class name must be a valid object or a string in includes/common.inc, line 8048
The external command could not be executed due to an application     [error]
error.

Proposed resolution

Remaining tasks

- Fix
- Review
- Test

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

vijaycs85 created an issue. See original summary.

TwoD’s picture

Try clearing all caches and run the update again, or maybe even rebuild the class rregistry with drush rr.

bondjimbond’s picture

I'm getting a similar error with that update in the browser:

Call to undefined function wysiwyg_profile_cache_clear()

jcazotto’s picture

I've tried to run drush rr --fire-bazooka and drush cc all, but I'm still getting the same fatal error when running updb.
It seems that this error occurs only if Wysiwyg is disabled. It doesn't happen if module is enabled or uninstalled.

TwoD’s picture

Oh, that explains it. If the module is disable the .module file will not be loaded, and thus it's not able to load the classes from there.
I don't know why Drupal allows updating disabled modules, it is bound to cause problems...

There does not seem to be a way to resolve this as there is already a line in that update hook which tries to load wysiwyg.module.
(I can't say for certain it's not trying to load some other class than the one available there though, as the error message doesn't actually include its name.)

Basically, my advice is; if you've disabled a module, don't try to update it without enabling it first. If you don't want to enable it, either uninstall it or don't upgrade. D8 does away with all these issues by forcing modules to be completely uninstall once disabled.

vijaycs85’s picture

Sorry, my bad, I didn't mention about the disabled status. More background why are we running disabled modules update is available at #194310: Check / run updates of disabled modules. As you mentioned, we end up enabling/uninstalling the module.

vijaycs85’s picture

Title: wysiwyg_update_7204 throws fatal error » wysiwyg_update_7204 throws fatal error when module is disabled status
Status: Active » Closed (won't fix)

Closing this issue as won't fix.

alexharries’s picture

Status: Closed (won't fix) » Needs work

I would like to re-open this as I've just spent 3 hours diagnosing why this was happening.

I can see that this isn't really the fault of the module developer, but it can be fixed at the module level:

Surely you only need to put "if (module_exists('wysiwyg')) {' at the top of the wysiwyg_update_7204() function?

This has caused a huge and unnecessary headache and made me very grumpy :( :)

/Alex

alexharries’s picture

Apologies - I don't have the bits and bobs set up to produce a diff against HEAD but here's wysiwyg_update_7104() with the module_exists() fix applied:

/**
 * Remove empty editor profiles and update existing profiles.
 */
function wysiwyg_update_7204() {
  // Actively check to confirm that the WYSIWYG module is enabled; this
  // avoids a fatal error at line 8048 of common.inc in cases where the
  // WYSIWYG module's database updates are attempted despite the module
  // being disabled.
  if (module_exists('wysiwyg')) {
    // Remove unused profiles.
    $query = db_delete('wysiwyg')
      ->condition('editor', '')
      ->execute();
    $query = db_select('wysiwyg', 'w')
      ->fields('w', ['format', 'editor', 'settings']);
    drupal_load('module', 'wysiwyg');
    if (module_exists('ctools')) {
      drupal_load('module', 'ctools');
    }
    foreach ($query->execute() as $profile) {
      // Clear the editing caches.
      if (module_exists('ctools')) {
        ctools_include('object-cache');
        ctools_object_cache_clear_all('wysiwyg_profile', 'format' . $profile->format);
      }
      cache_clear_all('wysiwyg_profile:format' . $profile->format, 'cache');
      // Move profile state to its own section.
      $settings = unserialize($profile->settings);
      if (!empty($settings['_profile_preferences'])) {
        // Skip in case of re-run.
        continue;
      }
      $preferences = [
        'add_to_summaries' => !empty($settings['add_to_summaries']),
        'default' => $settings['default'],
        'show_toggle' => $settings['show_toggle'],
        'user_choose' => $settings['user_choose'],
        'version' => NULL,
      ];
      unset($settings['add_to_summaries'], $settings['default'], $settings['show_toggle'], $settings['user_choose']);
      if (!empty($settings['library'])) {
        $prefereces['library'] = $settings['library'];
        unset($settings['library']);
      }
      $editor = wysiwyg_get_editor($profile->editor);
      if ($editor['installed']) {
        $preferences['version'] = $editor['installed version'];
      }
      $settings['_profile_preferences'] = $preferences;
      db_update('wysiwyg')
        ->condition('format', $profile->format)
        ->fields([
          'settings' => serialize($settings),
        ])
        ->execute();
    }
    wysiwyg_profile_cache_clear();
  }
}
TwoD’s picture

If I do that and someone runs an upgrade, and then enables Wysiwyg, it won't be run again if they activate the module as Core keeps track of which hook numbers have already run, putting the db in a state I'm not sure how to resolve. By that time you may not get any errors at all, just odd behavior.

It's already doing drupal_load('module', 'wysiwyg') so all Wysiwyg's classes are technically available at this point. The problem seems to be that entity_get_info() returns null if the module owning the entity isn't enabled, so Drupal after tries to load null as the controller class for Wysiwyg profiles. (This actually happens when trying to clear profile caches.)

What if we instead simply skip trying to clear the controller's cache if the module isn't enabled?

axle_foley00’s picture

I am happy I found this. I was getting the same error and enabling the module helped.

eg2234’s picture

I'm getting a similar error: SQLSTATE[42000]: Syntax error or access violation: 1068 Multiple primary key defined
WYSIWYG is enabled, and I've tried disabling, clearing cache, and re-enabling without success.

Aldu_boy’s picture

With Drupal 7.69 the 7204 update issue is still in place.

Fixed by editing /sites/all/modules/wysiwyg/wysiwyg.module

replaced a line
entity_get_controller('wysiwyg_profile')->resetCache();

with

if (module_exists('wysiwyg')) {
  // Skip this if the module is not enabled as entity_get_info() returns null.
  entity_get_controller('wysiwyg_profile')->resetCache();
}
steinmb’s picture

Status: Needs work » Needs review

  • TwoD committed 6a96cd23 on 7.x-2.x
    - #2878771 by TwoD, alexharries, vijaycs85, Aldu_boy:...
TwoD’s picture

Status: Needs review » Fixed

Thank you all.

Status: Fixed » Closed (fixed)

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