Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Class for listing mustache templates.
  19   *
  20   * @package    tool_templatelibrary
  21   * @copyright  2015 Damyon Wiese
  22   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  namespace tool_templatelibrary;
  25  
  26  use core_component;
  27  use core\output\mustache_template_finder;
  28  use coding_exception;
  29  use moodle_exception;
  30  use required_capability_exception;
  31  use stdClass;
  32  
  33  /**
  34   * API exposed by tool_templatelibrary
  35   *
  36   * @copyright  2015 Damyon Wiese
  37   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38   */
  39  class api {
  40  
  41      /**
  42       * Return a list of details about installed templates.
  43       *
  44       * @param string $component Filter the list to a single component.
  45       * @param string $search Search string to optionally filter the list of templates.
  46       * @param string $themename The name of the current theme.
  47       * @return array[string] Where each template is in the form "component/templatename".
  48       */
  49      public static function list_templates($component = '', $search = '', $themename = '') {
  50          global $CFG, $PAGE;
  51  
  52          if (empty($themename)) {
  53              $themename = $PAGE->theme->name;
  54          }
  55          $themeconfig = \theme_config::load($themename);
  56  
  57          $templatedirs = array();
  58          $results = array();
  59  
  60          if ($component !== '') {
  61              // Just look at one component for templates.
  62              $dirs = mustache_template_finder::get_template_directories_for_component($component, $themename);
  63  
  64              $templatedirs[$component] = $dirs;
  65          } else {
  66  
  67              // Look at all the templates dirs for core.
  68              $templatedirs['core'] = mustache_template_finder::get_template_directories_for_component('core', $themename);
  69  
  70              // Look at all the templates dirs for subsystems.
  71              $subsystems = core_component::get_core_subsystems();
  72              foreach ($subsystems as $subsystem => $dir) {
  73                  if (empty($dir)) {
  74                      continue;
  75                  }
  76                  $dir .= '/templates';
  77                  if (is_dir($dir)) {
  78                      $dirs = mustache_template_finder::get_template_directories_for_component('core_' . $subsystem, $themename);
  79                      $templatedirs['core_' . $subsystem] = $dirs;
  80                  }
  81              }
  82  
  83              // Look at all the templates dirs for plugins.
  84              $plugintypes = core_component::get_plugin_types();
  85              foreach ($plugintypes as $type => $dir) {
  86                  $plugins = core_component::get_plugin_list_with_file($type, 'templates', false);
  87                  foreach ($plugins as $plugin => $dir) {
  88                      if ($type == 'theme' && $plugin != $themename && !in_array($plugin, $themeconfig->parents)) {
  89                          continue;
  90                      }
  91                      if (!empty($dir) && is_dir($dir)) {
  92                          $pluginname = $type . '_' . $plugin;
  93                          $dirs = mustache_template_finder::get_template_directories_for_component($pluginname, $themename);
  94                          $templatedirs[$pluginname] = $dirs;
  95                      }
  96                  }
  97              }
  98          }
  99  
 100          foreach ($templatedirs as $templatecomponent => $dirs) {
 101              foreach ($dirs as $dir) {
 102                  if (!is_dir($dir) || !is_readable($dir)) {
 103                      continue;
 104                  }
 105                  $dir = realpath($dir);
 106  
 107                  // List it.
 108                  $directory = new \RecursiveDirectoryIterator($dir);
 109                  $files = new \RecursiveIteratorIterator($directory);
 110  
 111                  foreach ($files as $file) {
 112                      if (!$file->isFile()) {
 113                          continue;
 114                      }
 115                      $filename = substr($file->getRealpath(), strlen($dir) + 1);
 116                      if (strpos($templatecomponent, 'theme_') === 0) {
 117                          if (strpos($filename, '/') !== false && strpos($filename, 'local/') !== 0) {
 118                              // Skip any template in a sub-directory of a theme which is not in a local directory.
 119                              // These are theme overrides of core templates.
 120                              // Note: There is a rare edge case where a theme may override a template and then have additional
 121                              // dependant templates and these will not be shown.
 122                              continue;
 123                          }
 124                      }
 125                      $templatename = str_replace('.mustache', '', $filename);
 126                      $componenttemplatename = "{$templatecomponent}/{$templatename}";
 127  
 128                      if ($search == '' || strpos($componenttemplatename, $search) !== false) {
 129                          $results[$componenttemplatename] = 1;
 130                      }
 131                  }
 132              }
 133          }
 134          $results = array_keys($results);
 135          sort($results);
 136          return $results;
 137      }
 138  
 139      /**
 140       * Return a mustache template.
 141       * Note - this function differs from the function core_output_load_template
 142       * because it will never return a theme overridden version of a template.
 143       *
 144       * @param string $component The component that holds the template.
 145       * @param string $template The name of the template.
 146       * @return string the template or false if template doesn't exist.
 147       */
 148      public static function load_canonical_template($component, $template) {
 149          // Get the list of possible template directories.
 150          $dirs = mustache_template_finder::get_template_directories_for_component($component);
 151          $filename = false;
 152          $themedir = core_component::get_plugin_types()['theme'];
 153  
 154          foreach ($dirs as $dir) {
 155              // Skip theme dirs - we only want the original plugin/core template.
 156              if (strpos($dir, $themedir) === 0) {
 157                  continue;
 158              }
 159  
 160              $candidate = $dir . $template . '.mustache';
 161              if (file_exists($candidate)) {
 162                  $filename = $candidate;
 163                  break;
 164              }
 165          }
 166  
 167          if ($filename === false) {
 168              // There are occasions where we don't have a core template.
 169              return false;
 170          }
 171  
 172          $templatestr = file_get_contents($filename);
 173          return $templatestr;
 174      }
 175  
 176  }