More doc comment fiddling
[mediawiki.git] / PHPTAL-NP-0.7.0 / libs / PHPTAL / Template.php
blobcef3465da83aa5c9a3270fd2fa9c5511e86f9428
1 <?php
2 /* vim: set expandtab tabstop=4 shiftwidth=4: */
3 //
4 // Copyright (c) 2003 Laurent Bedubourg
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 //
20 // Authors: Laurent Bedubourg <laurent.bedubourg@free.fr>
21 //
24 class PHPTAL_Template
26 var $_ctx;
27 var $_code;
28 var $_codeFile;
29 var $_funcName;
30 var $_sourceFile;
31 var $_error = false;
32 var $_repository = false;
33 var $_cacheDir = false;
34 var $_parent = false;
35 var $_parentPath = false;
36 var $_prepared = false;
37 var $_cacheManager;
39 var $_outputMode = PHPTAL_XHTML;
41 var $_inputFilters;
42 var $_outputFilters;
43 var $_resolvers;
44 var $_locator;
46 var $_headers = false;
48 var $_translator;
50 var $_encoding = 'UTF-8';
52 /**
53 * Template object constructor.
55 * @param string $file -- The source file name
56 * @param string $repository optional -- Your templates root.
57 * @param string $cache_dir optional -- Intermediate php code repository.
59 function PHPTAL_Template($file, $repository=false, $cache_dir=false)
61 $this->_sourceFile = $file;
62 $this->_repository = $repository;
64 // deduce intermediate php code cache directory
65 if (!$cache_dir) {
66 if (defined('PHPTAL_CACHE_DIR')) {
67 $cache_dir = PHPTAL_CACHE_DIR;
68 } else {
69 $cache_dir = PHPTAL_DEFAULT_CACHE_DIR;
72 $this->_cacheDir = $cache_dir;
74 // instantiate a new context for this template
75 // !!! this context may be overwritten by a parent context
76 $this->_ctx = new PHPTAL_Context();
78 // create resolver vector and the default filesystem resolver
79 $this->_resolvers = new OArray();
80 $this->_resolvers->push(new PHPTAL_SourceResolver());
82 // vector for source filters
83 $this->_inputFilters = new OArray();
84 $this->_outputFilters = new OArray();
86 // if no cache manager set, we instantiate default dummy one
87 if (!isset($this->_cacheManager)) {
88 $this->_cacheManager = new PHPTAL_Cache();
92 /**
93 * Set template ouput type.
95 * Default output is XHTML, so you'll have to call this method only for
96 * specific xml documents with PHPTAL_XML parameter.
98 * @param int $mode -- output mode (PHPTAL_XML) as default system use XHTML
100 function setOutputMode($mode)
102 $this->_outputMode = $mode;
106 * Replace template context with specified hashtable.
108 * @param hash hashtable -- Associative array.
110 function setAll($hash)
112 $this->_ctx = new PHPTAL_Context($hash);
116 * Set a template context value.
118 * @param string $key -- The context key
119 * @param mixed $value -- The context value
121 function set($name, $value)
123 $this->_ctx->set($name, $value);
127 * Set a template context value by reference.
129 * @param string $name -- The template context key
130 * @param mixed $value -- The template context value
132 function setRef($name, &$value)
134 $this->_ctx->setRef($name, $value);
138 * Retrieve template context object.
140 * @return PHPTAL_Context
142 function &getContext()
144 return $this->_ctx;
148 * Set the template context object.
150 * @param PHPTAL_Context $ctx -- The context object
152 function setContext(&$ctx)
154 $this->_ctx =& $ctx;
158 * Set the cache manager to use for Template an Macro calls.
160 * @param PHPTAL_Cache $mngr -- Cache object that will be used to cache
161 * template and macros results.
163 function setCacheManager(&$mngr)
165 $this->_cacheManager =& $mngr;
169 * Retrieve the cache manager used in this template.
171 * @return PHPTAL_Cache
173 function &getCacheManager()
175 return $this->_cacheManager;
179 * Set the I18N implementation to use in this template.
181 * @param PHPTAL_I18N $tr -- I18N implementation
183 function setTranslator(&$tr)
185 $this->_translator =& $tr;
189 * The translator used by this template.
191 * @return PHPTAL_I18N
193 function &getTranslator()
195 return $this->_translator;
199 * Test if the template file exists.
200 * @deprecated use isValid() instead
201 * @return boolean
203 function fileExists()
205 return $this->isValid();
209 * Test if the template resource exists.
211 * @return boolean
213 function isValid()
215 if (isset($this->_locator)) {
216 return true;
219 // use template resolvers to locate template source data
220 // in most cases, there will be only one resolver in the
221 // resolvers list (the default one) which look on the file
222 // system.
224 $i = $this->_resolvers->getNewIterator();
225 while ($i->isValid()) {
226 $resolver =& $i->value();
227 $locator =& $resolver->resolve($this->_sourceFile,
228 $this->_repository,
229 $this->_parentPath);
230 if ($locator && !PEAR::isError($locator)) {
231 $this->_locator =& $locator;
232 $this->_real_path = $this->_locator->realPath();
233 return true;
235 $i->next();
237 return false;
241 * Add a source resolver to the template.
243 * @param PHPTAL_SourceResolver $resolver
244 * The source resolver.
246 function addSourceResolver(&$resolver)
248 $this->_resolvers->pushRef($resolver);
252 * Add filter to this template input filters list.
254 * @param PHPTAL_Filter $filter
255 * A filter which will be invoked on template source.
257 function addInputFilter(&$filter)
259 $this->_inputFilters->pushRef($filter);
263 * Add an output filter to this template output filters list.
265 * @param PHPTAL_Filter $filter
266 * A filter which will be invoked on template output.
268 function addOutputFilter(&$filter)
270 $this->_outputFilters->pushRef($filter);
274 * Retrieve the source template real path.
276 * This method store its result internally if no $file attribute is
277 * specified (work on template internals).
279 * If a file name is specified, this method will try to locate it
280 * exploring current path (PWD), the current template location,
281 * the repository and parent template location.
283 * @param string $file optional
284 * some file name to locate.
286 * @throws FileNotFound
287 * @return string
289 function realpath($file=false)
291 // real template path
292 if (!$file) {
293 if ($this->isValid()) {
294 return $this->_real_path;
295 } else {
296 $ex = new FileNotFound($this->_sourceFile . ' not found');
297 return PEAR::raiseError($ex);
302 // path to some file relative to this template
304 $i = $this->_resolvers->getNewIterator();
305 while ($i->isValid()) {
306 $resolver =& $i->value();
307 $locator =& $resolver->resolve($file,
308 $this->_repository,
309 $this->_real_path);
310 if ($locator) {
311 return $locator->realPath();
313 $i->next();
316 $ex = new FileNotFound($file . ' not found');
317 return PEAR::raiseError($ex);
321 * Set the template result encoding.
323 * Changing this encoding will change htmlentities behaviour.
325 * Example:
327 * $tpl->setEncoding('ISO-8859-1");
329 * See http://fr2.php.net/manual/en/function.htmlentities.php for a list of
330 * supported encodings.
332 * @param $enc string Template encoding
334 function setEncoding($enc)
336 $this->_encoding = $enc;
340 * Retrieve the template result encoding.
342 * @return string
344 function getEncoding()
346 return $this->_encoding;
349 // ----------------------------------------------------------------------
350 // private / protected methods
351 // ----------------------------------------------------------------------
354 * Set the called template. (internal)
356 * @access package
358 function setParent(&$tpl)
360 $this->_parent =& $tpl;
361 $this->_resolvers = $tpl->_resolvers;
362 $this->_inputFilters = $tpl->_inputFilters;
363 $this->_parentPath = $tpl->realPath();
364 $this->_cacheManager =& $tpl->getCacheManager();
365 $this->_translator =& $tpl->_translator;
366 $this->setOutputMode($tpl->_outputMode);
370 * Prepare template execution.
372 * @access private
374 function _prepare()
376 if ($this->_prepared) return;
377 $this->_sourceFile = $this->realpath();
379 // ensure that no error remain
380 if (PEAR::isError($this->_sourceFile)) {
381 return $this->_sourceFile;
383 $this->_funcName = "tpl_" . PHPTAL_MARK . md5($this->_sourceFile);
384 $this->_codeFile = $this->_cacheDir . $this->_funcName . '.php';
385 $this->_prepared = true;
389 * Generate php code from template source
391 * @access private
392 * @throws PHPTALParseException
394 function _generateCode()
396 require_once _phptal_os_path_join(dirname(__FILE__), 'Parser.php');
398 $parser = new PHPTAL_Parser();
399 $parser->_outputMode($this->_outputMode);
400 $data = $this->_locator->data();
402 // activate prefilters on data
403 $i = $this->_inputFilters->getNewIterator();
404 while ($i->isValid()){
405 $filter =& $i->value();
406 $data = $filter->filter($data);
407 $i->next();
410 // parse source
411 $result = $parser->parse($this->_real_path, $data);
412 if (PEAR::isError($result)) {
413 return $result;
416 // generate and store intermediate php code
417 $this->_code = $parser->generateCode($this->_funcName);
418 if (PEAR::isError($this->_code)) {
419 return $this->_code;
424 * Load cached php code
426 * @access private
428 function _loadCachedCode()
430 include_once($this->_codeFile);
431 $this->_code = "#loaded";
435 * Cache generated php code.
437 * @access private
439 function _cacheCode()
441 $fp = @fopen($this->_codeFile, "w");
442 if (!$fp) {
443 return PEAR::raiseError($php_errormsg);
445 fwrite($fp, $this->_code);
446 fclose($fp);
450 * Load or generate php code.
452 * @access private
454 function _load()
456 if (isset($this->_code) && !PEAR::isError($this->_code)) {
457 return;
460 if (!defined('PHPTAL_NO_CACHE')
461 && file_exists($this->_codeFile)
462 && filemtime($this->_codeFile) >= $this->_locator->lastModified()) {
463 return $this->_loadCachedCode();
466 $err = $this->_generateCode();
467 if (PEAR::isError($err)) {
468 return $err;
471 $err = $this->_cacheCode();
472 if (PEAR::isError($err)) {
473 return $err;
476 $err = $this->_loadCachedCode();
477 if (PEAR::isError($err)) {
478 return $err;
483 * Execute template with prepared context.
485 * This method execute the template file and returns the produced string.
487 * @return string
488 * @throws
490 function execute()
492 $err = $this->_prepare();
493 if (PEAR::isError($err)) {
494 $this->_ctx->_errorRaised = true;
495 return $err;
497 return $this->_cacheManager->template($this,
498 $this->_sourceFile,
499 $this->_ctx);
503 * Really load/parse/execute the template and process output filters.
505 * This method is called by cache manager to retrieve the real template
506 * execution value.
508 * IMPORTANT : The result is post-filtered here !
510 * @return string
511 * @access private
513 function _process()
515 $err = $this->_load();
516 if (PEAR::isError($err)) {
517 $this->_ctx->_errorRaised = true;
518 return $err;
521 $this->_ctx->_errorRaised = false;
522 $func = $this->_funcName;
523 if (!function_exists($func)) {
524 $err = "Template function '$func' not found (template source : $this->_sourceFile";
525 return PEAR::raiseError($err);
528 // ensure translator exists
529 if (!isset($this->_translator)) {
530 $this->_translator = new PHPTAL_I18N();
533 $res = $func($this);
534 if ($this->_headers) {
535 $res = $this->_headers . $res;
538 // activate post filters
539 $i = $this->_outputFilters->getNewIterator();
540 while ($i->isValid()) {
541 $filter =& $i->value();
542 $res = $filter->filter($this, $res, PHPTAL_POST_FILTER);
543 $i->next();
545 return $res;
548 function _translate($key)
550 return $this->_translator->translate($key);
553 function _setTranslateVar($name, $value)
555 if (is_object($value)) {
556 $value = $value->toString();
558 $this->_translator->set($name, $value);