summaryrefslogtreecommitdiff
path: root/buildscripts/phing/classes/phing/lib/Capsule.php
blob: bab05486a3d589c65a200d0b95fbb6b53d207d79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
<?php

/**
 * Capsule is a simple "template" engine that essentially provides an isolated context
 * for PHP scripts.
 * 
 * There is no special templating language, and therefore no limitations to what
 * can be accomplished within templates. The main purpose of Capsule is to separate 
 * the business logic from display / output logic.
 * 
 * @author Hans Lellelid <hans@xmpl.org>
 * @version $Revision: 1.9 $ $Date: 2004/08/31 20:12:02 $
 */
class Capsule {
    
    /**
     * Look for templates here (if relative path provided).
     * @var string
     */
    protected $templatePath;
    
    /**
     * Where should output files be written?
     * (This is named inconsistently to be compatible w/ Texen.)
     * @var string
     */
    protected $outputDirectory;
    
    /**
     * The variables that can be used by the templates.
     * @var array Hash of variables.
     */
    public $vars = array();
    
    /**
     * Has template been initialized.
     */    
    protected $initialized = false;
    
    /**
     * Stores the pre-parse() include_path.
     * @var string
     */
    private $old_include_path;
    
    function __construct() {
    }
    
    /**
     * Clears one or several or all variables.
     * @param mixed $which String name of var, or array of names.
     * @return void
     */
    function clear($which = null) {
        if ($which === null) {
            $this->vars = array();
        } elseif (is_array($which)) {
            foreach($which as $var) {
                unset($this->vars[$var]);
            }
        } else {
            unset($this->vars[$which]);
        }
    }
    
    /**
     * Set the basepath to use for template lookups.
     * @param string $v
     */
    function setTemplatePath($v) {
        $this->templatePath = rtrim($v, DIRECTORY_SEPARATOR.'/');
    }

    /**
     * Get the basepath to use for template lookups.
     * @return string
     */
    function getTemplatePath() {
        return $this->templatePath;
    }
    
    /**
     * Set a basepath to use for output file creation.
     * @param string $v
     */
    function setOutputDirectory($v) {
        $this->outputDirectory = rtrim($v, DIRECTORY_SEPARATOR.'/');
    }

    /**
     * Get basepath to use for output file creation.
     * @return string
     */
    function getOutputDirectory() {
        return $this->outputDirectory;
    }
    
    /**
     * Low overhead (no output buffering) method to simply dump template
     * to buffer.
     * 
     * @param string $__template
     * @return void
     * @throws Exception - if template cannot be found
     */ 
    function display($__template) {
        
        // Prepend "private" variable names with $__ in this function
        // to keep namespace conflict potential to a minimum.
            
        // Alias this class to $generator.
        $generator = $this;
                        
        if (isset($this->vars['this'])) {
            throw new Exception("Assigning a variable named \$this to a context conflicts with class namespace.");
        }
        
        // extract variables into local namespace
        extract($this->vars);
        
        // prepend template path to include path, 
        // so that include "path/relative/to/templates"; can be used within templates
        $__old_inc_path = ini_get('include_path');
        ini_set('include_path', $this->templatePath . PATH_SEPARATOR . $__old_inc_path);
                
        @ini_set('track_errors', true);
        include $__template;
        @ini_restore('track_errors');
        
        // restore the include path
        ini_set('include_path', $__old_inc_path);
        
        if (!empty($php_errormsg)) {
            throw new Exception("Unable to parse template " . $__template . ": " . $php_errormsg);
        }
    }
    
    /**
     * Fetches the results of a tempalte parse and either returns
     * the string or writes results to a specified output file.
     *
     * @param string $template The template filename (relative to templatePath or absolute).
     * @param string $outputFile If specified, contents of template will also be written to this file.
     * @param boolean $append Should output be appended to source file?
     * @return string The "parsed" template output.
     * @throws Exception - if template not found.
     */
    function parse($template, $outputFile = null, $append = false) {
                
        // main work done right here:
        // hopefully this works recursively ... fingers crossed.    
        ob_start();
        
        try {
            $this->display($template);
        } catch (Exception $e) {
            ob_end_flush(); // flush the output on error (so we can see up to what point it parsed everything)
            throw $e;
        }
                
        $output = ob_get_contents();
        ob_end_clean();
        
        if ($outputFile !== null) {
            $outputFile = $this->resolvePath($outputFile, $this->outputDirectory);
            
            $flags = null;
            if ($append) $flags = FILE_APPEND;
            
            if (!file_put_contents($outputFile, $output, $flags) && $output != "") {
                throw new Exception("Unable to write output to " . $outputFile);
            }
        }

        return $output;
    }
    
    /**
     * This returns a "best guess" path for the given file.
     *
     * @param string $file File name or possibly absolute path.
     * @param string $basepath The basepath that should be prepended if $file is not absolute.
     * @return string "Best guess" path for this file.
     */
    protected function resolvePath($file, $basepath) {
        if ( !($file{0} == DIRECTORY_SEPARATOR || $file{0} == '/') 
            // also account for C:\ style path
                && !($file{1} == ':' && ($file{2} ==  DIRECTORY_SEPARATOR || $file{2} == '/'))) { 
            if ($basepath != null) {
                $file = $basepath . DIRECTORY_SEPARATOR . $file;
            }
        }
        return $file;
    }

    /**
     * Gets value of specified var or NULL if var has not been put().
     * @param string $name Variable name to retrieve.
     * @return mixed
     */
    function get($name) {
        if (!isset($this->vars[$name])) return null;
        return $this->vars[$name];
    }
    
    /**
     * Merges in passed hash to vars array.
     *
     * Given an array like:
     *
     *            array(     'myvar' => 'Hello',
     *                    'myvar2' => 'Hello')
     *
     * Resulting template will have access to $myvar and $myvar2.
     *
     * @param array $vars
     * @param boolean $recursiveMerge Should matching keys be recursively merged?
     * @return void
     */
    function putAll($vars, $recursiveMerge = false) {
        if ($recursiveMerge) {
            $this->vars = array_merge_recursive($this->vars, $vars);
        } else {
            $this->vars = array_merge($this->vars, $vars);
        }
    }
    
    /**
     * Adds a variable to the context.
     * 
     * Resulting template will have access to ${$name$} variable.
     * 
     * @param string $name
     * @param mixed $value
     */
    function put($name, $value) {
        $this->vars[$name] = $value;
    }
        
    /**
     * Put a variable into the context, assigning it by reference.
     * This means that if the template modifies the variable, then it
     * will also be modified in the context.
     *
     * @param $name
     * @param &$value
     */
    function putRef($name, &$value) {
        $this->vars[$name] = &$value;
    }
    
    /**
     * Makes a copy of the value and puts it into the context.
     * This is primarily to force copying (cloning) of objects, rather
     * than the default behavior which is to assign them by reference.
     * @param string $name
     * @param mixed $value
     */
    function putCopy($name, $value) {
        if (is_object($value)) {
            $value = clone $value;
        }
        $this->vars[$name] = $value;
    }

}