]> CyberLeo.Net >> Repos - SourceForge/phpwiki.git/blob - lib/Template.php
No tabs
[SourceForge/phpwiki.git] / lib / Template.php
1 <?php //-*-php-*-
2 // $Id$
3
4 require_once("lib/ErrorManager.php");
5
6
7 /** An HTML template.
8  */
9 class Template
10 {
11     /**
12      * name optionally of form "theme/template" to include parent templates in children
13      */
14     function Template ($name, &$request, $args = false) {
15         global $WikiTheme;
16
17         $this->_request =& $request;
18         $this->_basepage = $request->getArg('pagename');
19
20         if (strstr($name, "/")) {
21             $oldname = $WikiTheme->_name;
22             $oldtheme = $WikiTheme->_theme;
23             list($themename, $name) = explode("/", $name);
24             $WikiTheme->_theme = "themes/$themename";
25             $WikiTheme->_name = $name;
26         }
27         $this->_name = $name;
28         $file = $WikiTheme->findTemplate($name);
29         if (!$file) {
30             trigger_error("no template for $name found.", E_USER_WARNING);
31             return;
32         }
33         if (isset($oldname)) {
34             $WikiTheme->_name = $oldname;
35             $WikiTheme->_theme = $oldtheme;
36         }
37         $fp = fopen($file, "rb");
38         if (!$fp) {
39             trigger_error("$file not found", E_USER_WARNING);
40             return;
41         }
42         $request->_TemplatesProcessed[$name] = 1;
43         $this->_tmpl = fread($fp, filesize($file));
44         if ($fp) fclose($fp);
45         //$userid = $request->_user->_userid;
46         if (is_array($args))
47             $this->_locals = $args;
48         elseif ($args)
49             $this->_locals = array('CONTENT' => $args);
50         else
51             $this->_locals = array();
52     }
53
54     function _munge_input($template) {
55
56         // Convert < ?plugin expr ? > to < ?php $this->_printPluginPI("expr"); ? >
57         $orig[] = '/<\?plugin.*?\?>/se';
58         $repl[] = "\$this->_mungePlugin('\\0')";
59
60         // Convert < ?= expr ? > to < ?php $this->_print(expr); ? >
61         $orig[] = '/<\?=(.*?)\?>/s';
62         $repl[] = '<?php $this->_print(\1);?>';
63
64         // Convert < ?php echo expr ? > to < ?php $this->_print(expr); ? >
65         $orig[] = '/<\?php echo (.*?)\?>/s';
66         $repl[] = '<?php $this->_print(\1);?>';
67
68         return preg_replace($orig, $repl, $template);
69     }
70
71     function _mungePlugin($pi) {
72         // HACK ALERT: PHP's preg_replace, with the /e option seems to
73         // escape both single and double quotes with backslashes.
74         // So we need to unescape the double quotes here...
75
76         $pi = preg_replace('/(?!<\\\\)\\\\"/x', '"', $pi);
77         return sprintf('<?php $this->_printPlugin(%s); ?>',
78                        "'" . str_replace("'", "\'", $pi) . "'");
79     }
80
81     function _printPlugin ($pi) {
82     include_once("lib/WikiPlugin.php");
83     static $loader;
84
85         if (empty($loader))
86             $loader = new WikiPluginLoader;
87
88         $this->_print($loader->expandPI($pi, $this->_request, $this, $this->_basepage));
89     }
90
91     function _print ($val) {
92         if (isa($val, 'Template')) {
93             $this->_expandSubtemplate($val);
94         } else {
95             PrintXML($val);
96         }
97     }
98
99     function _expandSubtemplate (&$template) {
100         // FIXME: big hack!
101         //if (!$template->_request)
102         //    $template->_request = &$this->_request;
103         if (DEBUG) {
104             echo "<!-- Begin $template->_name -->\n";
105         }
106         // Expand sub-template with defaults from this template.
107         $template->printExpansion($this->_vars);
108         if (DEBUG) {
109             echo "<!-- End $template->_name -->\n";
110         }
111     }
112
113     /**
114      * Substitute HTML replacement text for tokens in template.
115      *
116      * Constructs a new WikiTemplate based upon the named template.
117      *
118      * @access public
119      *
120      * @param $token string Name of token to substitute for.
121      *
122      * @param $replacement string Replacement HTML text.
123      */
124     function replace($varname, $value) {
125         $this->_locals[$varname] = $value;
126     }
127
128
129     function printExpansion ($defaults = false) {
130         if (!is_array($defaults)) // HTML object or template object
131             $defaults = array('CONTENT' => $defaults);
132         $this->_vars = array_merge($defaults, $this->_locals);
133         extract($this->_vars);
134
135         global $request;
136         if (!isset($user))
137             $user = $request->getUser();
138         if (!isset($page))
139             $page = $request->getPage();
140     // Speedup. I checked all templates
141         if (!isset($revision))
142         $revision = false;
143
144         global $WikiTheme, $charset;
145         //$this->_dump_template();
146         $SEP = $WikiTheme->getButtonSeparator();
147
148         global $ErrorManager;
149         $ErrorManager->pushErrorHandler(new WikiMethodCb($this, '_errorHandler'));
150
151         eval('?>' . $this->_munge_input($this->_tmpl));
152
153         $ErrorManager->popErrorHandler();
154     }
155
156     // FIXME (1.3.12)
157     // Find a way to do template expansion less memory intensive and faster.
158     // 1.3.4 needed no memory at all for dumphtml, now it needs +15MB.
159     // Smarty? As before?
160     function getExpansion ($defaults = false) {
161         ob_start();
162         $this->printExpansion($defaults);
163         $xml = ob_get_contents();
164         ob_end_clean();     // PHP problem: Doesn't release its memory?
165         return $xml;
166     }
167
168     function printXML () {
169         $this->printExpansion();
170     }
171
172     function asXML () {
173         return $this->getExpansion();
174     }
175
176
177     // Debugging:
178     function _dump_template () {
179         $lines = explode("\n", $this->_munge_input($this->_tmpl));
180         $pre = HTML::pre();
181         $n = 1;
182         foreach ($lines as $line)
183             $pre->pushContent(fmt("%4d  %s\n", $n++, $line));
184         $pre->printXML();
185     }
186
187     function _errorHandler($error) {
188         //if (!preg_match('/: eval\(\)\'d code$/', $error->errfile))
189     //    return false;
190
191         if (preg_match('/: eval\(\)\'d code$/', $error->errfile)) {
192             $error->errfile = "In template '$this->_name'";
193             // Hack alert: Ignore 'undefined variable' messages for variables
194             //  whose names are ALL_CAPS.
195             if (preg_match('/Undefined variable:\s*[_A-Z]+\s*$/', $error->errstr))
196                 return true;
197         }
198         // ignore recursively nested htmldump loop: browse -> body -> htmldump -> browse -> body ...
199         // FIXME for other possible loops also
200         elseif (strstr($error->errfile, "In template 'htmldump'")) {
201             ; //return $error;
202         }
203         elseif (strstr($error->errfile, "In template '")) { // merge
204             $error->errfile = preg_replace("/'(\w+)'\)$/", "'\\1' < '$this->_name')",
205                                            $error->errfile);
206         }
207         else {
208             $error->errfile .= " (In template '$this->_name')";
209         }
210
211         if (!empty($this->_tmpl)) {
212             $lines = explode("\n", $this->_tmpl);
213             if (isset($lines[$error->errline - 1]))
214                 $error->errstr .= ":\n\t" . $lines[$error->errline - 1];
215         }
216     return $error;
217     }
218 };
219
220 /**
221  * Get a templates
222  *
223  * This is a convenience function and is equivalent to:
224  * <pre>
225  *   new Template(...)
226  * </pre>
227  */
228 function Template($name, $args = false) {
229     global $request;
230     return new Template($name, $request, $args);
231 }
232
233 function alreadyTemplateProcessed($name) {
234     global $request;
235     return !empty($request->_TemplatesProcessed[$name]) ? true : false;
236 }
237 /**
238  * Make and expand the top-level template.
239  *
240  *
241  * @param $content mixed html content to put into the page
242  * @param $title string page title
243  * @param $page_revision object A WikiDB_PageRevision object or false
244  * @param $args hash Extract args for top-level template
245  *
246  * @return string HTML expansion of template.
247  */
248 function GeneratePage($content, $title, $page_revision = false, $args = false) {
249     global $request;
250
251     if (!is_array($args))
252         $args = array();
253
254     $args['CONTENT'] = $content;
255     $args['TITLE'] = $title;
256     $args['revision'] = $page_revision;
257
258     if (!isset($args['HEADER']))
259         $args['HEADER'] = $title;
260
261     printXML(new Template('html', $request, $args));
262 }
263
264
265 /**
266  * For dumping pages as html to a file.
267  * Used for action=dumphtml,action=ziphtml,format=pdf,format=xml
268  */
269 function GeneratePageasXML($content, $title, $page_revision = false, $args = false) {
270     global $request;
271
272     if (!is_array($args))
273         $args = array();
274
275     $content->_basepage = $title;
276     $args['CONTENT'] = $content;
277     $args['TITLE'] = SplitPagename($title);
278     $args['revision'] = $page_revision;
279
280     if (!isset($args['HEADER']))
281         $args['HEADER'] = SplitPagename($title);
282
283     global $HIDE_TOOLBARS, $NO_BASEHREF, $WikiTheme;
284     $HIDE_TOOLBARS = true;
285     if (!$WikiTheme->DUMP_MODE)
286     $WikiTheme->DUMP_MODE = 'HTML';
287
288     // FIXME: unfatal errors and login requirements
289     $html = asXML(new Template('htmldump', $request, $args));
290
291     $HIDE_TOOLBARS = false;
292     //$WikiTheme->DUMP_MODE = false;
293     return $html;
294 }
295
296 // Local Variables:
297 // mode: php
298 // tab-width: 8
299 // c-basic-offset: 4
300 // c-hanging-comment-ender-p: nil
301 // indent-tabs-mode: nil
302 // End:
303 ?>