source: branches/0.4/web/addons/job_monarch/dwoo/Dwoo/Template/String.php @ 755

Last change on this file since 755 was 755, checked in by ramonb, 11 years ago
  • add Dwoo
File size: 14.0 KB
Line 
1<?php
2
3/**
4 * represents a Dwoo template contained in a string
5 *
6 * This software is provided 'as-is', without any express or implied warranty.
7 * In no event will the authors be held liable for any damages arising from the use of this software.
8 *
9 * @author     Jordi Boggiano <j.boggiano@seld.be>
10 * @copyright  Copyright (c) 2008, Jordi Boggiano
11 * @license    http://dwoo.org/LICENSE   Modified BSD License
12 * @link       http://dwoo.org/
13 * @version    1.1.0
14 * @date       2009-07-18
15 * @package    Dwoo
16 */
17class Dwoo_Template_String implements Dwoo_ITemplate
18{
19        /**
20         * template name
21         *
22         * @var string
23         */
24        protected $name;
25
26        /**
27         * template compilation id
28         *
29         * @var string
30         */
31        protected $compileId;
32
33        /**
34         * template cache id, if not provided in the constructor, it is set to
35         * the md4 hash of the request_uri. it is however highly recommended to
36         * provide one that will fit your needs.
37         *
38         * in all cases, the compilation id is prepended to the cache id to separate
39         * templates with similar cache ids from one another
40         *
41         * @var string
42         */
43        protected $cacheId;
44
45        /**
46         * validity duration of the generated cache file (in seconds)
47         *
48         * set to -1 for infinite cache, 0 to disable and null to inherit the Dwoo instance's cache time
49         *
50         * @var int
51         */
52        protected $cacheTime;
53
54        /**
55         * boolean flag that defines whether the compilation should be enforced (once) or
56         * not use this if you have issues with the compiled templates not being updated
57         * but if you do need this it's most likely that you should file a bug report
58         *
59         * @var bool
60         */
61        protected $compilationEnforced;
62
63        /**
64         * caches the results of the file checks to save some time when the same
65         * templates is rendered several times
66         *
67         * @var array
68         */
69        protected static $cache = array('cached'=>array(), 'compiled'=>array());
70
71        /**
72         * holds the compiler that built this template
73         *
74         * @var Dwoo_ICompiler
75         */
76        protected $compiler;
77
78        /**
79         * chmod value for all files written (cached or compiled ones)
80         *
81         * set to null if you don't want any chmod operation to happen
82         *
83         * @var int
84         */
85        protected $chmod = 0777;
86
87        /**
88         * creates a template from a string
89         *
90         * @param string $templateString the template to use
91         * @param int $cacheTime duration of the cache validity for this template,
92         *                                               if null it defaults to the Dwoo instance that will
93         *                                               render this template, set to -1 for infinite cache or 0 to disable
94         * @param string $cacheId the unique cache identifier of this page or anything else that
95         *                                                makes this template's content unique, if null it defaults
96         *                                                to the current url
97         * @param string $compileId the unique compiled identifier, which is used to distinguish this
98         *                                                      template from others, if null it defaults to the md4 hash of the template
99         */
100        public function __construct($templateString, $cacheTime = null, $cacheId = null, $compileId = null)
101        {
102                $this->template = $templateString;
103                if (function_exists('hash')) {
104                        $this->name = hash('md4', $templateString);
105                } else {
106                        $this->name = md5($templateString);
107                }
108                $this->cacheTime = $cacheTime;
109
110                if ($compileId !== null) {
111                        $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;'.PATH_SEPARATOR, '/-------'));
112                }
113
114                if ($cacheId !== null) {
115                        $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------'));
116                }
117        }
118
119        /**
120         * returns the cache duration for this template
121         *
122         * defaults to null if it was not provided
123         *
124         * @return int|null
125         */
126        public function getCacheTime()
127        {
128                return $this->cacheTime;
129        }
130
131        /**
132         * sets the cache duration for this template
133         *
134         * can be used to set it after the object is created if you did not provide
135         * it in the constructor
136         *
137         * @param int $seconds duration of the cache validity for this template, if
138         * null it defaults to the Dwoo instance's cache time. 0 = disable and
139         * -1 = infinite cache
140         */
141        public function setCacheTime($seconds = null)
142        {
143                $this->cacheTime = $seconds;
144        }
145
146        /**
147         * returns the chmod value for all files written (cached or compiled ones)
148         *
149         * defaults to 0777
150         *
151         * @return int|null
152         */
153        public function getChmod()
154        {
155                return $this->chmod;
156        }
157
158        /**
159         * set the chmod value for all files written (cached or compiled ones)
160         *
161         * set to null if you don't want to do any chmod() operation
162         *
163         * @param int $mask new bitmask to use for all files
164         */
165        public function setChmod($mask = null)
166        {
167                $this->chmod = $mask;
168        }
169
170        /**
171         * returns the template name
172         *
173         * @return string
174         */
175        public function getName()
176        {
177                return $this->name;
178        }
179
180        /**
181         * returns the resource name for this template class
182         *
183         * @return string
184         */
185        public function getResourceName()
186        {
187                return 'string';
188        }
189
190        /**
191         * returns the resource identifier for this template, false here as strings don't have identifiers
192         *
193         * @return false
194         */
195        public function getResourceIdentifier()
196        {
197                return false;
198        }
199
200        /**
201         * returns the template source of this template
202         *
203         * @return string
204         */
205        public function getSource()
206        {
207                return $this->template;
208        }
209
210        /**
211         * returns an unique value identifying the current version of this template,
212         * in this case it's the md4 hash of the content
213         *
214         * @return string
215         */
216        public function getUid()
217        {
218                return $this->name;
219        }
220
221        /**
222         * returns the compiler used by this template, if it was just compiled, or null
223         *
224         * @return Dwoo_ICompiler
225         */
226        public function getCompiler()
227        {
228                return $this->compiler;
229        }
230
231        /**
232         * marks this template as compile-forced, which means it will be recompiled even if it
233         * was already saved and wasn't modified since the last compilation. do not use this in production,
234         * it's only meant to be used in development (and the development of dwoo particularly)
235         */
236        public function forceCompilation()
237        {
238                $this->compilationEnforced = true;
239        }
240
241        /**
242         * returns the cached template output file name, true if it's cache-able but not cached
243         * or false if it's not cached
244         *
245         * @param Dwoo_Core $dwoo the dwoo instance that requests it
246         * @return string|bool
247         */
248        public function getCachedTemplate(Dwoo_Core $dwoo)
249        {
250                if ($this->cacheTime !== null) {
251                        $cacheLength = $this->cacheTime;
252                } else {
253                        $cacheLength = $dwoo->getCacheTime();
254                }
255
256                // file is not cacheable
257                if ($cacheLength == 0) {
258                        return false;
259                }
260
261                $cachedFile = $this->getCacheFilename($dwoo);
262
263                if (isset(self::$cache['cached'][$this->cacheId]) === true && file_exists($cachedFile)) {
264                        // already checked, return cache file
265                        return $cachedFile;
266                } elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === -1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME'] - $cacheLength)) && $this->isValidCompiledFile($this->getCompiledFilename($dwoo))) {
267                        // cache is still valid and can be loaded
268                        self::$cache['cached'][$this->cacheId] = true;
269                        return $cachedFile;
270                } else {
271                        // file is cacheable
272                        return true;
273                }
274        }
275
276        /**
277         * caches the provided output into the cache file
278         *
279         * @param Dwoo_Core $dwoo the dwoo instance that requests it
280         * @param string $output the template output
281         * @return mixed full path of the cached file or false upon failure
282         */
283        public function cache(Dwoo_Core $dwoo, $output)
284        {
285                $cacheDir = $dwoo->getCacheDir();
286                $cachedFile = $this->getCacheFilename($dwoo);
287
288                // the code below is courtesy of Rasmus Schultz,
289                // thanks for his help on avoiding concurency issues
290                $temp = tempnam($cacheDir, 'temp');
291                if (!($file = @fopen($temp, 'wb'))) {
292                        $temp = $cacheDir . uniqid('temp');
293                        if (!($file = @fopen($temp, 'wb'))) {
294                                trigger_error('Error writing temporary file \''.$temp.'\'', E_USER_WARNING);
295                                return false;
296                        }
297                }
298
299                fwrite($file, $output);
300                fclose($file);
301
302                $this->makeDirectory(dirname($cachedFile), $cacheDir);
303                if (!@rename($temp, $cachedFile)) {
304                        @unlink($cachedFile);
305                        @rename($temp, $cachedFile);
306                }
307
308                if ($this->chmod !== null) {
309                        chmod($cachedFile, $this->chmod);
310                }
311
312                self::$cache['cached'][$this->cacheId] = true;
313
314                return $cachedFile;
315        }
316
317        /**
318         * clears the cached template if it's older than the given time
319         *
320         * @param Dwoo_Core $dwoo the dwoo instance that was used to cache that template
321         * @param int $olderThan minimum time (in seconds) required for the cache to be cleared
322         * @return bool true if the cache was not present or if it was deleted, false if it remains there
323         */
324        public function clearCache(Dwoo_Core $dwoo, $olderThan = -1)
325        {
326                $cachedFile = $this->getCacheFilename($dwoo);
327
328                return !file_exists($cachedFile) || (filectime($cachedFile) < (time() - $olderThan) && unlink($cachedFile));
329        }
330
331        /**
332         * returns the compiled template file name
333         *
334         * @param Dwoo_Core $dwoo the dwoo instance that requests it
335         * @param Dwoo_ICompiler $compiler the compiler that must be used
336         * @return string
337         */
338        public function getCompiledTemplate(Dwoo_Core $dwoo, Dwoo_ICompiler $compiler = null)
339        {
340                $compiledFile = $this->getCompiledFilename($dwoo);
341
342                if ($this->compilationEnforced !== true && isset(self::$cache['compiled'][$this->compileId]) === true) {
343                        // already checked, return compiled file
344                } elseif ($this->compilationEnforced !== true && $this->isValidCompiledFile($compiledFile)) {
345                        // template is compiled
346                        self::$cache['compiled'][$this->compileId] = true;
347                } else {
348                        // compiles the template
349                        $this->compilationEnforced = false;
350
351                        if ($compiler === null) {
352                                $compiler = $dwoo->getDefaultCompilerFactory($this->getResourceName());
353
354                                if ($compiler === null || $compiler === array('Dwoo_Compiler', 'compilerFactory')) {
355                                        if (class_exists('Dwoo_Compiler', false) === false) {
356                                                include DWOO_DIRECTORY . 'Dwoo/Compiler.php';
357                                        }
358                                        $compiler = Dwoo_Compiler::compilerFactory();
359                                } else {
360                                        $compiler = call_user_func($compiler);
361                                }
362                        }
363
364                        $this->compiler = $compiler;
365
366                        $compiler->setCustomPlugins($dwoo->getCustomPlugins());
367                        $compiler->setSecurityPolicy($dwoo->getSecurityPolicy());
368                        $this->makeDirectory(dirname($compiledFile), $dwoo->getCompileDir());
369                        file_put_contents($compiledFile, $compiler->compile($dwoo, $this));
370                        if ($this->chmod !== null) {
371                                chmod($compiledFile, $this->chmod);
372                        }
373
374                        self::$cache['compiled'][$this->compileId] = true;
375                }
376
377                return $compiledFile;
378        }
379
380        /**
381         * Checks if compiled file is valid (it exists)
382         *
383         * @param string file
384         * @return boolean True cache file existance
385         */
386        protected function isValidCompiledFile($file) {
387                return file_exists($file);
388        }
389
390        /**
391         * returns a new template string object with the resource id being the template source code
392         *
393         * @param Dwoo_Core $dwoo the dwoo instance requiring it
394         * @param mixed $resourceId the filename (relative to this template's dir) of the template to include
395         * @param int $cacheTime duration of the cache validity for this template,
396         *                                               if null it defaults to the Dwoo instance that will
397         *                                               render this template
398         * @param string $cacheId the unique cache identifier of this page or anything else that
399         *                                                makes this template's content unique, if null it defaults
400         *                                                to the current url
401         * @param string $compileId the unique compiled identifier, which is used to distinguish this
402         *                                                      template from others, if null it defaults to the filename+bits of the path
403         * @param Dwoo_ITemplate $parentTemplate the template that is requesting a new template object (through
404         *                                                                                      an include, extends or any other plugin)
405         * @return Dwoo_Template_String
406         */
407        public static function templateFactory(Dwoo_Core $dwoo, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, Dwoo_ITemplate $parentTemplate = null)
408        {
409                return new self($resourceId, $cacheTime, $cacheId, $compileId);
410        }
411
412        /**
413         * returns the full compiled file name and assigns a default value to it if
414         * required
415         *
416         * @param Dwoo_Core $dwoo the dwoo instance that requests the file name
417         * @return string the full path to the compiled file
418         */
419        protected function getCompiledFilename(Dwoo_Core $dwoo)
420        {
421                // no compile id was provided, set default
422                if ($this->compileId===null) {
423                        $this->compileId = $this->name;
424                }
425                return $dwoo->getCompileDir() . $this->compileId.'.d'.Dwoo_Core::RELEASE_TAG.'.php';
426        }
427
428        /**
429         * returns the full cached file name and assigns a default value to it if
430         * required
431         *
432         * @param Dwoo_Core $dwoo the dwoo instance that requests the file name
433         * @return string the full path to the cached file
434         */
435        protected function getCacheFilename(Dwoo_Core $dwoo)
436        {
437                // no cache id provided, use request_uri as default
438                if ($this->cacheId === null) {
439                        if (isset($_SERVER['REQUEST_URI']) === true) {
440                                $cacheId = $_SERVER['REQUEST_URI'];
441                        } elseif (isset($_SERVER['SCRIPT_FILENAME']) && isset($_SERVER['argv'])) {
442                                $cacheId = $_SERVER['SCRIPT_FILENAME'].'-'.implode('-', $_SERVER['argv']);
443                        } else {
444                                $cacheId = '';
445                        }
446                        // force compiled id generation
447                        $this->getCompiledFilename($dwoo);
448
449                        $this->cacheId = str_replace('../', '__', $this->compileId . strtr($cacheId, '\\%?=!:;'.PATH_SEPARATOR, '/-------'));
450                }
451                return $dwoo->getCacheDir() . $this->cacheId.'.html';
452        }
453
454        /**
455         * returns some php code that will check if this template has been modified or not
456         *
457         * if the function returns null, the template will be instanciated and then the Uid checked
458         *
459         * @return string
460         */
461        public function getIsModifiedCode()
462        {
463                return null;
464        }
465
466        /**
467         * ensures the given path exists
468         *
469         * @param string $path any path
470         * @param string $baseDir the base directory where the directory is created
471         *                        ($path must still contain the full path, $baseDir
472         *                        is only used for unix permissions)
473         */
474        protected function makeDirectory($path, $baseDir = null)
475        {
476                if (is_dir($path) === true) {
477                        return;
478                }
479
480                if ($this->chmod === null) {
481                        $chmod = 0777;
482                } else {
483                        $chmod = $this->chmod;
484                }
485                mkdir($path, $chmod, true);
486
487                // enforce the correct mode for all directories created
488                if (strpos(PHP_OS, 'WIN') !== 0 && $baseDir !== null) {
489                        $path = strtr(str_replace($baseDir, '', $path), '\\', '/');
490                        $folders = explode('/', trim($path, '/'));
491                        foreach ($folders as $folder) {
492                                $baseDir .= $folder . DIRECTORY_SEPARATOR;
493                                chmod($baseDir, $chmod);
494                        }
495                }
496        }
497}
Note: See TracBrowser for help on using the repository browser.