3 +---------------------------------------------------------------------------------+
4 | Copyright (c) 2010 Haanga |
5 +---------------------------------------------------------------------------------+
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met: |
8 | 1. Redistributions of source code must retain the above copyright |
9 | notice, this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
15 | 3. All advertising materials mentioning features or use of this software |
16 | must display the following acknowledgement: |
17 | This product includes software developed by César D. Rodas. |
19 | 4. Neither the name of the César D. Rodas nor the |
20 | names of its contributors may be used to endorse or promote products |
21 | derived from this software without specific prior written permission. |
23 | THIS SOFTWARE IS PROVIDED BY CÉSAR D. RODAS ''AS IS'' AND ANY |
24 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
26 | DISCLAIMED. IN NO EVENT SHALL CÉSAR D. RODAS BE LIABLE FOR ANY |
27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE |
33 +---------------------------------------------------------------------------------+
34 | Authors: César Rodas <crodas@php.net> |
35 +---------------------------------------------------------------------------------+
40 * Haanga Runtime class
42 * Simple class to call templates efficiently. This class aims
43 * to reduce the compilation of a template as less a possible. Also
44 * it will not load in memory the compiler, except when there is not
45 * cache (compiled template) or it is out-dated.
50 protected static $cache_dir;
51 protected static $templates_dir='.';
52 protected static $debug;
53 protected static $bootstrap = NULL;
54 protected static $check_ttl;
55 protected static $check_get;
56 protected static $check_set;
57 protected static $use_autoload = TRUE;
58 protected static $hash_filename = TRUE;
59 protected static $compiler = array();
61 public static $has_compiled;
63 private function __construct()
65 /* The class can't be instanced */
68 final public static function AutoLoad($class)
70 static $loaded = array();
73 if (!isset($loaded[$class]) && substr($class, 0, 6) === 'Haanga' && !class_exists($class, false)) {
75 $path = dirname(__FILE__
);
77 $file = $path.DIRECTORY_SEPARATOR
.str_replace('_', DIRECTORY_SEPARATOR
, $class).'.php';
81 $loaded[$class] = TRUE;
88 // configure(Array $opts) {{{
90 * Configuration to load Haanga
94 * - (string) cache_dir
95 * - (string) tempalte_dir
96 * - (callback) on_compile
99 * - (callback) check_get
100 * - (callback) check_set
101 * - (boolean) autoload
102 * - (boolean) use_hash_filename
106 final public static function configure(Array $opts)
108 foreach ($opts as $option => $value) {
109 switch (strtolower($option)) {
111 self
::setCacheDir($value);
114 self
::setTemplateDir($value);
117 if (is_callable($value)) {
118 self
::$bootstrap = $value;
122 self
::enableDebug((bool)$value);
125 self
::$check_ttl = (int)$value;
128 if (is_callable($value)) {
129 self
::$check_get = $value;
133 if (is_callable($value)) {
134 self
::$check_set = $value;
138 self
::$use_autoload = (bool)$value;
140 case 'use_hash_filename':
141 self
::$hash_filename = (bool)$value;
144 if (is_array($value)) {
145 self
::$compiler = $value;
155 // setCacheDir(string $dir) {{{
157 * Set the directory where the compiled templates
164 public static function setCacheDir($dir)
166 if (!is_dir($dir) && !mkdir($dir, 0777, TRUE)) {
167 throw new Haanga_Exception("{$dir} is not a valid directory");
169 if (!is_writable($dir)) {
170 throw new Haanga_Exception("{$dir} can't be written");
172 self
::$cache_dir = $dir;
176 // setTemplateDir(string $dir) {{{
178 * Set the directory where the templates are located.
184 public static function setTemplateDir($dir)
187 throw new Haanga_Exception("{$dir} is not a valid directory");
189 self
::$templates_dir = $dir;
193 // enableDebug($bool) {{{
194 public static function enableDebug($bool)
196 self
::$debug = $bool;
200 // load(string $file, array $vars, bool $return, array $blocks) {{{
204 * Load template. If the template is already compiled, just the compiled
205 * PHP file will be included an used. If the template is new, or it
206 * had changed, the Haanga compiler is loaded in memory, and the template
210 * @param string $file
212 * @param bool $return
213 * @param array $blocks
215 * @return string|NULL
217 public static function Load($file, $vars = array(), $return=FALSE, $blocks=array())
220 if (empty(self
::$cache_dir)) {
221 throw new Haanga_Exception("Cache dir or template dir is missing");
224 self
::$has_compiled = FALSE;
226 $tpl = self
::$templates_dir.'/'.$file;
228 $callback = "haanga_".$fnc;
230 if (is_callable($callback)) {
231 return $callback($vars, $return, $blocks);
234 $php = self
::$hash_filename ?
$fnc : str_replace(DIRECTORY_SEPARATOR
, '_', $file);
235 $php = self
::$cache_dir.'/'.$php.'.php';
240 if (self
::$check_ttl && self
::$check_get && self
::$check_set) {
242 if (call_user_func(self
::$check_get, $callback)) {
243 /* disable checking for the next $check_ttl seconds */
246 $result = call_user_func(self
::$check_set, $callback, TRUE, self
::$check_ttl);
250 if (!is_file($php) ||
($check && filemtime($tpl) > filemtime($php))) {
252 if (!is_file($tpl)) {
253 /* There is no template nor compiled file */
254 throw new Exception("View {$file} doesn't exists");
260 /* Load needed files (to avoid autoload as much as possible) */
261 $dir = dirname(__FILE__
);
262 require_once "{$dir}/Haanga/AST.php";
263 require_once "{$dir}/Haanga/Compiler.php";
264 require_once "{$dir}/Haanga/Compiler/Runtime.php";
265 require_once "{$dir}/Haanga/Compiler/Parser.php";
266 require_once "{$dir}/Haanga/Compiler/Lexer.php";
267 require_once "{$dir}/Haanga/Generator/PHP.php";
268 require_once "{$dir}/Haanga/Extension.php";
269 require_once "{$dir}/Haanga/Extension/Filter.php";
270 require_once "{$dir}/Haanga/Extension/Tag.php";
272 /* load compiler (done just once) */
273 if (self
::$use_autoload) {
274 spl_autoload_register(array(__CLASS__
, 'AutoLoad'));
277 $compiler = new Haanga_Compiler_Runtime
;
279 if (self
::$bootstrap) {
280 /* call bootstrap hook, just the first time */
281 call_user_func(self
::$bootstrap);
284 if (count(self
::$compiler) != 0) {
285 foreach (self
::$compiler as $opt => $value) {
286 $compiler->setOption($opt, $value);
294 $compiler->setDebug($php.".dump");
297 $code = $compiler->compile_file($tpl, FALSE, $vars);
299 file_put_contents($php, "<?php".$code, LOCK_EX
);
300 self
::$has_compiled = TRUE;
303 if (!is_callable($callback)) {
307 return $callback($vars, $return, $blocks);
318 * vim600: sw=4 ts=4 fdm=marker