changed git call from https to git readonly
[atutor.git] / mods / phpdoc / PHPDoc / redist / IT.php
1 <?php\r
2 /**\r
3 * Integrated Template - IT\r
4\r
5 * Well there's not much to say about it. I needed a template class that\r
6 * supports a single template file with multiple (nested) blocks inside.\r
7\r
8 * Usage:\r
9 * $tpl = new IntegratedTemplate( [string filerootdir] );\r
10\r
11 * // load a template or set it with setTemplate()\r
12 * $tpl->loadTemplatefile( string filename [, boolean removeUnknownVariables, boolean removeEmptyBlocks] )\r
13 *\r
14 * // set "global" Variables meaning variables not beeing within a (inner) block\r
15 * $tpl->setVariable( string variablename, mixed value );\r
16\r
17 * // like with the Isotopp Templates there's a second way to use setVariable()\r
18 * $tpl->setVariable( array ( string varname => mixed value ) );\r
19\r
20 * // Let's use any block, even a deeply nested one\r
21 * $tpl->setCurrentBlock( string blockname );\r
22 *\r
23 * // repeat this as often as you neer. \r
24 * $tpl->setVariable( array ( string varname => mixed value ) );\r
25 * $tpl->parseCurrentBlock();\r
26 *\r
27 * // get the parsed template or print it: $tpl->show()\r
28 * $tpl->get();\r
29\r
30 * @author         Ulf Wendel <uw@netuse.de>\r
31 * @version  $Id: IT.php,v 1.4 2000/12/03 20:30:42 uw Exp $\r
32 * @access               public\r
33 * @package      PHPDoc\r
34 */\r
35 class IntegratedTemplate {\r
36 \r
37         /**\r
38         * Contains the error objects\r
39         * @var          array\r
40         * @access       public\r
41         * @see          halt(), $printError, $haltOnError\r
42         */\r
43         var $err = array();\r
44         \r
45         /**\r
46         * Print error messages?\r
47         * @var          boolean\r
48         * @access       public\r
49         * @see          halt(), $haltOnError, $err\r
50         */\r
51         var $printError = false;\r
52         \r
53         /**\r
54         * Call die() on error?\r
55         * @var          boolean\r
56         * @access       public\r
57         * @see          halt(), $printError, $err\r
58         */\r
59         var $haltOnError = false;\r
60         \r
61         /**\r
62         * Clear cache on get()? \r
63         * @var  boolean\r
64         */ \r
65         var $clearCache = false;\r
66                 \r
67         /**\r
68         * First character of a variable placeholder ( _{_VARIABLE} ).\r
69         * @var          string\r
70         * @access       public\r
71         * @see          $closingDelimiter, $blocknameRegExp, $variablenameRegExp\r
72         */\r
73         var $openingDelimiter = "{";\r
74         \r
75         /**\r
76         * Last character of a variable placeholder ( {VARIABLE_}_ ).\r
77         * @var          string\r
78         * @access       public\r
79         * @see          $openingDelimiter, $blocknameRegExp, $variablenameRegExp\r
80         */\r
81         var $closingDelimiter   = "}";\r
82         \r
83         /**\r
84         * RegExp matching a block in the template. \r
85         * Per default "sm" is used as the regexp modifier, "i" is missing.\r
86         * That means a case sensitive search is done.\r
87         * @var          string\r
88         * @access       public\r
89         * @see          $variablenameRegExp, $openingDelimiter, $closingDelimiter\r
90         */\r
91         var $blocknameRegExp    = "[0-9A-Za-z_-]+";\r
92         \r
93         /**\r
94         * RegExp matching a variable placeholder in the template.\r
95         * Per default "sm" is used as the regexp modifier, "i" is missing.\r
96         * That means a case sensitive search is done.\r
97         * @var          string  \r
98         * @access       public\r
99         * @see          $blocknameRegExp, $openingDelimiter, $closingDelimiter\r
100         */\r
101         var $variablenameRegExp = "[0-9A-Za-z_-]+";\r
102         \r
103         /**\r
104         * Full RegExp used to find variable placeholder, filled by the constructor.\r
105         * @var  string  Looks somewhat like @(delimiter varname delimiter)@\r
106         * @see  IntegratedTemplate()\r
107         */\r
108         var $variablesRegExp = "";\r
109         \r
110         /**\r
111         * Full RegExp used to find blocks an their content, filled by the constructor.\r
112         * @var  string\r
113         * @see  IntegratedTemplate()\r
114         */\r
115         var $blockRegExp = "";\r
116         \r
117         /**\r
118         * Name of the current block.\r
119         * @var          string\r
120         */\r
121         var $currentBlock = "__global__";\r
122 \r
123         /**\r
124         * Content of the template.\r
125         * @var          string\r
126         */      \r
127         var $template = "";\r
128         \r
129         /**\r
130         * Array of all blocks and their content.\r
131         * \r
132         * @var  array\r
133         * @see  findBlocks()\r
134         */      \r
135         var $blocklist                  = array();\r
136   \r
137   /**\r
138   * Array with the parsed content of a block.\r
139   *\r
140   * @var  array\r
141   */\r
142   var $blockdata      = array();\r
143         \r
144         /**\r
145         * Array of variables in a block.\r
146         * @var  array\r
147         */\r
148         var $blockvariables = array();\r
149 \r
150         /**\r
151         * Array of inner blocks of a block.\r
152         * @var  array\r
153         */      \r
154         var $blockinner                 = array();\r
155         \r
156   /**\r
157   * Future versions will use this...\r
158   * @var  array\r
159   */\r
160   var $blocktypes = array();\r
161   \r
162         /**\r
163         * Variable cache.\r
164         *\r
165         * Variables get cached before any replacement is done.\r
166         * Advantage: empty blocks can be removed automatically.\r
167         * Disadvantage: might take some more memory\r
168         * \r
169         * @var  array\r
170         * @see  setVariable(), $clearCacheOnParse\r
171         */\r
172         var $variableCache = array();\r
173         \r
174         /**\r
175         * @var  boolean\r
176         */\r
177         var $clearCacheOnParse = true;\r
178         \r
179         /**\r
180         * Controls the handling of unknown variables, default is remove.\r
181         * @var  boolean\r
182         */\r
183         var $removeUnknownVariables = true;\r
184         \r
185         /**\r
186         * Controls the handling of empty blocks, default is remove.\r
187         * @var  boolean\r
188         */\r
189         var $removeEmptyBlocks = true;\r
190         \r
191         /**\r
192         * Root directory for all file operations. \r
193         * The string gets prefixed to all filenames given.\r
194         * @var  string\r
195         * @see  IntegratedTemplate(), setRoot()\r
196         */\r
197         var $fileRoot = "";\r
198         \r
199         /**\r
200         * Internal flag indicating that a blockname was used multiple times.\r
201         * @var  boolean\r
202         */\r
203         var $flagBlocktrouble = false;\r
204         \r
205         /**\r
206         * Flag indicating that the global block was parsed.\r
207         * @var  boolean\r
208         */\r
209         var $flagGlobalParsed = false;\r
210         \r
211         /**\r
212         * Builds some complex regular expressions and optinally sets the file root directory.\r
213         *\r
214         * Make sure that you call this constructor if you derive your template \r
215         * class from this one. \r
216         *\r
217         * @param        string  File root directory, prefix for all filenames given to the object.\r
218         * @see  setRoot()\r
219         */\r
220         function IntegratedTemplate($root = "") {\r
221         \r
222                 $this->variablesRegExp = "@".$this->openingDelimiter."(".$this->variablenameRegExp.")".$this->closingDelimiter."@sm";\r
223                 $this->blockRegExp = '@!--\s+BEGIN\s+('.$this->blocknameRegExp.')\s+-->(.*)<!--\s+END\s+\1\s+-->@sm';\r
224 \r
225                 $this->setRoot($root);          \r
226                 \r
227         } // end constructor\r
228         \r
229         /**\r
230         * Print a certain block with all replacements done.\r
231         * @brother get()\r
232         */\r
233         function show($block = "__global__") {\r
234                 print $this->get($block);\r
235         } // end func show\r
236         \r
237         /**\r
238         * Returns a block with all replacements done.\r
239         * \r
240         * @param        string  name of the block\r
241         * @return       string          \r
242         * @access       public\r
243         * @see  show()\r
244         */\r
245         function get($block = "__global__") {\r
246 \r
247                 if ("__global__" == $block && !$this->flagGlobalParsed)\r
248                         $this->parse("__global__");\r
249                         \r
250                 if (!isset($this->blocklist[$block])) {\r
251                         $this->halt("The block '$block' was not found in the template.", __FILE__, __LINE__);\r
252                         return true;\r
253                 }\r
254                 \r
255     if ($this->clearCache) {\r
256     \r
257       $data = (isset($this->blockdata[$block])) ? $this->blockdata[$block] : "";\r
258       unset($this->blockdata[$block]);\r
259       return $data;\r
260        \r
261     } else {\r
262     \r
263       return (isset($this->blockdata[$block])) ? $this->blockdata[$block] : "";\r
264       \r
265     }\r
266 \r
267         } // end func get()\r
268                 \r
269         /**\r
270         * Parses the given block.\r
271         *       \r
272         * @param        string  name of the block to be parsed\r
273         * @access       public\r
274         * @see          parseCurrentBlock()\r
275         */\r
276         function parse($block = "__global__", $flag_recursion = false) {\r
277 \r
278                 if (!isset($this->blocklist[$block])) {\r
279                         $this->halt("The block '$block' was not found in the template.", __FILE__, __LINE__);\r
280                         return false;\r
281                 }\r
282 \r
283                 if ("__global__" == $block)\r
284                         $this->flagGlobalParsed = true;\r
285                         \r
286     $regs = array();\r
287     $values = array();\r
288 \r
289                 if ($this->clearCacheOnParse) {\r
290                         \r
291                         reset($this->variableCache);\r
292                         while (list($name, $value)=each($this->variableCache)) {\r
293                                 $regs[] = "@".$this->openingDelimiter.$name.$this->closingDelimiter."@";\r
294                                 $values[] = $value;\r
295                         }\r
296                         $this->variableCache = array();\r
297                 \r
298                 } else {\r
299                 \r
300                         reset($this->blockvariables[$block]);\r
301                         while (list($k, $allowedvar)=each($this->blockvariables[$block])) {\r
302                 \r
303                                 if (isset($this->variableCache[$allowedvar])) {\r
304                   $regs[]   = "@".$this->openingDelimiter.$allowedvar.$this->closingDelimiter."@";\r
305                     $values[] = $this->variableCache[$allowedvar];\r
306                                         unset($this->variableCache[$allowedvar]);\r
307                                 }\r
308 \r
309                         }               \r
310                         \r
311                 }\r
312 \r
313                 $outer = (0 == count($regs)) ? $this->blocklist[$block] : preg_replace($regs, $values, $this->blocklist[$block]);\r
314                 $empty = (0 == count($values)) ? true : false;\r
315 \r
316     if (isset($this->blockinner[$block])) {\r
317                 \r
318       reset($this->blockinner[$block]);\r
319       while (list($k, $innerblock)=each($this->blockinner[$block])) {\r
320 \r
321         $this->parse($innerblock, true);\r
322                                 if (""!=$this->blockdata[$innerblock])\r
323                                         $empty = false;\r
324 \r
325                                 $placeholder = $this->openingDelimiter."__".$innerblock."__".$this->closingDelimiter;                           \r
326         $outer = str_replace($placeholder, $this->blockdata[$innerblock], $outer);\r
327                                 $this->blockdata[$innerblock] = "";                             \r
328       }\r
329     }\r
330 \r
331     if ($this->removeUnknownVariables)\r
332                         $outer = preg_replace($this->variablesRegExp, "", $outer);\r
333                 \r
334                 if ($empty) {\r
335                 \r
336                         if (!$this->removeEmptyBlocks) \r
337                                 $this->blockdata[$block].= $outer;\r
338                                 \r
339                 } else {\r
340                 \r
341                         $this->blockdata[$block].= $outer;\r
342                 \r
343                 }\r
344 \r
345     return $empty;\r
346         } // end func parse\r
347 \r
348         /**\r
349         * Parses the current block\r
350         * @see  parse(), setCurrentBlock(), $currentBlock\r
351         *       @access public\r
352         */\r
353         function parseCurrentBlock() {\r
354                 return $this->parse($this->currentBlock);\r
355         } // end func parseCurrentBlock\r
356 \r
357         /**\r
358         * Sets a variable value.\r
359         * \r
360         * The function can be used eighter like setVariable( "varname", "value")\r
361         * or with one array $variables["varname"] = "value" given setVariable($variables)\r
362         * quite like phplib templates set_var().\r
363         * \r
364         * @param        mixed           string with the variable name or an array %variables["varname"] = "value"\r
365         * @param        string  value of the variable or empty if $variable is an array.\r
366         * @param        string  prefix for variable names\r
367         * @access       public\r
368         */      \r
369         function setVariable($variable, $value="") {\r
370                 \r
371                 if (is_array($variable)) {\r
372                 \r
373                         reset($variable);\r
374                         while (list($var, $value)=each($variable)) \r
375                                 $this->variableCache[$var]      = $value;\r
376                                 \r
377                 } else {\r
378                         \r
379                         $this->variableCache[$variable]         = $value;\r
380                         \r
381                 }\r
382         \r
383         } // end func setVariable\r
384         \r
385         /**\r
386         * Sets the name of the current block that is the block where variables are added.\r
387         *\r
388         * @param        string  name of the block \r
389         * @return       boolean false on failure otherwise true\r
390         *       @access public\r
391         */\r
392         function setCurrentBlock($block = "__global__") {\r
393         \r
394                 if (!isset($this->blocklist[$block])) {\r
395                         $this->halt("Can't find the block '$block' in the template.", __FILE__, __LINE__);\r
396                         return false;\r
397                 }\r
398                         \r
399                 $this->currentBlock = $block;\r
400                 \r
401                 return true;\r
402         } // end func setCurrentBlock\r
403         \r
404         /**\r
405         * Clears all datafields of the object and rebuild the internal blocklist\r
406         * \r
407         * LoadTemplatefile() and setTemplate() automatically call this function \r
408         * when a new template is given. Don't use this function \r
409         * unless you know what you're doing.\r
410         *\r
411         * @access       public\r
412         * @see  free()\r
413         */\r
414         function init() {\r
415         \r
416                 $this->free();\r
417                 $this->findBlocks($this->template);\r
418                 $this->buildBlockvariablelist();\r
419                 \r
420         } // end func init\r
421         \r
422         /**\r
423         * Clears all datafields of the object.\r
424         * \r
425         * Don't use this function unless you know what you're doing.\r
426         *\r
427         * @access       public\r
428         * @see  init()\r
429         */\r
430         function free() {\r
431         \r
432                 $this->err[] = "";\r
433                 \r
434                 $this->currentBlock = "__global__";\r
435                 \r
436                 $this->variableCache    = array();              \r
437                 $this->blocklist                        = array();\r
438                 $this->blockvariables   = array();\r
439                 $this->blockinner                       = array();\r
440                 $this->blockdata                        = array();\r
441                 $this->blocklookup              = array();\r
442     $this->blocktypes     = array();\r
443                 \r
444                 $this->flagBlocktrouble = false;\r
445                 $this->flagGlobalParsed = false;\r
446                 \r
447         } // end func free\r
448         \r
449         /**\r
450         * Sets the template.\r
451         *  \r
452         * You can eighter load a template file from disk with LoadTemplatefile() or set the\r
453         * template manually using this function.\r
454         * \r
455         * @param                string  template content\r
456         * @param                boolean Unbekannte, nicht ersetzte Platzhalter entfernen?\r
457         * @param                boolean remove unknown/unused variables?\r
458         * @param                boolean remove empty blocks?\r
459         * @see                  LoadTemplatefile(), $template\r
460         * @access               public\r
461         */\r
462         function setTemplate($template, $removeUnknownVariables = true, $removeEmptyBlocks = false) {\r
463                 if (""==$template) {\r
464                         $this->halt("The given string is empty.", __FILE__, __LINE__);\r
465                         return false;\r
466                 }\r
467                 \r
468                 $this->removeUnknownVariables = $removeUnknownVariables;\r
469                 $this->removeEmptyBlocks = $removeEmptyBlocks;\r
470                 \r
471                 $this->template = '<!-- BEGIN __global__ -->'.$template.'<!-- END __global__ -->';\r
472                 $this->init();\r
473                 \r
474                 if ($this->flagBlocktrouble)\r
475                         return false;\r
476                 \r
477                 return true;\r
478         } // end func setTemplate\r
479         \r
480         /**\r
481         * Reads a template file from the disk.\r
482         *\r
483         * @param                string  name of the template file, full path!\r
484         * @param                boolean remove unknown/unused variables?\r
485         * @param                boolean remove empty blocks?\r
486         * @access               public\r
487         * @return               boolean false on failure, otherwise true\r
488         * @see                  $template, setTemplate()\r
489         */\r
490         function loadTemplatefile($filename, $removeUnknownVariables = true, $removeEmptyBlocks = true) {\r
491         \r
492                 $template = $this->getfile($filename);\r
493                 \r
494                 return $this->setTemplate($this->getFile($filename), $removeUnknownVariables, $removeEmptyBlocks);\r
495         } // end func LoadTemplatefile\r
496         \r
497         /**\r
498         * Sets the file root. The file root gets prefixed to all filenames passed to the object.\r
499         * \r
500         * Make sure that you override this function when using the class\r
501         * on windows.\r
502         * \r
503         * @param        string\r
504         * @see          IntegratedTemplate()\r
505         * @access       public\r
506         */\r
507         function setRoot($root) {\r
508                 \r
509                 if (""!=$root && "/"!= substr($root, -1))\r
510                         $root.="/";\r
511                 \r
512                 $this->fileRoot = $root;\r
513                 \r
514         } // end func setRoot\r
515 \r
516         /**\r
517         * Build a list of all variables within a block\r
518         */      \r
519         function buildBlockvariablelist() {\r
520 \r
521                 reset($this->blocklist);\r
522                 while (list($name, $content)=each($this->blocklist)) {\r
523                         preg_match_all( $this->variablesRegExp, $content, $regs );\r
524                         $this->blockvariables[$name] = $regs[1];\r
525                 }       \r
526                 \r
527         } // end func buildBlockvariablelist\r
528         \r
529         /**\r
530         * Returns a list of all \r
531         */\r
532         function getGlobalvariables() {\r
533 \r
534     $regs   = array();\r
535     $values = array();\r
536     \r
537                 reset($this->blockvariables["__global__"]);\r
538                 while (list($k, $allowedvar)=each($this->blockvariables["__global__"])) {\r
539                         \r
540                         if (isset($this->variableCache[$allowedvar])) {\r
541                                 $regs[]   = "@".$this->openingDelimiter.$allowedvar.$this->closingDelimiter."@";\r
542                                 $values[] = $this->variableCache[$allowedvar];\r
543                                 unset($this->variableCache[$allowedvar]);\r
544                         }\r
545                         \r
546                 }\r
547                 \r
548     return array($regs, $values);\r
549         } // end func getGlobalvariables\r
550 \r
551         /**\r
552         * Recusively builds a list of all blocks within the template.\r
553         *\r
554         * @param        string  string that gets scanned\r
555         * @access       private\r
556         * @see  $blocklist\r
557         */      \r
558         function findBlocks($string) {\r
559 \r
560                 $blocklist = array();\r
561 \r
562                 if (preg_match_all($this->blockRegExp, $string, $regs, PREG_SET_ORDER)) {\r
563                         \r
564                         reset($regs);\r
565                         while (list($k, $match)=each($regs)) {\r
566                         \r
567                                 $blockname              = $match[1];\r
568                                 $blockcontent = $match[2];\r
569                         \r
570                                 if (isset($this->blocklist[$blockname])) {\r
571                                         $this->halt("The name of a block must be unique within a template. Found '$blockname' twice. Unpredictable results may appear.", __FILE__, __LINE__);\r
572                                         $this->flagBlocktrouble = true;\r
573                                 }                               \r
574 \r
575                                 $this->blocklist[$blockname] = $blockcontent;\r
576                                 $this->blockdata[$blockname] = "";\r
577 \r
578                                 $blocklist[] = $blockname;\r
579                                 \r
580                                 $inner = $this->findBlocks($blockcontent);\r
581                                 reset($inner);\r
582                                 while (list($k, $name)=each($inner)) {\r
583 \r
584                                         $pattern = sprintf('@<!--\s+BEGIN\s+%s\s+-->(.*)<!--\s+END\s+%s\s+-->@sm', \r
585                                                                                                         $name,\r
586                                                                                                         $name\r
587                                                                                                 );\r
588 \r
589                                         $this->blocklist[$blockname] = preg_replace(    $pattern, \r
590                                                                                                                                                                                                                                 $this->openingDelimiter."__".$name."__".$this->closingDelimiter, \r
591                                                                                                                                                                                                                                 $this->blocklist[$blockname]\r
592                                                                                                                                                                                                                         );\r
593                                         $this->blockinner[$blockname][] = $name;\r
594                                         $this->blockparents[$name] = $blockname;\r
595                                         \r
596                                 }\r
597                                 \r
598                         }\r
599                         \r
600                 }\r
601 \r
602                 return $blocklist;\r
603         } // end func findBlocks\r
604 \r
605         /**\r
606         * Reads a file from disk and returns its content.\r
607         * @param        string  Filename\r
608         * @return       string  Filecontent\r
609         */      \r
610         function getFile($filename) {\r
611                 \r
612                 if ("/" == substr($filename, 0, 1)) \r
613                         $filename = substr($filename, 1);\r
614                         \r
615                 $filename = $this->fileRoot.$filename;\r
616                 \r
617                 if ( !($fh = @fopen($filename, "r")) ) {\r
618                         $this->halt("Can't read '$filename'.", __FILE__, __LINE__);\r
619                         return "";\r
620                 }\r
621         \r
622                 $content = fread($fh, filesize($filename));\r
623                 fclose($fh);\r
624                 \r
625                 return $content; \r
626         } // end func getFile\r
627         \r
628         /**\r
629         * Error Handling function.\r
630         * @param        string  error message\r
631         * @param        mixed           File where the error occured\r
632         * @param        int                     Line where the error occured\r
633         * @see          $err\r
634         */\r
635         function halt($message, $file="", $line=0) {\r
636                 \r
637                 $message = sprintf("IntegratedTemplate Error: %s [File: %s, Line: %d]",\r
638                                                                                                                         $message,\r
639                                                                                                                         $file,\r
640                                                                                                                         $line\r
641                                                                                                         );\r
642 \r
643                 $this->err[] = $message;\r
644                                                                                                                                 \r
645                 if ($this->printError)\r
646                         print $message;\r
647                         \r
648                 if ($this->haltOnError)\r
649                         die($message);                                                                                                                  \r
650 \r
651         } // end func halt\r
652         \r
653 } // end class IntegratedTemplate\r
654 ?>