_system_theme_data() reads theme files from the disk and executes drupal_alter.
On a system with many modules and/or themes this adds a performance hit.

Replacing _system_theme_data() with a DB read of the system table (as done in common.inc's list_themes()) can greatly improve performance.

$result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme');
while ($theme = db_fetch_object($result)) {
  if (file_exists($theme->filename)) {
    $theme->info = unserialize($theme->info);
    $themes[] = $theme;
  }
}

is around 40-50x faster than

  _system_theme_data()

Patch follows.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

setvik’s picture

Peter Bowey’s picture

Refer #1

I like it: +1 rating

Good lateral thinking setvik

I had several issues with the private _system_theme_data() method
used in skinr 6.x-1.x-dev

moonray’s picture

Peter Bowey’s picture

I have updated your patch in #1:

I was getting PHP E-Notices: ==> Notice: Trying to get property of non-object in system_find_base_themes()

New code (below):

/**
 * Helper function to load theme data
 * Code borrowed from list_themes().
 *
 * If the database is active then it will be retrieved from the database.
 * Otherwise it will retrieve a new list.
 *
 * @return
 *   An array of the currently available themes.
 */
function _skinr_get_theme_data() {
  static $themes = array();

  if (empty($themes)) {
    $themes = array();
    // Extract from the database only when it is available.
    // Also check that the site is not in the middle of an install or update.
    if (db_is_active() && !defined('MAINTENANCE_MODE')) {
      $result = db_query("SELECT * FROM {system} WHERE type = '%s'", 'theme');
      while ($theme = db_fetch_object($result)) {
        if (file_exists($theme->filename)) {
          $theme->info = unserialize($theme->info);
          $themes[] = $theme;
        }
      }
    }
    else {
      // Scan the installation when the database should not be read.
      $themes = _system_theme_data();
    }

    foreach ($themes as $theme) {
      foreach ($theme->info['stylesheets'] as $media => $stylesheets) {
        foreach ($stylesheets as $stylesheet => $path) {
          $theme->stylesheets[$media][$stylesheet] = $path;
        }
      }
      foreach ($theme->info['scripts'] as $script => $path) {
        if (file_exists($path)) {
          $theme->scripts[$script] = $path;
        }
      }
      if (isset($theme->info['engine'])) {
        $theme->engine = $theme->info['engine'];
      }
      if (isset($theme->info['base theme'])) {
        $theme->base_theme = $theme->info['base theme'];
      }
      // Status is normally retrieved from the database. Add zero values when
      // read from the installation directory to prevent notices.
      if (!isset($theme->status)) {
        $theme->status = 0;
      }
      $themes[$theme->name] = $theme;
    }

  }
  return $themes;
}

I no longer see PHP 5.3.x 'E-Notice' reports via Pressflow 6.22.

Status: Needs review » Needs work

The last submitted patch, skinr-system-theme-data-1129746-1.patch, failed testing.

moonray’s picture

Issue summary: View changes

@Peter Bowey How is this different from just calling list_themes()?

moonray’s picture

Status: Needs work » Needs review
FileSize
1.31 KB

Using list_themes() instead of system_theme_data() speeds things up a lot. No need for custom function.

  • Commit 89e017a on 6.x-1.x by moonray:
    Issue #1129746 by moonray, Peter Bowey, setvik: Skinr_process_info_files...
moonray’s picture

Status: Needs review » Fixed

Status: Fixed » Closed (fixed)

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