Drupal如何解析主题继承关系?

Drupal中,主题是可以继承的,或者说是扩展。例如,要创建一个新的名为custom的主题,该主题与名为default的主题只有某些细小的差别。这个时候,不需要复制一份default到custom,可以在custom声明该主题继承自default就可以了。

主题的继承关系在info文件中说明。首先,default主题的info文件不需要修改:

name = Default Theme

custom主题的info文件需要特别地声明base theme属性:

name = Custom Theme
base theme = default

Drupal内部是如何解析这种继承关系的呢?解析的过程发生在system_list()函数中:

$result = db_query("SELECT * FROM {system} WHERE type = 'theme' OR (type = 'module' AND status = 1) ORDER BY weight ASC, name ASC");
foreach ($result as $record) {
  $record->info = unserialize($record->info);
  
  // Build a list of themes.
  if ($record->type == 'theme') {
    $lists['theme'][$record->name] = $record;
  }
}

foreach ($lists['theme'] as $key => $theme) {
  if (!empty($theme->info['base theme'])) {
    // Make a list of the theme's base themes.
    require_once DRUPAL_ROOT . '/includes/theme.inc';
    $lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key);
    // Don't proceed if there was a problem with the root base theme.
    if (!current($lists['theme'][$key]->base_themes)) {
      continue;
    }
    
    // Determine the root base theme.
    $base_key = key($lists['theme'][$key]->base_themes);
    // Add to the list of sub-themes for each of the theme's base themes.
    foreach (array_keys($lists['theme'][$key]->base_themes) as $base_theme) {
      $lists['theme'][$base_theme]->sub_themes[$key] = $lists['theme'][$key]->info['name'];
    }
    
    // Add the base theme's theme engine info.
    $lists['theme'][$key]->info['engine'] = isset($lists['theme'][$base_key]->info['engine']) ? $lists['theme'][$base_key]->info['engine'] : 'theme';
  }
  else {
    // A plain theme is its own engine.
    $base_key = $key;
    if (!isset($lists['theme'][$key]->info['engine'])) {
      $lists['theme'][$key]->info['engine'] = 'theme';
    }
  }
  // Set the theme engine prefix.
  $lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine'];
}

首先,从系统表system中读取出主题信息,记录到$lists['theme']数组:

$result = db_query("SELECT * FROM {system} WHERE type = 'theme' OR (type = 'module' AND status = 1) ORDER BY weight ASC, name ASC");
foreach ($result as $record) {
  $record->info = unserialize($record->info);
  
  // Build a list of themes.
  if ($record->type == 'theme') {
    $lists['theme'][$record->name] = $record;
  }
}

然后,遍历$lists['theme']数组。如果声明了base theme属性,则通过drupal_find_base_themes()函数获取父主题:

require_once DRUPAL_ROOT . '/includes/theme.inc';
$lists['theme'][$key]->base_themes = drupal_find_base_themes($lists['theme'], $key);
// Don't proceed if there was a problem with the root base theme.
if (!current($lists['theme'][$key]->base_themes)) {
  continue;
}

drupal_find_base_theme()返回的是一个数组。在当前例子中,返回的数组是array('default' => 'Default Theme')。主题也是可以多重继承的,假设default主题再继承自top主题,drupal_find_base_theme()返回的数组则是array('top' => 'Top Theme', 'default' => 'Default Theme')。base_themes数组是有序的,最顶层的主题在最前面,然后依次下来。

function drupal_find_base_themes($themes, $key, $used_keys = array()) {
  $base_key = $themes[$key]->info['base theme'];
  // Does the base theme exist?
  if (!isset($themes[$base_key])) {
    return array($base_key => NULL);
  }

  $current_base_theme = array($base_key => $themes[$base_key]->info['name']);

  // Is the base theme itself a child of another theme?
  if (isset($themes[$base_key]->info['base theme'])) {
    // Do we already know the base themes of this theme?
    if (isset($themes[$base_key]->base_themes)) {
      return $themes[$base_key]->base_themes + $current_base_theme;
    }
    // Prevent loops.
    if (!empty($used_keys[$base_key])) {
      return array($base_key => NULL);
    }
    $used_keys[$base_key] = TRUE;
    return drupal_find_base_themes($themes, $base_key, $used_keys) + $current_base_theme;
  }
  // If we get here, then this is our parent theme.
  return $current_base_theme;
}

接下来得到root base theme,base_themes数组中的第一个key,上例中是top。

// Determine the root base theme.
$base_key = key($lists['theme'][$key]->base_themes);

再后,更新每个base theme的sub_themes属性。sub_themes是无序的,取决于于主题加载顺序。

// Add to the list of sub-themes for each of the theme's base themes.
foreach (array_keys($lists['theme'][$key]->base_themes) as $base_theme) {
  $lists['theme'][$base_theme]->sub_themes[$key] = $lists['theme'][$key]->info['name'];
}

最后,设置引擎前缀engine prefix,就是主题解析函数都是以什么开头的。注意变量$base_key,当有继承存在,$base_key代表root base theme,否则就是current theme。当前主题有声明engine属性时,prefix就是engine属性,否则就是$base_key。

if (!empty($theme->info['base theme'])) {
  // Determine the root base theme.
  $base_key = key($lists['theme'][$key]->base_themes);
  
  // Add the base theme's theme engine info.
  $lists['theme'][$key]->info['engine'] = isset($lists['theme'][$base_key]->info['engine']) ? $lists['theme'][$base_key]->info['engine'] : 'theme';
}
else {
  // A plain theme is its own engine.
  $base_key = $key;
  if (!isset($lists['theme'][$key]->info['engine'])) {
    $lists['theme'][$key]->info['engine'] = 'theme';
  }
}

// Set the theme engine prefix.
$lists['theme'][$key]->prefix = ($lists['theme'][$key]->info['engine'] == 'theme') ? $base_key : $lists['theme'][$key]->info['engine'];
原文地址:https://www.cnblogs.com/eastson/p/3372119.html