KXStudio Website https://kx.studio/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
4.9KB

  1. <?php
  2. /**
  3. * Twig::API
  4. * ~~~~~~~~~
  5. *
  6. * The High-Level API
  7. *
  8. * :copyright: 2008 by Armin Ronacher.
  9. * :license: BSD.
  10. */
  11. /**
  12. * Load the compiler system. Call this before you access the
  13. * compiler!
  14. */
  15. function twig_load_compiler()
  16. {
  17. if (!defined('TWIG_COMPILER_INCLUDED'))
  18. require TWIG_BASE . '/compiler.php';
  19. }
  20. /**
  21. * A helper function that can be used by filters to get the
  22. * current active template. This use useful to access variables
  23. * on the template like the charset.
  24. */
  25. function twig_get_current_template()
  26. {
  27. return $GLOBALS['twig_current_template'];
  28. }
  29. /* the current template that is rendered. This used used internally
  30. and is an implementation detail. Don't tamper with that. */
  31. $twig_current_template = NULL;
  32. /**
  33. * This class wraps a template instance as returned by the compiler and
  34. * is usually constructed from the `Twig_Loader`.
  35. */
  36. class Twig_Template
  37. {
  38. private $instance;
  39. public $charset;
  40. public $loader;
  41. public function __construct($instance, $charset=NULL, $loader)
  42. {
  43. $this->instance = $instance;
  44. $this->charset = $charset;
  45. $this->loader = $loader;
  46. }
  47. /**
  48. * Render the template with the given context and return it
  49. * as string.
  50. */
  51. public function render($context=NULL)
  52. {
  53. ob_start();
  54. $this->display($context);
  55. return ob_get_clean();
  56. }
  57. /**
  58. * Works like `render()` but prints the output.
  59. */
  60. public function display($context=NULL)
  61. {
  62. global $twig_current_template;
  63. $old = $twig_current_template;
  64. $twig_current_template = $this;
  65. if (is_null($context))
  66. $context = array();
  67. $this->instance->render($context);
  68. $twig_current_template = $old;
  69. }
  70. }
  71. /**
  72. * Baseclass for custom loaders. Subclasses have to provide a
  73. * getFilename method.
  74. */
  75. class Twig_BaseLoader
  76. {
  77. public $cache;
  78. public $charset;
  79. public function __construct($cache=NULL, $charset=NULL)
  80. {
  81. $this->cache = $cache;
  82. $this->charset = $charset;
  83. }
  84. public function getTemplate($name)
  85. {
  86. $cls = $this->requireTemplate($name);
  87. return new Twig_Template(new $cls, $this->charset, $this);
  88. }
  89. public function getCacheFilename($name)
  90. {
  91. return $this->cache . '/twig_' . md5($name) . '.cache';
  92. }
  93. public function requireTemplate($name)
  94. {
  95. $cls = '__TwigTemplate_' . md5($name);
  96. if (!class_exists($cls)) {
  97. if (is_null($this->cache)) {
  98. $this->evalTemplate($name);
  99. return $cls;
  100. }
  101. $fn = $this->getFilename($name);
  102. if (!file_exists($fn))
  103. throw new Twig_TemplateNotFound($name);
  104. $cache_fn = $this->getCacheFilename($name);
  105. if (!file_exists($cache_fn) ||
  106. filemtime($cache_fn) < filemtime($fn)) {
  107. twig_load_compiler();
  108. $fp = @fopen($cache_fn, 'wb');
  109. if (!$fp) {
  110. $this->evalTemplate($name, $fn);
  111. return $cls;
  112. }
  113. $compiler = new Twig_FileCompiler($fp);
  114. $this->compileTemplate($name, $compiler, $fn);
  115. fclose($fp);
  116. }
  117. include $cache_fn;
  118. }
  119. return $cls;
  120. }
  121. public function compileTemplate($name, $compiler=NULL, $fn=NULL)
  122. {
  123. twig_load_compiler();
  124. if (is_null($compiler)) {
  125. $compiler = new Twig_StringCompiler();
  126. $returnCode = true;
  127. }
  128. else
  129. $returnCode = false;
  130. if (is_null($fn))
  131. $fn = $this->getFilename($name);
  132. $node = twig_parse(file_get_contents($fn, $name), $name);
  133. $node->compile($compiler);
  134. if ($returnCode)
  135. return $compiler->getCode();
  136. }
  137. private function evalTemplate($name, $fn=NULL)
  138. {
  139. $code = $this->compileTemplate($name, NULL, $fn);
  140. # echo "ORIGINAL: <textarea rows=15 style=\"width: 100%\">".fix(print_r($code, true))."</textarea>";
  141. $code = preg_replace('/(?!echo twig_get_attribute.+)echo "[\\\\tn]+";/', "", $code); # Remove blank lines
  142. #echo "STRIPPED: <textarea rows=15 style=\"width: 100%\">".fix(print_r($code, true))."</textarea>";
  143. eval('?>' . $code);
  144. }
  145. }
  146. /**
  147. * Helper class that loads templates.
  148. */
  149. class Twig_Loader extends Twig_BaseLoader
  150. {
  151. public $folder;
  152. public function __construct($folder, $cache=NULL, $charset=NULL)
  153. {
  154. parent::__construct($cache, $charset);
  155. $this->folder = $folder;
  156. }
  157. public function getFilename($name)
  158. {
  159. if ($name[0] == '/' or preg_match("/[a-zA-Z]:\\\/", $name)) return $name;
  160. $path = array();
  161. foreach (explode('/', $name) as $part) {
  162. if ($part[0] != '.')
  163. array_push($path, $part);
  164. }
  165. return $this->folder . '/' . implode('/', $path) ;
  166. }
  167. }