]> git.mxchange.org Git - friendica.git/blob - include/template_processor.php
added spaces + some curly braces + some usage of dbm::is_result()
[friendica.git] / include / template_processor.php
1 <?php
2 /*
3  * This is the old template engine, now deprecated.
4  * Friendica's default template engine is Smarty3 (see include/friendica_smarty.php)
5  * 
6  */
7 require_once 'object/TemplateEngine.php';
8
9 define("KEY_NOT_EXISTS", '^R_key_not_Exists^');
10
11 class Template implements ITemplateEngine {
12         static $name ="internal";
13         
14         var $r;
15         var $search;
16         var $replace;
17         var $stack = array();
18         var $nodes = array();
19         var $done = false;
20         var $d = false;
21         var $lang = null;
22         var $debug = false;
23
24         private function _preg_error() {
25
26                 switch (preg_last_error()) {
27                         case PREG_INTERNAL_ERROR: echo('PREG_INTERNAL_ERROR');
28                                 break;
29                         case PREG_BACKTRACK_LIMIT_ERROR: echo('PREG_BACKTRACK_LIMIT_ERROR');
30                                 break;
31                         case PREG_RECURSION_LIMIT_ERROR: echo('PREG_RECURSION_LIMIT_ERROR');
32                                 break;
33                         case PREG_BAD_UTF8_ERROR: echo('PREG_BAD_UTF8_ERROR');
34                                 break;
35 //                      This is only valid for php > 5.3, not certain how to code around it for unit tests
36 //                      case PREG_BAD_UTF8_OFFSET_ERROR: echo('PREG_BAD_UTF8_OFFSET_ERROR'); break;
37                         default:
38                                 //die("Unknown preg error.");
39                                 return;
40                 }
41                 echo "<hr><pre>";
42                 debug_print_backtrace();
43                 die();
44         }
45
46         private function _push_stack() {
47                 $this->stack[] = array($this->r, $this->nodes);
48         }
49
50         private function _pop_stack() {
51                 list($this->r, $this->nodes) = array_pop($this->stack);
52         }
53
54         private function _get_var($name, $retNoKey = false) {
55                 $keys = array_map('trim', explode(".", $name));
56                 if ($retNoKey && !array_key_exists($keys[0], $this->r))
57                         return KEY_NOT_EXISTS;
58                 $val = $this->r;
59                 foreach ($keys as $k) {
60                         $val = (isset($val[$k]) ? $val[$k] : null);
61                 }
62                 return $val;
63         }
64
65         /**
66          * IF node
67          * 
68          * {{ if <$var> }}...[{{ else }} ...] {{ endif }}
69          * {{ if <$var>==<val|$var> }}...[{{ else }} ...]{{ endif }}
70          * {{ if <$var>!=<val|$var> }}...[{{ else }} ...]{{ endif }}
71          */
72         private function _replcb_if ($args) {
73                 if (strpos($args[2], "==") > 0) {
74                         list($a, $b) = array_map("trim", explode("==", $args[2]));
75                         $a = $this->_get_var($a);
76                         if ($b[0] == "$")
77                                 $b = $this->_get_var($b);
78                         $val = ($a == $b);
79                 } else if (strpos($args[2], "!=") > 0) {
80                         list($a, $b) = array_map("trim", explode("!=", $args[2]));
81                         $a = $this->_get_var($a);
82                         if ($b[0] == "$")
83                                 $b = $this->_get_var($b);
84                         $val = ($a != $b);
85                 } else {
86                         $val = $this->_get_var($args[2]);
87                 }
88                 $x = preg_split("|{{ *else *}}|", $args[3]);
89                 return ( $val ? $x[0] : (isset($x[1]) ? $x[1] : ""));
90         }
91
92         /**
93          * FOR node
94          * 
95          * {{ for <$var> as $name }}...{{ endfor }}
96          * {{ for <$var> as $key=>$name }}...{{ endfor }}
97          */
98         private function _replcb_for ($args) {
99                 $m = array_map('trim', explode(" as ", $args[2]));
100                 $x = explode("=>", $m[1]);
101                 if (count($x) == 1) {
102                         $varname = $x[0];
103                         $keyname = "";
104                 } else {
105                         list($keyname, $varname) = $x;
106                 }
107                 if ($m[0] == "" || $varname == "" || is_null($varname))
108                         die("template error: 'for " . $m[0] . " as " . $varname . "'");
109                 //$vals = $this->r[$m[0]];
110                 $vals = $this->_get_var($m[0]);
111                 $ret = "";
112                 if (!is_array($vals)) {
113                         return $ret;
114                 }
115                 foreach ($vals as $k => $v) {
116                         $this->_push_stack();
117                         $r = $this->r;
118                         $r[$varname] = $v;
119                         if ($keyname != '') {
120                                 $r[$keyname] = (($k === 0) ? '0' : $k);
121                         }
122                         $ret .= $this->replace($args[3], $r);
123                         $this->_pop_stack();
124                 }
125                 return $ret;
126         }
127
128         /**
129          * INC node
130          * 
131          * {{ inc <templatefile> [with $var1=$var2] }}{{ endinc }}
132          */
133         private function _replcb_inc($args) {
134                 if (strpos($args[2], "with")) {
135                         list($tplfile, $newctx) = array_map('trim', explode("with", $args[2]));
136                 } else {
137                         $tplfile = trim($args[2]);
138                         $newctx = null;
139                 }
140
141                 if ($tplfile[0] == "$")
142                         $tplfile = $this->_get_var($tplfile);
143
144                 $this->_push_stack();
145                 $r = $this->r;
146                 if (!is_null($newctx)) {
147                         list($a, $b) = array_map('trim', explode("=", $newctx));
148                         $r[$a] = $this->_get_var($b);
149                 }
150                 $this->nodes = Array();
151                 $tpl = get_markup_template($tplfile);
152                 $ret = $this->replace($tpl, $r);
153                 $this->_pop_stack();
154                 return $ret;
155         }
156
157         /**
158          * DEBUG node
159          * 
160          * {{ debug $var [$var [$var [...]]] }}{{ enddebug }}
161          * 
162          * replace node with <pre>var_dump($var, $var, ...);</pre>
163          */
164         private function _replcb_debug($args) {
165                 $vars = array_map('trim', explode(" ", $args[2]));
166                 $vars[] = $args[1];
167
168                 $ret = "<pre>";
169                 foreach ($vars as $var) {
170                         $ret .= htmlspecialchars(var_export($this->_get_var($var), true));
171                         $ret .= "\n";
172                 }
173                 $ret .= "</pre>";
174                 return $ret;
175         }
176
177         private function _replcb_node($m) {
178                 $node = $this->nodes[$m[1]];
179                 if (method_exists($this, "_replcb_" . $node[1])) {
180                         $s = call_user_func(array($this, "_replcb_" . $node[1]), $node);
181                 } else {
182                         $s = "";
183                 }
184                 $s = preg_replace_callback('/\|\|([0-9]+)\|\|/', array($this, "_replcb_node"), $s);
185                 return $s;
186         }
187
188         private function _replcb($m) {
189                 //var_dump(array_map('htmlspecialchars', $m));
190                 $this->done = false;
191                 $this->nodes[] = (array) $m;
192                 return "||" . (count($this->nodes) - 1) . "||";
193         }
194
195         private function _build_nodes($s) {
196                 $this->done = false;
197                 while (!$this->done) {
198                         $this->done = true;
199                         $s = preg_replace_callback('|{{ *([a-z]*) *([^}]*)}}([^{]*({{ *else *}}[^{]*)?){{ *end\1 *}}|', array($this, "_replcb"), $s);
200                         if ($s == Null)
201                                 $this->_preg_error();
202                 }
203                 //({{ *else *}}[^{]*)?
204                 krsort($this->nodes);
205                 return $s;
206         }
207
208         private function var_replace($s) {
209                 $m = array();
210                 /** regexp:
211                  * \$                                           literal $
212                  * (\[)?                                        optional open square bracket
213                  * ([a-zA-Z0-9-_]+\.?)+         var name, followed by optional
214                  *                                                      dot, repeated at least 1 time
215                  * (|[a-zA-Z0-9-_:]+)*          pipe followed by filter name and args, zero or many
216                  * (?(1)\])                                     if there was opened square bracket
217                  *                                                      (subgrup 1), match close bracket
218                  */
219                 if (preg_match_all('/\$(\[)?([a-zA-Z0-9-_]+\.?)+(\|[a-zA-Z0-9-_:]+)*(?(1)\])/', $s, $m)) {
220                         foreach ($m[0] as $var) {
221
222                                 $exp = str_replace(array("[", "]"), array("", ""), $var);
223                                 $exptks = explode("|", $exp);
224
225                                 $varn = $exptks[0];
226                                 unset($exptks[0]);
227                                 $val = $this->_get_var($varn, true);
228                                 if ($val != KEY_NOT_EXISTS) {
229                                         /* run filters */
230                                         /*
231                                          * Filter are in form of:
232                                          * filtername:arg:arg:arg
233                                          * 
234                                          * "filtername" is function name
235                                          * "arg"s are optional, var value is appended to the end
236                                          *                      if one "arg"==='x' , is replaced with var value
237                                          * 
238                                          * examples:
239                                          * $item.body|htmlspecialchars                          // escape html chars
240                                          * $item.body|htmlspecialchars|strtoupper   // escape html and uppercase result
241                                          * $item.created|date:%Y %M %j                          // format date (created is a timestamp)
242                                          * $item.body|str_replace:cat:dog                       // replace all "cat" with "dog"
243                                          * $item.body|str_replace:cat:dog:x:1           // replace one "cat" with "dog"
244                                          
245                                          */
246                                         foreach ($exptks as $filterstr) {
247                                                 $filter = explode(":", $filterstr);
248                                                 $filtername = $filter[0];
249                                                 unset($filter[0]);
250                                                 $valkey = array_search("x", $filter);
251                                                 if ($valkey === false) {
252                                                         $filter[] = $val;
253                                                 } else {
254                                                         $filter[$valkey] = $val;
255                                                 }
256                                                 if (function_exists($filtername)) {
257                                                         $val = call_user_func_array($filtername, $filter);
258                                                 }
259                                         }
260                                         $s = str_replace($var, $val, $s);
261                                 }
262                         }
263                 }
264
265                 return $s;
266         }
267
268         // TemplateEngine interface
269         public function replace_macros($s, $r) {
270                 $this->r = $r;
271
272                 // remove comments block
273                 $s = preg_replace('/{#(.*?\s*?)*?#}/', "", $s);
274
275                 $s = $this->_build_nodes($s);
276
277                 $s = preg_replace_callback('/\|\|([0-9]+)\|\|/', array($this, "_replcb_node"), $s);
278                 if ($s == Null)
279                         $this->_preg_error();
280
281                 // replace strings recursively (limit to 10 loops)
282                 $os = "";
283                 $count = 0;
284                 while ($os != $s && $count < 10) {
285                         $os = $s;
286                         $count++;
287                         $s = $this->var_replace($s);
288                 }
289                 return template_unescape($s);
290         }
291         
292         public function get_template_file($file, $root='') {
293                 $a = get_app();
294                 $template_file = get_template_file($a, $file, $root);
295                 $content = file_get_contents($template_file);
296                 return $content;                
297         }
298         
299 }
300
301
302 function template_escape($s) {
303
304         return str_replace(array('$', '{{'), array('!_Doll^Ars1Az_!', '!_DoubLe^BraceS4Rw_!'), $s);
305 }
306
307 function template_unescape($s) {
308
309         return str_replace(array('!_Doll^Ars1Az_!', '!_DoubLe^BraceS4Rw_!'), array('$', '{{'), $s);
310 }
311