zoukankan      html  css  js  c++  java
  • 解析_theme_build_registry()和_theme_process_registry()

    Drupal使用_theme_build_registry()和_theme_process_registry()两个函数构建theme registry。theme registry是theme hook的集合组数。这里以practice模块定义两个theme hook为例,说明一下theme registry的构建过程。

    环境:
    1. cool_breadcrumbs:定义在practice_theme()中,用function实现。
    2. cool_messages:定义在practice_theme()中,用template实现。
    3. 使用默认PHPTemplate主题引擎。
    4. 使用sub_bartik主题,该主题继承自bartik。

    _theme_build_registry()的函数原型:

    function _theme_build_registry($theme, $base_theme, $theme_engine) {
      ... ...
    }

    _theme_build_registry()调用了_theme_process_registry(),而且还调用了很多次:
    1. 所有实现了hook_theme()钩子的模块,每个模块都要调用一次:

    foreach (module_implements('theme') as $module) {
      // 注意调用时$name=模块名称, $type='module', $theme=模块名称, $path=模块路径
      _theme_process_registry($cache, $module, 'module', $module, drupal_get_path('module', $module));
    }

    2. 每个base theme都要调用一次。Drupal中的theme是可以继承的,而且可以多级继承。

    // Process each base theme.
    foreach ($base_theme as $base) {
      // If the base theme uses a theme engine, process its hooks.
      $base_path = dirname($base->filename);
      if ($theme_engine) {
        // 注意调用时$name=theme engine name, $type='base_theme_engine', $theme=base theme name, $path=base theme path
        // 对theme engine调用时,$theme都是对应的theme name, $path都是对应的theme path
        _theme_process_registry($cache, $theme_engine, 'base_theme_engine', $base->name, $base_path);
      }
      // 注意调用时$name=base theme name, $type='base_theme', $theme=base theme name, $path=base theme path
      _theme_process_registry($cache, $base->name, 'base_theme', $base->name, $base_path);
    }

    3. 对theme engine调用一次。

    // And then the same thing, but for the theme.
    if ($theme_engine) {
      // 注意调用时$name=theme engine name, $type='theme_engine', $theme=theme name, $path=theme path
      // 对theme engine调用时,$theme都是对应的theme name, $path都是对应的theme path
      _theme_process_registry($cache, $theme_engine, 'theme_engine', $theme->name, dirname($theme->filename));
    }

    4. 对theme调用一次。

    // Finally, hooks provided by the theme itself.
    // 注意调用时$name=theme name, $type='theme', $theme=theme name, $path=theme path
    _theme_process_registry($cache, $theme->name, 'theme', $theme->name, dirname($theme->filename));


    _theme_process_registry()的函数原型:

    function _theme_process_registry(&$cache, $name, $type, $theme, $path) {
      ... ... // 注意这里的参数$cache是传址的
    }

    从上面的_theme_build_registry()知道,_theme_build_registry()会在多种情况下被执行:
    1.module
    2. base theme engine
    3. base theme
    4. theme engine
    5. theme
    每种情况被执行时_theme_build_registry()都会找是否有hook_theme()钩子存在,在hook_theme返回的结果被处理后,合并到$cache,注意$cache参数是传址的。

    $variable_process_phases = array(
      'preprocess functions' => 'preprocess',
      'process functions'    => 'process',
    );
    
    $hook_defaults = array(
      'variables' => TRUE,
      'render element' => TRUE,
      'pattern' => TRUE,
      'base hook' => TRUE,
    );
    
    // Invoke the hook_theme() implementation, process what is returned, and
    // merge it into $cache.
    $function = $name . '_theme';
    if (function_exists($function)) {
      $result = $function($cache, $type, $theme, $path);
      foreach ($result as $hook => $info) {
        // When a theme or engine overrides a module's theme function
        // $result[$hook] will only contain key/value pairs for information being
        // overridden.  Pull the rest of the information from what was defined by
        // an earlier hook.
    
        // Fill in the type and path of the module, theme, or engine that
        // implements this theme function.
        $result[$hook]['type'] = $type; 
        $result[$hook]['theme path'] = $path;
    
        // 注意这里的type和theme path,这和传入的参数密切相关
        // 当type=module时,theme path=module path
        // 当type=base theme engine时,因为传入的是base theme path,所以theme path=base theme path
        // 当type=base them时,theme path=base theme path
        // 当type=theme engine时,因为传入的是current theme path,所以theme path=current theme path
        // 当type=theme时,theme path=current theme path
    
        // If function and file are omitted, default to standard naming
        // conventions.
        if (!isset($info['template']) && !isset($info['function'])) {
          $result[$hook]['function'] = ($type == 'module' ? 'theme_' : $name . '_') . $hook;
        }
    
        // 在hook_theme()定义theme hook时,一般会设置template或者function
        // 如果两者都没有设置,则默认地type=module时为theme_$hook(),或者$name_$hook()
        // 例如type=theme,则可能是bartik_cool_messages()
        // 或者type=theme engine,则可能是phptemplate_cool_engine()
    
        if (isset($cache[$hook]['includes'])) {
          $result[$hook]['includes'] = $cache[$hook]['includes'];
        }
    
        // $cache[$hook]是什么意思?
        // 在后面会看到这样一句代码:$cache = $result + $cache;
        // $cache合并了当前的hook_theme()结果$result,并确保$result优先$cache
        // 举例来说,可能在practice模块中定义了cool_messsages,
        // 当_theme_process_registry()在type=module被执行完成后,$cache就应该有了cool_messages。
        // 后面的bartik又修改了cool_messages的定义,当type=theme执行完成后,
        // $cache的就是两者合并后的结果,并且后面定义的优先于前面定义的。
    
        // If the theme implementation defines a file, then also use the path
        // that it defined. Otherwise use the default path. This allows
        // system.module to declare theme functions on behalf of core .include
        // files.
        if (isset($info['file'])) {
          $include_file = isset($info['path']) ? $info['path'] : $path;
          $include_file .= '/' . $info['file'];
          include_once DRUPAL_ROOT . '/' . $include_file;
          $result[$hook]['includes'][] = $include_file;
        }
    
        // 可以定义一个专门的theme function file,用$info['file']说明
        // 这个theme function file可能不属于当前模块,例如可能是system模块用到core模块里面的文件,
        // 这时候需要用$info['path']说明这个theme function file所在的目录
    
        // If the default keys are not set, use the default values registered
        // by the module.
        if (isset($cache[$hook])) {
          $result[$hook] += array_intersect_key($cache[$hook], $hook_defaults);
        }
    
        // The following apply only to theming hooks implemented as templates.
        if (isset($info['template'])) {
          // Prepend the current theming path when none is set.
          if (!isset($info['path'])) {
            // 将template转成完整路径
            $result[$hook]['template'] = $path . '/' . $info['template'];
          }
        }
    
        // Allow variable processors for all theming hooks, whether the hook is
        // implemented as a template or as a function.
        foreach ($variable_process_phases as $phase_key => $phase) {
          // Check for existing variable processors. Ensure arrayness.
          if (!isset($info[$phase_key]) || !is_array($info[$phase_key])) {
            $info[$phase_key] = array();
            $prefixes = array();
            if ($type == 'module') {
              // Default variable processor prefix.
              $prefixes[] = 'template';
              // Add all modules so they can intervene with their own variable
              // processors. This allows them to provide variable processors even
              // if they are not the owner of the current hook.
              $prefixes += module_list();
            }
            elseif ($type == 'theme_engine' || $type == 'base_theme_engine') {
              // Theme engines get an extra set that come before the normally
              // named variable processors.
              $prefixes[] = $name . '_engine';
              // The theme engine registers on behalf of the theme using the
              // theme's name.
              $prefixes[] = $theme;
            }
            else {
              // This applies when the theme manually registers their own variable
              // processors.
              $prefixes[] = $name;
            }
            foreach ($prefixes as $prefix) {
              // Only use non-hook-specific variable processors for theming hooks
              // implemented as templates. See theme().
              if (isset($info['template']) && function_exists($prefix . '_' . $phase)) {
                $info[$phase_key][] = $prefix . '_' . $phase;
              }
              if (function_exists($prefix . '_' . $phase . '_' . $hook)) {
                $info[$phase_key][] = $prefix . '_' . $phase . '_' . $hook;
              }
            }
    
            // variable processor,变量处理器,这是一个数组
            // 变量处理器分两种:preprocess function和皮肉process function
            // 当type=module时,按照下列顺序查找(以cool_messages为例):
            //       template_preprocess()
            //       template_preprocess_cool_messages()
            //       moduleA_preprocess()
            //       moduleA_preprocess_cool_messages()
            //       ... ...
            //       moduleZ_preprocess()
            //       moduleZ_preprocess_cool_messages()
            //       ---
            //       template_process()
            //       template_process_cool_messages()
            //       moduleA_process()
            //       moduleA_process_cool_messages()
            //       ... ...
            //       moduleZ_process()
            //       moduleZ_process_cool_messages()
            //
            // 当type=theme_engine/base_theme_engine时,按照下列顺序查找:
            //       phptemplate_engine_preprocess()
            //       phptemplate_engine_preprocess_cool_messages()
            //       bartik_preprocess()
            //       bartik_preprocess_cool_messages()
            //       ---
            //       phptemplate_engine_process()
            //       phptemplate_engine_process_cool_messages()
            //       bartik_process()
            //       bartik_process_cool_messages()
            //
            // 当type=theme/base_theme时,按照下列顺序查找:
            //       bartik_preprocess()
            //       bartik_preprocess_cool_messages()
            //       ---
            //       bartik_process()
            //       bartik_process_cool_messages()
    
          }
          // Check for the override flag and prevent the cached variable
          // processors from being used. This allows themes or theme engines to
          // remove variable processors set earlier in the registry build.
          if (!empty($info['override ' . $phase_key])) {
            // Flag not needed inside the registry.
            unset($result[$hook]['override ' . $phase_key]);
            // 色泽override preprocess functions这样的参数,
            // 可以忽略其它情况下的变量处理器
          }
          elseif (isset($cache[$hook][$phase_key]) && is_array($cache[$hook][$phase_key])) {
            $info[$phase_key] = array_merge($cache[$hook][$phase_key], $info[$phase_key]);
            // 这里将$cache[$hook][$phase_key]和$info[$phase_key]做了合并,
            // 也就是说可能出现这样的情况:
            //       practice_preprocess()/practice_preproces_cool_messages()    模块practice的缺省处理器
            //       other_preproces_cool_messages()                             模块other定义的cool_messages处理器
            //       phptemplate_engine_preprocess_cool_messages()               主题引擎定义的cool_messages处理器
            //       bartik_preprocess_cool_message()                            主题bartik定义的cool_messages处理器
            //       sub_bartik_preprocess_cool_message()                        主题sub_bartik定义的cool_messages处理器
            // 这些变量处理器是没有顺序的,这一点要特别注意
          }
          $result[$hook][$phase_key] = $info[$phase_key];
        }
      }
    
      // Merge the newly created theme hooks into the existing cache.
      // 合并$result到$cache,这一句代码很重要
      // _theme_build_registry()执行完成后,$cache就是最后的theme registry
      $cache = $result + $cache;
    }

    当theme/base theme被执行时,_theme_process_registry()会自动关联在theme里面定义的变量处理器:

    // $result是hook_theme()返回的结果
    // phptemplate_theme()做了两件事情:
    // 一是搜索get_defined_functions()中所有的theme function,
    // 二是搜索主题目录下所有以.tpl.php结尾的theme template,
    // 然后返回到$result,再保存到$cache.
    // 例如,theme目录中可以存在一个cool_sideleft.tpl.php这样一个theme template,
    // 不需要用hook_theme()定义这个theme hook,phptemplate会自动搜索这个theme template注册到$cache。
    // 
    // phptemplate执行在前,theme执行在后,
    // 当theme执行时,$cache已经包含了them中定义所有theme function和theme template。
    // 这时候,可以在theme定义变量处理器,例如bartik_preprocess_cool_sideleft()。
    // 执行下面的代码可以将bartik_preprocess_cool_sideleft()关联到cool_sideleft。
    
    // Let themes have variable processors even if they didn't register a
    // template.
    if ($type == 'theme' || $type == 'base_theme') {
      foreach ($cache as $hook => $info) {
        // Check only if not registered by the theme or engine.
        if (empty($result[$hook])) {
          foreach ($variable_process_phases as $phase_key => $phase) {
            if (!isset($info[$phase_key])) {
              $cache[$hook][$phase_key] = array();
            }
            // Only use non-hook-specific variable processors for theming hooks
            // implemented as templates. See theme().
            if (isset($info['template']) && function_exists($name . '_' . $phase)) {
              $cache[$hook][$phase_key][] = $name . '_' . $phase;
            }
            if (function_exists($name . '_' . $phase . '_' . $hook)) {
              $cache[$hook][$phase_key][] = $name . '_' . $phase . '_' . $hook;
              $cache[$hook]['theme path'] = $path;
            }
            // Ensure uniqueness.
            $cache[$hook][$phase_key] = array_unique($cache[$hook][$phase_key]);
          }
        }
      }
    }


    情境A:接文章开头假设的例子,我们用practice_theme()定义两个theme hook:

    function practice_theme() {
        return array(
            'cool_breadcrumbs' => array(
                'render element' => 'breadcrumbs',
                'function' => 'practice_cool_breadcrumbs',
            ),
            'cool_messages' => array(
                'render element' => 'messages',
                'template' => 'cool_messages',
            ),
        );
    }

    要完成上面的定义,需要建立一个名为practice_cool_breadcrumbs的theme function:

    function practice_cool_breadcrumbs($variables) {
      return '<div>Demo Breadcrumbs</div>';
    }

    还需要建立一个名为cool_messages.tpl.php的theme template:

    <?php
    // sites/all/modules/practice/cool_messages.tpl.php
    print '<div>Demo Messages</div>';

    到这里,practice模块新增的两个theme hook就完成了。当_theme_process_registry($type='module', $name='practice')执行完成后,对应的$result结果如下:

    $result = array(
      'cool_breadcrumbs' => array(
        'render element' => 'breadcrumbs',
        'function' => 'practice_cool_breadcrumbs',
        'type' => 'module',
        'theme path' => 'sites/all/modules/practice',
        'preprocess functions' => array(),
        'process functions' => array(),
      ),
      'cool_messages' => array(
        'render element' => 'messages',
        'template' => 'sites/all/modules/practice/cool_messages', // template转成了完整路径
        'type' => 'module',
        'theme path' => 'sites/all/modules/practice',
        'preprocess functions' => array( // 用template实现的theme hook,默认的会加上template_preprocess/process()
          0 => 'template_preprocess', 
        ),
        'process functions' => array(
          0 => 'template_process',
        ),
      ),
    );

    因为没有在其它地方修改这两个theme hook,所有最后的$cache和$result是一样的。

    情境B:续情境A。theme hook可以定义变量处理器preprocess function和process function。实质上,情境A中的template_preprocess()和template_process()也是变量处理器。

    function practice_preprocess(&$variables, $hook) { ... }
    function practice_process(&$variables, $hook) { ... }

    _theme_process_registry($type='module', $name='practice')执行完成后,$result结果如下:

    $result = array(
      'cool_breadcrumbs' => array(
        ... ...
        'preprocess functions' => array(), // 不带theme hook名称的变量处理器不适用于function
        'process functions' => array(),
      ),
      'cool_messages' => array(
        ... ...
        'preprocess functions' => array(
          0 => 'template_preprocess', 
          1 => 'practice_preprocess', // 不带theme hook名称的变量处理器只针对template
        ),
        'process functions' => array(
          0 => 'template_process', 
          1 => 'practice_preprocess',
        ),
      ),
    );

    上面的变量处理器不带theme hook名称,这样的处理器适用与所有用template实现的theme hook。带名称的处理器只适用于指定名称的theme hook:

    function practice_preprocess_cool_breadcrumbs(&$variables, $hook) { ... }
    
    $result = array(
      'cool_breadcrumbs' => array(
        'preprocess functions' => array(
          0 => 'practice_preprocess_cool_breadcrumbs', // 带名称的处理器只适用于指定名称的theme hook
        ),
        'process functions' => array(),
      ),
      ... ...
    );

    情境C:续情境A。情境B是在theme hook定义所在的模块practice建立处理器,在其它模块也是可以的。其它模块定义处理器也可以分通用(不带theme hook名称,适用与所有的template)和专用(带theme hook名称,只适用于指定名称)两种。

    function other_preprocess(&$variables, $hook) { ... }
    function other_preprocess_cool_messages(&$variables, $hook) { ... }
    
    $result = array(
      'cool_messages' => array(
        'preprocess functions' => array(
          0 => 'template_preprocess',
          1 => 'other_preprocess',
          2 => 'other_preprocess_cool_messages',
        ),
        'process functions' => array(
          0 => 'template_process', 
        ),
      ),
    );

    情境D:续情境A。在theme中也可以为theme hook定义处理器。这部分的处理是在_theme_process_registry($type='theme/base_theme')的最后实现的:

    if ($type == 'theme' || $type == 'base_theme') {
      foreach ($cache as $hook => $info) { // 只针对在$cache中已经注册过的theme hook
        // Check only if not registered by the theme or engine.
        if (empty($result[$hook])) { // empty($result[$hook])表明是没有在theme的hook_theme()钩子中定义
          foreach ($variable_process_phases as $phase_key => $phase) {
            if (!isset($info[$phase_key])) {
              $cache[$hook][$phase_key] = array();
            }
            // Only use non-hook-specific variable processors for theming hooks
            // implemented as templates. See theme().
            if (isset($info['template']) && function_exists($name . '_' . $phase)) {
              $cache[$hook][$phase_key][] = $name . '_' . $phase;
            }
            if (function_exists($name . '_' . $phase . '_' . $hook)) {
              $cache[$hook][$phase_key][] = $name . '_' . $phase . '_' . $hook;
              $cache[$hook]['theme path'] = $path;
            }
            // Ensure uniqueness.
            $cache[$hook][$phase_key] = array_unique($cache[$hook][$phase_key]);
          }
        }
      }
    }

    例如,情境A中的cool_messages,可以在theme中再定义一个处理器:

    function bartik_preprocess_cool_messages(&$variables) { ... }
    
    // _theme_process_registry($type='module', $name='practice')执行完毕后的$cache
    $cache = array(
      'cool_messages' => array(
        'preprocess functions' => array(
          0 => 'template_preprocess', 
        ),
        'process functions' => array(
          0 => 'template_process',
        ),
      ),
    );
    
    // _theme_process_registry($type='theme', $name='bartik')执行完毕后的$cache
    $cache = array(
      'cool_messages' => array(
        'preprocess functions' => array(
          0 => 'template_preprocess',
          1 => 'bartik_preprocess_cool_messages', // bartik中定义的处理器
        ),
        'process functions' => array(
          0 => 'template_process',
        ),
      ),
    );

    情境E:续情境A。hook_theme()定义的theme hook可以在主题theme中被重载。这里的重载有几个意思:
    1. theme function重载。例如,cool_breadcrumbs默认由practice_cool_breadcrumbs()输出,可以在主题中定义bartik_cool_breadcrumbs()实现重载。
    2. theme template重载。例如,cool_messages默认由practice/cool_messages.tpl.php输出,可以在主题中定义cool_messages.tpl.php实现重载。
    3. theme suggestion重载。例如,名为page的theme hook,默认可能是在某个模块中顶一顶,可以在主题中定义bartik_page()实现函数重载,定义bartik_page__node()/bartik_page__node__1()这样的函数实现theme suggestion函数重载;也可以在主题中定义page.tpl.php实现模板重载,定义page__node.tpl.php/page__node__1.tpl.php这样的模板实现theme suggestion模板重载。

    function phptemplate_theme($existing, $type, $theme, $path) {
      $templates = drupal_find_theme_functions($existing, array($theme));
      $templates += drupal_find_theme_templates($existing, '.tpl.php', $path);
      return $templates;
    }
    
    function drupal_find_theme_functions($cache, $prefixes) {
      $implementations = array();
      $functions = get_defined_functions();
    
      // 查找以theme名称开头的theme functions
      // 注意这里只处理$cache中已注册的theme hook
      // $prefix指的是theme名称, 例如bartik
    
      foreach ($cache as $hook => $info) { 
        foreach ($prefixes as $prefix) { 
    
          // Find theme functions that implement possible "suggestion" variants of
          // registered theme hooks and add those as new registered theme hooks.
          // The 'pattern' key defines a common prefix that all suggestions must
          // start with. The default is the name of the hook followed by '__'. An
          // 'base hook' key is added to each entry made for a found suggestion,
          // so that common functionality can be implemented for all suggestions of
          // the same base hook. To keep things simple, deep hierarchy of
          // suggestions is not supported: each suggestion's 'base hook' key
          // refers to a base hook, not to another suggestion, and all suggestions
          // are found using the base hook's pattern, not a pattern from an
          // intermediary suggestion.
    
          // 这里查找的是theme suggestion functions
          // 例如,在$cahce中已存在名为page的theme hook
          // 可以在theme中定义一系列的theme suggestion functions:
          //     bartik_page__node()
          //     bartik_page__node__1()
          //
          // theme suggestion会做为一个新的theme hook被注册,例如
          //     $cache['page__node__1'] = ...
          //
          // theme suggesion hook的base hook被标记为$hook
    
          $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
          if (!isset($info['base hook']) && !empty($pattern)) {
            $matches = preg_grep('/^' . $prefix . '_' . $pattern . '/', $functions['user']);
            if ($matches) {
              foreach ($matches as $match) {
                $new_hook = substr($match, strlen($prefix) + 1);
                $arg_name = isset($info['variables']) ? 'variables' : 'render element';
                $implementations[$new_hook] = array(
                  'function' => $match,
                  $arg_name => $info[$arg_name],
                  'base hook' => $hook,
                );
              }
            }
          }
    
          // Find theme functions that implement registered theme hooks and include
          // that in what is returned so that the registry knows that the theme has
          // this implementation.
    
          // 如果存在bartik_page()函数,则覆盖hook_theme()定义的page实现
          //
          // 覆盖是在_theme_process_registry()处理的, $result是phptemplate_theme()返回的结果:
          // if (isset($cache[$hook])) {
          //  $result[$hook] += array_intersect_key($cache[$hook], $hook_defaults);
          // }
    
          if (function_exists($prefix . '_' . $hook)) {
            $implementations[$hook] = array(
              'function' => $prefix . '_' . $hook,
            );
          }
        }
      }
    
      return $implementations;
    }
    
    function drupal_find_theme_templates($cache, $extension, $path) {
      $implementations = array();
    
      // Collect paths to all sub-themes grouped by base themes. These will be
      // used for filtering. This allows base themes to have sub-themes in its
      // folder hierarchy without affecting the base themes template discovery.
      $theme_paths = array();
      foreach (list_themes() as $theme_info) {
        if (!empty($theme_info->base_theme)) {
          $theme_paths[$theme_info->base_theme][$theme_info->name] = dirname($theme_info->filename);
        }
      }
      foreach ($theme_paths as $basetheme => $subthemes) {
        foreach ($subthemes as $subtheme => $subtheme_path) {
          if (isset($theme_paths[$subtheme])) {
            $theme_paths[$basetheme] = array_merge($theme_paths[$basetheme], $theme_paths[$subtheme]);
          }
        }
      }
      global $theme;
      $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] : array();
    
      // Escape the periods in the extension.
      $regex = '/' . str_replace('.', '.', $extension) . '$/';
      // Get a listing of all template files in the path to search.
      $files = drupal_system_listing($regex, $path, 'name', 0);
    
      // 在theme目录下查找所有以.tpl.php结尾的模板文件:
      //    page.tpl.php
      //    page__node.tpl.php
      //    page__node__1.tpl.php
    
      // Find templates that implement registered theme hooks and include that in
      // what is returned so that the registry knows that the theme has this
      // implementation.
      foreach ($files as $template => $file) {
        // Ignore sub-theme templates for the current theme.
        if (strpos($file->uri, str_replace($subtheme_paths, '', $file->uri)) !== 0) {
          continue;
        }
        // Chop off the remaining extensions if there are any. $template already
        // has the rightmost extension removed, but there might still be more,
        // such as with .tpl.php, which still has .tpl in $template at this point.
        if (($pos = strpos($template, '.')) !== FALSE) {
          $template = substr($template, 0, $pos);
        }
        // Transform - in filenames to _ to match function naming scheme
        // for the purposes of searching.
        $hook = strtr($template, '-', '_');
        if (isset($cache[$hook])) { 
          // 只处理在$cache中注册的theme hook
          // 如果存page.tpl.php模板, 则覆盖hook_theme()定义的page实现
          $implementations[$hook] = array(
            'template' => $template,
            'path' => dirname($file->uri),
          );
        }
      }
    
      // Find templates that implement possible "suggestion" variants of registered
      // theme hooks and add those as new registered theme hooks. See
      // drupal_find_theme_functions() for more information about suggestions and
      // the use of 'pattern' and 'base hook'.
      $patterns = array_keys($files);
      foreach ($cache as $hook => $info) { // 循环处理在$cache中注册的theme hook
        $pattern = isset($info['pattern']) ? $info['pattern'] : ($hook . '__');
        if (!isset($info['base hook']) && !empty($pattern)) {
          // Transform _ in pattern to - to match file naming scheme
          // for the purposes of searching.
          $pattern = strtr($pattern, '_', '-');
    
          // 这里查找的是theme suggestion templates
          // theme suggestion会做为一个新的theme hook被注册,例如
          //     $cache['page__node__1'] = ...
          //
          // theme suggesion hook的base hook被标记为$hook
    
          $matches = preg_grep('/^' . $pattern . '/', $patterns);
          if ($matches) {
            foreach ($matches as $match) {
              $file = substr($match, 0, strpos($match, '.'));
              // Put the underscores back in for the hook name and register this
              // pattern.
              $arg_name = isset($info['variables']) ? 'variables' : 'render element';
              $implementations[strtr($file, '-', '_')] = array(
                'template' => $file,
                'path' => dirname($files[$match]->uri),
                $arg_name => $info[$arg_name],
                'base hook' => $hook,
              );
            }
          }
        }
      }
      return $implementations;
    }

    情境F:独立情境。除了在module中用hook_theme()钩子定义theme hook外,也可以在theme和theme engine用hook_theme()钩子theme hook。

    function bartik_theme() {
      return array(
        'cool_sideleft' => array(
          'render element' => 'sideleft',
          'template' => 'cool_sideleft',
        ),
      );
    }
    
    function bartik_preprocess_cool_sideleft(&$variables) { ... }
    
    $result = array(
      'cool_sideleft' => array(
        'render element' => 'sideleft',
        'template' => 'themes/bartik/cool_sideleft',
        'type' => 'theme',
        'theme path' => 'themes/bartik',
        'preprocess functions' => array(
          0 => 'bartik_preprocess_cool_sideleft', // 没有template_preprocess(). 处理器要以bartik_开头。
        ),
        'process functions' => array(),
      ),
    );
  • 相关阅读:
    响应式网页设计项目#1---Tribute Page to Kobe and Gigi---致敬科比和Gigi
    Vue---第二部分
    Vue---概述 第一部分
    SaaS应用“正益工作”发布,为大中型企业轻松构建移动门户
    6.24 AppCan移动开发者大会:议程重大更新,报名即将关闭
    【6.24-AppCan移动开发大会倒计时】科大讯飞来了!
    6.24 AppCan移动开发者大会,我爱我家即将闪亮登场!
    惊曝6.24AppCan移动开发大会参展名录,现场礼品超多!
    6.24AppCan移动开发者大会价值30万的展示机会归了谁?
    6月24日AppCan移动开发者大会礼品清单遭泄露
  • 原文地址:https://www.cnblogs.com/eastson/p/3703687.html
Copyright © 2011-2022 走看看