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  
   3  /*
   4   * This file is part of Mustache.php.
   5   *
   6   * (c) 2010-2017 Justin Hileman
   7   *
   8   * For the full copyright and license information, please view the LICENSE
   9   * file that was distributed with this source code.
  10   */
  11  
  12  /**
  13   * Abstract Mustache Template class.
  14   *
  15   * @abstract
  16   */
  17  abstract class Mustache_Template
  18  {
  19      /**
  20       * @var Mustache_Engine
  21       */
  22      protected $mustache;
  23  
  24      /**
  25       * @var bool
  26       */
  27      protected $strictCallables = false;
  28  
  29      /**
  30       * Mustache Template constructor.
  31       *
  32       * @param Mustache_Engine $mustache
  33       */
  34      public function __construct(Mustache_Engine $mustache)
  35      {
  36          $this->mustache = $mustache;
  37      }
  38  
  39      /**
  40       * Mustache Template instances can be treated as a function and rendered by simply calling them.
  41       *
  42       *     $m = new Mustache_Engine;
  43       *     $tpl = $m->loadTemplate('Hello, {{ name }}!');
  44       *     echo $tpl(array('name' => 'World')); // "Hello, World!"
  45       *
  46       * @see Mustache_Template::render
  47       *
  48       * @param mixed $context Array or object rendering context (default: array())
  49       *
  50       * @return string Rendered template
  51       */
  52      public function __invoke($context = array())
  53      {
  54          return $this->render($context);
  55      }
  56  
  57      /**
  58       * Render this template given the rendering context.
  59       *
  60       * @param mixed $context Array or object rendering context (default: array())
  61       *
  62       * @return string Rendered template
  63       */
  64      public function render($context = array())
  65      {
  66          return $this->renderInternal(
  67              $this->prepareContextStack($context)
  68          );
  69      }
  70  
  71      /**
  72       * Internal rendering method implemented by Mustache Template concrete subclasses.
  73       *
  74       * This is where the magic happens :)
  75       *
  76       * NOTE: This method is not part of the Mustache.php public API.
  77       *
  78       * @param Mustache_Context $context
  79       * @param string           $indent  (default: '')
  80       *
  81       * @return string Rendered template
  82       */
  83      abstract public function renderInternal(Mustache_Context $context, $indent = '');
  84  
  85      /**
  86       * Tests whether a value should be iterated over (e.g. in a section context).
  87       *
  88       * In most languages there are two distinct array types: list and hash (or whatever you want to call them). Lists
  89       * should be iterated, hashes should be treated as objects. Mustache follows this paradigm for Ruby, Javascript,
  90       * Java, Python, etc.
  91       *
  92       * PHP, however, treats lists and hashes as one primitive type: array. So Mustache.php needs a way to distinguish
  93       * between between a list of things (numeric, normalized array) and a set of variables to be used as section context
  94       * (associative array). In other words, this will be iterated over:
  95       *
  96       *     $items = array(
  97       *         array('name' => 'foo'),
  98       *         array('name' => 'bar'),
  99       *         array('name' => 'baz'),
 100       *     );
 101       *
 102       * ... but this will be used as a section context block:
 103       *
 104       *     $items = array(
 105       *         1        => array('name' => 'foo'),
 106       *         'banana' => array('name' => 'bar'),
 107       *         42       => array('name' => 'baz'),
 108       *     );
 109       *
 110       * @param mixed $value
 111       *
 112       * @return bool True if the value is 'iterable'
 113       */
 114      protected function isIterable($value)
 115      {
 116          switch (gettype($value)) {
 117              case 'object':
 118                  return $value instanceof Traversable;
 119  
 120              case 'array':
 121                  $i = 0;
 122                  foreach ($value as $k => $v) {
 123                      if ($k !== $i++) {
 124                          return false;
 125                      }
 126                  }
 127  
 128                  return true;
 129  
 130              default:
 131                  return false;
 132          }
 133      }
 134  
 135      /**
 136       * Helper method to prepare the Context stack.
 137       *
 138       * Adds the Mustache HelperCollection to the stack's top context frame if helpers are present.
 139       *
 140       * @param mixed $context Optional first context frame (default: null)
 141       *
 142       * @return Mustache_Context
 143       */
 144      protected function prepareContextStack($context = null)
 145      {
 146          $stack = new Mustache_Context();
 147  
 148          $helpers = $this->mustache->getHelpers();
 149          if (!$helpers->isEmpty()) {
 150              $stack->push($helpers);
 151          }
 152  
 153          if (!empty($context)) {
 154              $stack->push($context);
 155          }
 156  
 157          return $stack;
 158      }
 159  
 160      /**
 161       * Resolve a context value.
 162       *
 163       * Invoke the value if it is callable, otherwise return the value.
 164       *
 165       * @param mixed            $value
 166       * @param Mustache_Context $context
 167       *
 168       * @return string
 169       */
 170      protected function resolveValue($value, Mustache_Context $context)
 171      {
 172          if (($this->strictCallables ? is_object($value) : !is_string($value)) && is_callable($value)) {
 173              return $this->mustache
 174                  ->loadLambda((string) call_user_func($value))
 175                  ->renderInternal($context);
 176          }
 177  
 178          return $value;
 179      }
 180  }