Passed
Push — 1.3 ( 6f1a67...b00944 )
by David
05:24
created
lib/Dwoo/Compiler.php 2 patches
Spacing   +384 added lines, -386 removed lines patch added patch discarded remove patch
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
      */
295 295
     public function setNestedCommentsHandling($allow = true)
296 296
     {
297
-        $this->allowNestedComments = (bool)$allow;
297
+        $this->allowNestedComments = (bool) $allow;
298 298
     }
299 299
 
300 300
     /**
@@ -319,7 +319,7 @@  discard block
 block discarded – undo
319 319
      */
320 320
     public function setLooseOpeningHandling($allow = false)
321 321
     {
322
-        $this->allowLooseOpenings = (bool)$allow;
322
+        $this->allowLooseOpenings = (bool) $allow;
323 323
     }
324 324
 
325 325
     /**
@@ -344,7 +344,7 @@  discard block
 block discarded – undo
344 344
      */
345 345
     public function setAutoEscape($enabled)
346 346
     {
347
-        $this->autoEscape = (bool)$enabled;
347
+        $this->autoEscape = (bool) $enabled;
348 348
     }
349 349
 
350 350
     /**
@@ -371,7 +371,7 @@  discard block
 block discarded – undo
371 371
     {
372 372
         if ($autoload) {
373 373
             $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', Core::toCamelCase($callback));
374
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . $name;
374
+            $class = Core::NAMESPACE_PLUGINS_PROCESSORS.$name;
375 375
 
376 376
             if (class_exists($class)) {
377 377
                 $callback = array(new $class($this), 'process');
@@ -396,12 +396,12 @@  discard block
 block discarded – undo
396 396
     {
397 397
         if (($index = array_search($callback, $this->processors['pre'], true)) !== false) {
398 398
             unset($this->processors['pre'][$index]);
399
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
399
+        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS.str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
400 400
                     $callback),
401 401
                 $this->processors['pre'], true)) !== false) {
402 402
             unset($this->processors['pre'][$index]);
403 403
         } else {
404
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
404
+            $class = Core::NAMESPACE_PLUGINS_PROCESSORS.str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
405 405
             foreach ($this->processors['pre'] as $index => $proc) {
406 406
                 if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
407 407
                     unset($this->processors['pre'][$index]);
@@ -424,7 +424,7 @@  discard block
 block discarded – undo
424 424
     {
425 425
         if ($autoload) {
426 426
             $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
427
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . Core::toCamelCase($name);
427
+            $class = Core::NAMESPACE_PLUGINS_PROCESSORS.Core::toCamelCase($name);
428 428
 
429 429
             if (class_exists($class)) {
430 430
                 $callback = array(new $class($this), 'process');
@@ -449,12 +449,12 @@  discard block
 block discarded – undo
449 449
     {
450 450
         if (($index = array_search($callback, $this->processors['post'], true)) !== false) {
451 451
             unset($this->processors['post'][$index]);
452
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
452
+        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS.str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
453 453
                     $callback),
454 454
                 $this->processors['post'], true)) !== false) {
455 455
             unset($this->processors['post'][$index]);
456 456
         } else {
457
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
457
+            $class = Core::NAMESPACE_PLUGINS_PROCESSORS.str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
458 458
             foreach ($this->processors['post'] as $index => $proc) {
459 459
                 if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
460 460
                     unset($this->processors['post'][$index]);
@@ -480,7 +480,7 @@  discard block
 block discarded – undo
480 480
                 $this->getCore()->getLoader()->loadPlugin($name);
481 481
             }
482 482
             catch (Exception $e) {
483
-                throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
483
+                throw new Exception('Processor '.$name.' could not be found in your plugin directories, please ensure it is in a file named '.$name.'.php in the plugin directory');
484 484
             }
485 485
         }
486 486
 
@@ -666,7 +666,7 @@  discard block
 block discarded – undo
666 666
     public function setTemplateSource($newSource, $fromPointer = false)
667 667
     {
668 668
         if ($fromPointer === true) {
669
-            $this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource;
669
+            $this->templateSource = substr($this->templateSource, 0, $this->pointer).$newSource;
670 670
         } else {
671 671
             $this->templateSource = $newSource;
672 672
         }
@@ -737,11 +737,11 @@  discard block
 block discarded – undo
737 737
 
738 738
                 if ($this->debug) {
739 739
                     echo "\n";
740
-                    echo 'COMPILER INIT' . "\n";
740
+                    echo 'COMPILER INIT'."\n";
741 741
                 }
742 742
 
743 743
                 if ($this->debug) {
744
-                    echo 'PROCESSING PREPROCESSORS (' . count($this->processors['pre']) . ')' . "\n";
744
+                    echo 'PROCESSING PREPROCESSORS ('.count($this->processors['pre']).')'."\n";
745 745
                 }
746 746
 
747 747
                 // runs preprocessors
@@ -785,23 +785,23 @@  discard block
 block discarded – undo
785 785
             if ($pos === false) {
786 786
                 $this->push(substr($tpl, $ptr), 0);
787 787
                 break;
788
-            } elseif (substr($tpl, $pos - 1, 1) === '\\' && substr($tpl, $pos - 2, 1) !== '\\') {
789
-                $this->push(substr($tpl, $ptr, $pos - $ptr - 1) . $this->ld);
790
-                $ptr = $pos + strlen($this->ld);
791
-            } elseif (preg_match('/^' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', substr($tpl, $pos), $litOpen)) {
792
-                if (!preg_match('/' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
788
+            } elseif (substr($tpl, $pos-1, 1) === '\\' && substr($tpl, $pos-2, 1) !== '\\') {
789
+                $this->push(substr($tpl, $ptr, $pos-$ptr-1).$this->ld);
790
+                $ptr = $pos+strlen($this->ld);
791
+            } elseif (preg_match('/^'.$this->ldr.($this->allowLooseOpenings ? '\s*' : '').'literal'.($this->allowLooseOpenings ? '\s*' : '').$this->rdr.'/s', substr($tpl, $pos), $litOpen)) {
792
+                if (!preg_match('/'.$this->ldr.($this->allowLooseOpenings ? '\s*' : '').'\/literal'.($this->allowLooseOpenings ? '\s*' : '').$this->rdr.'/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
793 793
                     throw new CompilationException($this, 'The {literal} blocks must be closed explicitly with {/literal}');
794 794
                 }
795 795
                 $endpos = $litClose[0][1];
796
-                $this->push(substr($tpl, $ptr, $pos - $ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos - $pos - strlen($litOpen[0])));
797
-                $ptr = $endpos + strlen($litClose[0][0]);
796
+                $this->push(substr($tpl, $ptr, $pos-$ptr).substr($tpl, $pos+strlen($litOpen[0]), $endpos-$pos-strlen($litOpen[0])));
797
+                $ptr = $endpos+strlen($litClose[0][0]);
798 798
             } else {
799
-                if (substr($tpl, $pos - 2, 1) === '\\' && substr($tpl, $pos - 1, 1) === '\\') {
800
-                    $this->push(substr($tpl, $ptr, $pos - $ptr - 1));
799
+                if (substr($tpl, $pos-2, 1) === '\\' && substr($tpl, $pos-1, 1) === '\\') {
800
+                    $this->push(substr($tpl, $ptr, $pos-$ptr-1));
801 801
                     $ptr = $pos;
802 802
                 }
803 803
 
804
-                $this->push(substr($tpl, $ptr, $pos - $ptr));
804
+                $this->push(substr($tpl, $ptr, $pos-$ptr));
805 805
                 $ptr = $pos;
806 806
 
807 807
                 $pos += strlen($this->ld);
@@ -819,7 +819,7 @@  discard block
 block discarded – undo
819 819
 
820 820
                 // check that there is an end tag present
821 821
                 if (strpos($tpl, $this->rd, $pos) === false) {
822
-                    throw new CompilationException($this, 'A template tag was not closed, started with "' . substr($tpl, $ptr, 30) . '"');
822
+                    throw new CompilationException($this, 'A template tag was not closed, started with "'.substr($tpl, $ptr, 30).'"');
823 823
                 }
824 824
 
825 825
                 $ptr += strlen($this->ld);
@@ -833,7 +833,7 @@  discard block
 block discarded – undo
833 833
                         continue 2;
834 834
                     }
835 835
 
836
-                    $len = $subptr - $ptr;
836
+                    $len = $subptr-$ptr;
837 837
                     $this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n"));
838 838
                     $ptr += $len;
839 839
 
@@ -847,7 +847,7 @@  discard block
 block discarded – undo
847 847
         $compiled .= $this->removeBlock('TopLevelBlock');
848 848
 
849 849
         if ($this->debug) {
850
-            echo 'PROCESSING POSTPROCESSORS' . "\n";
850
+            echo 'PROCESSING POSTPROCESSORS'."\n";
851 851
         }
852 852
 
853 853
         foreach ($this->processors['post'] as $postProc) {
@@ -863,7 +863,7 @@  discard block
 block discarded – undo
863 863
         unset($postProc);
864 864
 
865 865
         if ($this->debug) {
866
-            echo 'COMPILATION COMPLETE : MEM USAGE : ' . memory_get_usage() . "\n";
866
+            echo 'COMPILATION COMPLETE : MEM USAGE : '.memory_get_usage()."\n";
867 867
         }
868 868
 
869 869
         $output = "<?php\n/* template head */\n";
@@ -876,30 +876,30 @@  discard block
 block discarded – undo
876 876
 
877 877
             switch ($type) {
878 878
                 case Core::CLASS_PLUGIN:
879
-                case Core::CLASS_PLUGIN + Core::BLOCK_PLUGIN:
880
-                    if (class_exists('Plugin' . $plugin) !== false) {
881
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
879
+                case Core::CLASS_PLUGIN+Core::BLOCK_PLUGIN:
880
+                    if (class_exists('Plugin'.$plugin) !== false) {
881
+                        $output .= "if (class_exists('"."Plugin".$plugin."')===false)".
882 882
                         "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
883 883
                     } else {
884
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_BLOCKS . "Plugin" . $plugin . "')===false)".
884
+                        $output .= "if (class_exists('".Core::NAMESPACE_PLUGINS_BLOCKS."Plugin".$plugin."')===false)".
885 885
                         "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
886 886
                     }
887 887
                     break;
888
-                case Core::CLASS_PLUGIN + Core::FUNC_PLUGIN:
889
-                    if (class_exists('Plugin' . $plugin) !== false) {
890
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
888
+                case Core::CLASS_PLUGIN+Core::FUNC_PLUGIN:
889
+                    if (class_exists('Plugin'.$plugin) !== false) {
890
+                        $output .= "if (class_exists('"."Plugin".$plugin."')===false)".
891 891
                             "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
892 892
                     } else {
893
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
893
+                        $output .= "if (class_exists('".Core::NAMESPACE_PLUGINS_FUNCTIONS."Plugin".$plugin."')===false)".
894 894
                             "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
895 895
                     }
896 896
                     break;
897 897
                 case Core::FUNC_PLUGIN:
898
-                    if (function_exists('Plugin' . $plugin) !== false) {
899
-                        $output .= "if (function_exists('" . "Plugin" . $plugin . "')===false)".
898
+                    if (function_exists('Plugin'.$plugin) !== false) {
899
+                        $output .= "if (function_exists('"."Plugin".$plugin."')===false)".
900 900
                         "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
901 901
                     } else {
902
-                        $output .= "if (function_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
902
+                        $output .= "if (function_exists('".Core::NAMESPACE_PLUGINS_FUNCTIONS."Plugin".$plugin."')===false)".
903 903
                         "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
904 904
                     }
905 905
                     break;
@@ -919,7 +919,7 @@  discard block
 block discarded – undo
919 919
                     $output .= $this->getCore()->getPluginProxy()->getLoader($plugin);
920 920
                     break;
921 921
                 default:
922
-                    throw new CompilationException($this, 'Type error for ' . $plugin . ' with type' . $type);
922
+                    throw new CompilationException($this, 'Type error for '.$plugin.' with type'.$type);
923 923
             }
924 924
         }
925 925
 
@@ -930,30 +930,30 @@  discard block
 block discarded – undo
930 930
         }
931 931
         foreach ($this->templatePlugins as $function) {
932 932
             if (isset($function['called']) && $function['called'] === true) {
933
-                $output .= $function['body'] . PHP_EOL;
933
+                $output .= $function['body'].PHP_EOL;
934 934
             }
935 935
         }
936 936
 
937
-        $output .= $compiled . "\n?>";
937
+        $output .= $compiled."\n?>";
938 938
 
939
-        $output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*' . preg_quote(self::PHP_CLOSE, '/') . preg_quote(self::PHP_OPEN, '/') . ')/', ";\n", $output);
940
-        $output = str_replace(self::PHP_CLOSE . self::PHP_OPEN, "\n", $output);
939
+        $output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*'.preg_quote(self::PHP_CLOSE, '/').preg_quote(self::PHP_OPEN, '/').')/', ";\n", $output);
940
+        $output = str_replace(self::PHP_CLOSE.self::PHP_OPEN, "\n", $output);
941 941
 
942 942
         // handle <?xml tag at the beginning
943 943
         $output = preg_replace('#(/\* template body \*/ \?>\s*)<\?xml#is', '$1<?php echo \'<?xml\'; ?>', $output);
944 944
 
945 945
         // add another line break after PHP closing tags that have a line break following,
946 946
         // as we do not know whether it's intended, and PHP will strip it otherwise
947
-        $output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0' . "\n", $output);
947
+        $output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0'."\n", $output);
948 948
 
949 949
         if ($this->debug) {
950
-            echo '=============================================================================================' . "\n";
950
+            echo '============================================================================================='."\n";
951 951
             $lines = preg_split('{\r\n|\n|<br />}', $output);
952 952
             array_shift($lines);
953 953
             foreach ($lines as $i => $line) {
954
-                echo ($i + 1) . '. ' . $line . "\r\n";
954
+                echo ($i+1).'. '.$line."\r\n";
955 955
             }
956
-            echo '=============================================================================================' . "\n";
956
+            echo '============================================================================================='."\n";
957 957
         }
958 958
 
959 959
         $this->template = $this->dwoo = null;
@@ -970,13 +970,13 @@  discard block
 block discarded – undo
970 970
     protected function resolveSubTemplateDependencies($function)
971 971
     {
972 972
         if ($this->debug) {
973
-            echo 'Compiler::' . __FUNCTION__ . "\n";
973
+            echo 'Compiler::'.__FUNCTION__."\n";
974 974
         }
975 975
 
976 976
         $body = $this->templatePlugins[$function]['body'];
977 977
         foreach ($this->templatePlugins as $func => $attr) {
978
-            if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS .
979
-            'Plugin' . Core::toCamelCase($func)) !== false) {
978
+            if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS.
979
+            'Plugin'.Core::toCamelCase($func)) !== false) {
980 980
                 $this->templatePlugins[$func]['called'] = true;
981 981
                 $this->resolveSubTemplateDependencies($func);
982 982
             }
@@ -1000,14 +1000,14 @@  discard block
 block discarded – undo
1000 1000
 
1001 1001
         if ($this->curBlock['buffer'] === null && count($this->stack) > 1) {
1002 1002
             // buffer is not initialized yet (the block has just been created)
1003
-            $this->stack[count($this->stack) - 2]['buffer'] .= (string)$content;
1003
+            $this->stack[count($this->stack)-2]['buffer'] .= (string) $content;
1004 1004
             $this->curBlock['buffer'] = '';
1005 1005
         } else {
1006 1006
             if (!isset($this->curBlock['buffer'])) {
1007 1007
                 throw new CompilationException($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere');
1008 1008
             }
1009 1009
             // append current content to current block's buffer
1010
-            $this->curBlock['buffer'] .= (string)$content;
1010
+            $this->curBlock['buffer'] .= (string) $content;
1011 1011
         }
1012 1012
         $this->line += $lineCount;
1013 1013
     }
@@ -1077,26 +1077,26 @@  discard block
 block discarded – undo
1077 1077
     public function addBlock($type, array $params, $paramtype)
1078 1078
     {
1079 1079
         if ($this->debug) {
1080
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1080
+            echo 'Compiler::'.__FUNCTION__."\n";
1081 1081
         }
1082 1082
 
1083 1083
         $class = current(array_filter([
1084
-            'Plugin' . Core::toCamelCase($type),
1085
-            Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type)
1084
+            'Plugin'.Core::toCamelCase($type),
1085
+            Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($type)
1086 1086
         ], 'class_exists'));
1087 1087
         if (false === $class) {
1088 1088
             $this->getCore()->getLoader()->loadPlugin($type);
1089 1089
         }
1090 1090
         $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1091 1091
 
1092
-        $this->stack[]  = array(
1092
+        $this->stack[] = array(
1093 1093
             'type'   => $type,
1094 1094
             'params' => $params,
1095 1095
             'custom' => false,
1096 1096
             'class'  => $class,
1097 1097
             'buffer' => null
1098 1098
         );
1099
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1099
+        $this->curBlock = &$this->stack[count($this->stack)-1];
1100 1100
 
1101 1101
         return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1102 1102
     }
@@ -1121,14 +1121,14 @@  discard block
 block discarded – undo
1121 1121
 
1122 1122
         $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1123 1123
 
1124
-        $this->stack[]  = array(
1124
+        $this->stack[] = array(
1125 1125
             'type'   => $type,
1126 1126
             'params' => $params,
1127 1127
             'custom' => true,
1128 1128
             'class'  => $class,
1129 1129
             'buffer' => null
1130 1130
         );
1131
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1131
+        $this->curBlock = &$this->stack[count($this->stack)-1];
1132 1132
 
1133 1133
         return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1134 1134
     }
@@ -1143,21 +1143,21 @@  discard block
 block discarded – undo
1143 1143
     public function injectBlock($type, array $params)
1144 1144
     {
1145 1145
         if ($this->debug) {
1146
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1146
+            echo 'Compiler::'.__FUNCTION__."\n";
1147 1147
         }
1148 1148
 
1149
-        $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1149
+        $class = Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($type);
1150 1150
         if (class_exists($class) === false) {
1151 1151
             $this->getCore()->getLoader()->loadPlugin($type);
1152 1152
         }
1153
-        $this->stack[]  = array(
1153
+        $this->stack[] = array(
1154 1154
             'type'   => $type,
1155 1155
             'params' => $params,
1156 1156
             'custom' => false,
1157 1157
             'class'  => $class,
1158 1158
             'buffer' => null
1159 1159
         );
1160
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1160
+        $this->curBlock = &$this->stack[count($this->stack)-1];
1161 1161
     }
1162 1162
 
1163 1163
     /**
@@ -1172,7 +1172,7 @@  discard block
 block discarded – undo
1172 1172
     public function removeBlock($type)
1173 1173
     {
1174 1174
         if ($this->debug) {
1175
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1175
+            echo 'Compiler::'.__FUNCTION__."\n";
1176 1176
         }
1177 1177
 
1178 1178
         $output = '';
@@ -1187,12 +1187,12 @@  discard block
 block discarded – undo
1187 1187
                     $class = $top['class'];
1188 1188
                 } else {
1189 1189
                     $class = current(array_filter([
1190
-                        'Plugin' . Core::toCamelCase($top['type']),
1191
-                        Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($top['type'])
1190
+                        'Plugin'.Core::toCamelCase($top['type']),
1191
+                        Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($top['type'])
1192 1192
                     ], 'class_exists'));
1193 1193
                 }
1194 1194
                 if (count($this->stack)) {
1195
-                    $this->curBlock = &$this->stack[count($this->stack) - 1];
1195
+                    $this->curBlock = &$this->stack[count($this->stack)-1];
1196 1196
                     $this->push(call_user_func(array(
1197 1197
                         $class,
1198 1198
                         'postProcessing'
@@ -1213,7 +1213,7 @@  discard block
 block discarded – undo
1213 1213
                 }
1214 1214
             }
1215 1215
 
1216
-            throw new CompilationException($this, 'Syntax malformation, a block of type "' . $type . '" was closed but was not opened');
1216
+            throw new CompilationException($this, 'Syntax malformation, a block of type "'.$type.'" was closed but was not opened');
1217 1217
         }
1218 1218
 
1219 1219
         return $output;
@@ -1251,7 +1251,7 @@  discard block
 block discarded – undo
1251 1251
             }
1252 1252
         }
1253 1253
 
1254
-        throw new CompilationException($this, 'A parent block of type "' . $type . '" is required and can not be found');
1254
+        throw new CompilationException($this, 'A parent block of type "'.$type.'" is required and can not be found');
1255 1255
     }
1256 1256
 
1257 1257
     /**
@@ -1274,7 +1274,7 @@  discard block
 block discarded – undo
1274 1274
     public function removeTopBlock()
1275 1275
     {
1276 1276
         if ($this->debug) {
1277
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1277
+            echo 'Compiler::'.__FUNCTION__."\n";
1278 1278
         }
1279 1279
 
1280 1280
         $o = array_pop($this->stack);
@@ -1284,10 +1284,10 @@  discard block
 block discarded – undo
1284 1284
         if ($o['custom']) {
1285 1285
             $class = $o['class'];
1286 1286
         } else {
1287
-            $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($o['type']);
1287
+            $class = Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($o['type']);
1288 1288
         }
1289 1289
 
1290
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1290
+        $this->curBlock = &$this->stack[count($this->stack)-1];
1291 1291
 
1292 1292
         return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']);
1293 1293
     }
@@ -1366,7 +1366,7 @@  discard block
 block discarded – undo
1366 1366
     protected function parse($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1367 1367
     {
1368 1368
         if ($this->debug) {
1369
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1369
+            echo 'Compiler::'.__FUNCTION__."\n";
1370 1370
         }
1371 1371
 
1372 1372
         if ($to === null) {
@@ -1383,14 +1383,14 @@  discard block
 block discarded – undo
1383 1383
                 // end template tag
1384 1384
                 $pointer += strlen($this->rd);
1385 1385
                 if ($this->debug) {
1386
-                    echo 'TEMPLATE PARSING ENDED' . "\n";
1386
+                    echo 'TEMPLATE PARSING ENDED'."\n";
1387 1387
                 }
1388 1388
 
1389 1389
                 return false;
1390 1390
             }
1391
-            ++ $from;
1391
+            ++$from;
1392 1392
             if ($pointer !== null) {
1393
-                ++ $pointer;
1393
+                ++$pointer;
1394 1394
             }
1395 1395
             if ($from >= $to) {
1396 1396
                 if (is_array($parsingParams)) {
@@ -1402,22 +1402,22 @@  discard block
 block discarded – undo
1402 1402
             $first = $in[$from];
1403 1403
         }
1404 1404
 
1405
-        $substr = substr($in, $from, $to - $from);
1405
+        $substr = substr($in, $from, $to-$from);
1406 1406
 
1407 1407
         if ($this->debug) {
1408
-            echo 'PARSE CALL : PARSING "' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . '" @ ' . $from . ':' . $to . ' in ' . $curBlock . ' : pointer=' . $pointer . "\n";
1408
+            echo 'PARSE CALL : PARSING "'.htmlentities(substr($in, $from, min($to-$from, 50))).(($to-$from) > 50 ? '...' : '').'" @ '.$from.':'.$to.' in '.$curBlock.' : pointer='.$pointer."\n";
1409 1409
         }
1410 1410
         $parsed = '';
1411 1411
 
1412 1412
         if ($curBlock === 'root' && $first === '*') {
1413 1413
             $src      = $this->getTemplateSource();
1414
-            $startpos = $this->getPointer() - strlen($this->ld);
1414
+            $startpos = $this->getPointer()-strlen($this->ld);
1415 1415
             if (substr($src, $startpos, strlen($this->ld)) === $this->ld) {
1416 1416
                 if ($startpos > 0) {
1417 1417
                     do {
1418 1418
                         $char = substr($src, -- $startpos, 1);
1419 1419
                         if ($char == "\n") {
1420
-                            ++ $startpos;
1420
+                            ++$startpos;
1421 1421
                             $whitespaceStart = true;
1422 1422
                             break;
1423 1423
                         }
@@ -1428,12 +1428,12 @@  discard block
 block discarded – undo
1428 1428
                 if (!isset($whitespaceStart)) {
1429 1429
                     $startpos = $this->getPointer();
1430 1430
                 } else {
1431
-                    $pointer -= $this->getPointer() - $startpos;
1431
+                    $pointer -= $this->getPointer()-$startpos;
1432 1432
                 }
1433 1433
 
1434
-                if ($this->allowNestedComments && strpos($src, $this->ld . '*', $this->getPointer()) !== false) {
1435
-                    $comOpen  = $this->ld . '*';
1436
-                    $comClose = '*' . $this->rd;
1434
+                if ($this->allowNestedComments && strpos($src, $this->ld.'*', $this->getPointer()) !== false) {
1435
+                    $comOpen  = $this->ld.'*';
1436
+                    $comClose = '*'.$this->rd;
1437 1437
                     $level    = 1;
1438 1438
                     $ptr      = $this->getPointer();
1439 1439
 
@@ -1443,33 +1443,33 @@  discard block
 block discarded – undo
1443 1443
 
1444 1444
                         if ($open !== false && $close !== false) {
1445 1445
                             if ($open < $close) {
1446
-                                $ptr = $open + strlen($comOpen);
1447
-                                ++ $level;
1446
+                                $ptr = $open+strlen($comOpen);
1447
+                                ++$level;
1448 1448
                             } else {
1449
-                                $ptr = $close + strlen($comClose);
1450
-                                -- $level;
1449
+                                $ptr = $close+strlen($comClose);
1450
+                                --$level;
1451 1451
                             }
1452 1452
                         } elseif ($open !== false) {
1453
-                            $ptr = $open + strlen($comOpen);
1454
-                            ++ $level;
1453
+                            $ptr = $open+strlen($comOpen);
1454
+                            ++$level;
1455 1455
                         } elseif ($close !== false) {
1456
-                            $ptr = $close + strlen($comClose);
1457
-                            -- $level;
1456
+                            $ptr = $close+strlen($comClose);
1457
+                            --$level;
1458 1458
                         } else {
1459 1459
                             $ptr = strlen($src);
1460 1460
                         }
1461 1461
                     }
1462
-                    $endpos = $ptr - strlen('*' . $this->rd);
1462
+                    $endpos = $ptr-strlen('*'.$this->rd);
1463 1463
                 } else {
1464
-                    $endpos = strpos($src, '*' . $this->rd, $startpos);
1464
+                    $endpos = strpos($src, '*'.$this->rd, $startpos);
1465 1465
                     if ($endpos == false) {
1466 1466
                         throw new CompilationException($this, 'Un-ended comment');
1467 1467
                     }
1468 1468
                 }
1469
-                $pointer += $endpos - $startpos + strlen('*' . $this->rd);
1470
-                if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos + strlen('*' . $this->rd)), $m)) {
1469
+                $pointer += $endpos-$startpos+strlen('*'.$this->rd);
1470
+                if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos+strlen('*'.$this->rd)), $m)) {
1471 1471
                     $pointer += strlen($m[0]);
1472
-                    $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld)));
1472
+                    $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer'])-($this->getPointer()-$startpos-strlen($this->ld)));
1473 1473
                 }
1474 1474
 
1475 1475
                 return false;
@@ -1486,20 +1486,20 @@  discard block
 block discarded – undo
1486 1486
         } elseif (($first === '"' || $first === "'") && !(is_array($parsingParams) && preg_match('#^([\'"])[a-z0-9_]+\1\s*=>?(?:\s+|[^=])#i', $substr))) {
1487 1487
             // string
1488 1488
             $out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer);
1489
-        } elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?(' . (is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|') . '\s*\(|\s*' . $this->rdr . '|\s*;)/i', $substr)) {
1489
+        } elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?('.(is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|').'\s*\(|\s*'.$this->rdr.'|\s*;)/i', $substr)) {
1490 1490
             // func
1491 1491
             $out    = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer);
1492 1492
             $parsed = 'func';
1493 1493
         } elseif ($first === ';') {
1494 1494
             // instruction end
1495 1495
             if ($this->debug) {
1496
-                echo 'END OF INSTRUCTION' . "\n";
1496
+                echo 'END OF INSTRUCTION'."\n";
1497 1497
             }
1498 1498
             if ($pointer !== null) {
1499
-                ++ $pointer;
1499
+                ++$pointer;
1500 1500
             }
1501 1501
 
1502
-            return $this->parse($in, $from + 1, $to, false, 'root', $pointer);
1502
+            return $this->parse($in, $from+1, $to, false, 'root', $pointer);
1503 1503
         } elseif ($curBlock === 'root' && preg_match('#^/([a-z_][a-z0-9_]*)?#i', $substr, $match)) {
1504 1504
             // close block
1505 1505
             if (!empty($match[1]) && $match[1] == 'else') {
@@ -1516,13 +1516,13 @@  discard block
 block discarded – undo
1516 1516
                     $pointer -= strlen($match[0]);
1517 1517
                 }
1518 1518
                 if ($this->debug) {
1519
-                    echo 'TOP BLOCK CLOSED' . "\n";
1519
+                    echo 'TOP BLOCK CLOSED'."\n";
1520 1520
                 }
1521 1521
 
1522 1522
                 return $this->removeTopBlock();
1523 1523
             } else {
1524 1524
                 if ($this->debug) {
1525
-                    echo 'BLOCK OF TYPE ' . $match[1] . ' CLOSED' . "\n";
1525
+                    echo 'BLOCK OF TYPE '.$match[1].' CLOSED'."\n";
1526 1526
                 }
1527 1527
 
1528 1528
                 return $this->removeBlock($match[1]);
@@ -1530,19 +1530,19 @@  discard block
 block discarded – undo
1530 1530
         } elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) {
1531 1531
             // end template tag
1532 1532
             if ($this->debug) {
1533
-                echo 'TAG PARSING ENDED' . "\n";
1533
+                echo 'TAG PARSING ENDED'."\n";
1534 1534
             }
1535 1535
             $pointer += strlen($this->rd);
1536 1536
 
1537 1537
             return false;
1538
-        } elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*=' . ($curBlock === 'array' ? '>?' : '') . ')(?:\s+|[^=]).*#i', $substr, $match)) {
1538
+        } elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*='.($curBlock === 'array' ? '>?' : '').')(?:\s+|[^=]).*#i', $substr, $match)) {
1539 1539
             // named parameter
1540 1540
             if ($this->debug) {
1541
-                echo 'NAMED PARAM FOUND' . "\n";
1541
+                echo 'NAMED PARAM FOUND'."\n";
1542 1542
             }
1543 1543
             $len = strlen($match[1]);
1544
-            while (substr($in, $from + $len, 1) === ' ') {
1545
-                ++ $len;
1544
+            while (substr($in, $from+$len, 1) === ' ') {
1545
+                ++$len;
1546 1546
             }
1547 1547
             if ($pointer !== null) {
1548 1548
                 $pointer += $len;
@@ -1550,7 +1550,7 @@  discard block
 block discarded – undo
1550 1550
 
1551 1551
             $output = array(
1552 1552
                 trim($match[1], " \t\r\n=>'\""),
1553
-                $this->parse($in, $from + $len, $to, false, 'namedparam', $pointer)
1553
+                $this->parse($in, $from+$len, $to, false, 'namedparam', $pointer)
1554 1554
             );
1555 1555
 
1556 1556
             $parsingParams[] = $output;
@@ -1571,31 +1571,31 @@  discard block
 block discarded – undo
1571 1571
             $out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1572 1572
         } else {
1573 1573
             // parse error
1574
-            throw new CompilationException($this, 'Parse error in "' . substr($in, $from, $to - $from) . '"');
1574
+            throw new CompilationException($this, 'Parse error in "'.substr($in, $from, $to-$from).'"');
1575 1575
         }
1576 1576
 
1577 1577
         if (empty($out)) {
1578 1578
             return '';
1579 1579
         }
1580 1580
 
1581
-        $substr = substr($in, $pointer, $to - $pointer);
1581
+        $substr = substr($in, $pointer, $to-$pointer);
1582 1582
 
1583 1583
         // var parsed, check if any var-extension applies
1584 1584
         if ($parsed === 'var') {
1585 1585
             if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) {
1586 1586
                 if ($this->debug) {
1587
-                    echo 'PARSING POST-VAR EXPRESSION ' . $substr . "\n";
1587
+                    echo 'PARSING POST-VAR EXPRESSION '.$substr."\n";
1588 1588
                 }
1589 1589
                 // parse expressions
1590
-                $pointer += strlen($match[0]) - 1;
1590
+                $pointer += strlen($match[0])-1;
1591 1591
                 if (is_array($parsingParams)) {
1592 1592
                     if ($match[2] == '$') {
1593 1593
                         $expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer);
1594 1594
                     } else {
1595 1595
                         $expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer);
1596 1596
                     }
1597
-                    $out[count($out) - 1][0] .= $match[1] . $expr[0][0];
1598
-                    $out[count($out) - 1][1] .= $match[1] . $expr[0][1];
1597
+                    $out[count($out)-1][0] .= $match[1].$expr[0][0];
1598
+                    $out[count($out)-1][1] .= $match[1].$expr[0][1];
1599 1599
                 } else {
1600 1600
                     if ($match[2] == '$') {
1601 1601
                         $expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer);
@@ -1603,26 +1603,26 @@  discard block
 block discarded – undo
1603 1603
                         $expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer);
1604 1604
                     }
1605 1605
                     if (is_array($out) && is_array($expr)) {
1606
-                        $out[0] .= $match[1] . $expr[0];
1607
-                        $out[1] .= $match[1] . $expr[1];
1606
+                        $out[0] .= $match[1].$expr[0];
1607
+                        $out[1] .= $match[1].$expr[1];
1608 1608
                     } elseif (is_array($out)) {
1609
-                        $out[0] .= $match[1] . $expr;
1610
-                        $out[1] .= $match[1] . $expr;
1609
+                        $out[0] .= $match[1].$expr;
1610
+                        $out[1] .= $match[1].$expr;
1611 1611
                     } elseif (is_array($expr)) {
1612
-                        $out .= $match[1] . $expr[0];
1612
+                        $out .= $match[1].$expr[0];
1613 1613
                     } else {
1614
-                        $out .= $match[1] . $expr;
1614
+                        $out .= $match[1].$expr;
1615 1615
                     }
1616 1616
                 }
1617 1617
             } elseif ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) {
1618 1618
                 if ($this->debug) {
1619
-                    echo 'PARSING POST-VAR ASSIGNMENT ' . $substr . "\n";
1619
+                    echo 'PARSING POST-VAR ASSIGNMENT '.$substr."\n";
1620 1620
                 }
1621 1621
                 // parse assignment
1622 1622
                 $value    = $match[2];
1623 1623
                 $operator = trim($match[1]);
1624 1624
                 if (substr($value, 0, 1) == '=') {
1625
-                    throw new CompilationException($this, 'Unexpected "=" in <em>' . $substr . '</em>');
1625
+                    throw new CompilationException($this, 'Unexpected "=" in <em>'.$substr.'</em>');
1626 1626
                 }
1627 1627
 
1628 1628
                 if ($pointer !== null) {
@@ -1643,7 +1643,7 @@  discard block
 block discarded – undo
1643 1643
                         throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1644 1644
                     }
1645 1645
 
1646
-                    $parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS . 'PluginIf', 'init'), 1);
1646
+                    $parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS.'PluginIf', 'init'), 1);
1647 1647
                     $tokens = $this->getParamTokens($parts);
1648 1648
                     $parts  = $this->getCompiledParams($parts);
1649 1649
 
@@ -1657,14 +1657,14 @@  discard block
 block discarded – undo
1657 1657
                 if ($this->autoEscape) {
1658 1658
                     $out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out);
1659 1659
                 }
1660
-                $out = self::PHP_OPEN . $echo . $out . $operator . implode(' ', $value) . self::PHP_CLOSE;
1660
+                $out = self::PHP_OPEN.$echo.$out.$operator.implode(' ', $value).self::PHP_CLOSE;
1661 1661
             } elseif ($curBlock === 'array' && is_array($parsingParams) && preg_match('#^(\s*=>?\s*)#', $substr, $match)) {
1662 1662
                 // parse namedparam with var as name (only for array)
1663 1663
                 if ($this->debug) {
1664
-                    echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND' . "\n";
1664
+                    echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND'."\n";
1665 1665
                 }
1666 1666
                 $len = strlen($match[1]);
1667
-                $var = $out[count($out) - 1];
1667
+                $var = $out[count($out)-1];
1668 1668
                 $pointer += $len;
1669 1669
 
1670 1670
                 $output = array($var[0], $this->parse($substr, $len, null, false, 'namedparam', $pointer));
@@ -1679,16 +1679,16 @@  discard block
 block discarded – undo
1679 1679
             // parse modifier on funcs or vars
1680 1680
             $srcPointer = $pointer;
1681 1681
             if (is_array($parsingParams)) {
1682
-                $tmp                     = $this->replaceModifiers(
1682
+                $tmp = $this->replaceModifiers(
1683 1683
                     array(
1684 1684
                     null,
1685 1685
                     null,
1686
-                    $out[count($out) - 1][0],
1686
+                    $out[count($out)-1][0],
1687 1687
                     $match[0]
1688 1688
                     ), $curBlock, $pointer
1689 1689
                 );
1690
-                $out[count($out) - 1][0] = $tmp;
1691
-                $out[count($out) - 1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer);
1690
+                $out[count($out)-1][0] = $tmp;
1691
+                $out[count($out)-1][1] .= substr($substr, $srcPointer, $srcPointer-$pointer);
1692 1692
             } else {
1693 1693
                 $out = $this->replaceModifiers(array(null, null, $out, $match[0]), $curBlock, $pointer);
1694 1694
             }
@@ -1700,10 +1700,10 @@  discard block
 block discarded – undo
1700 1700
             $ptr = 0;
1701 1701
 
1702 1702
             if (is_array($parsingParams)) {
1703
-                $output = $this->parseMethodCall($out[count($out) - 1][1], $match[0], $curBlock, $ptr);
1703
+                $output = $this->parseMethodCall($out[count($out)-1][1], $match[0], $curBlock, $ptr);
1704 1704
 
1705
-                $out[count($out) - 1][0] = $output;
1706
-                $out[count($out) - 1][1] .= substr($match[0], 0, $ptr);
1705
+                $out[count($out)-1][0] = $output;
1706
+                $out[count($out)-1][1] .= substr($match[0], 0, $ptr);
1707 1707
             } else {
1708 1708
                 $out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr);
1709 1709
             }
@@ -1712,7 +1712,7 @@  discard block
 block discarded – undo
1712 1712
         }
1713 1713
 
1714 1714
         if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) {
1715
-            return self::PHP_OPEN . 'echo ' . $out . ';' . self::PHP_CLOSE;
1715
+            return self::PHP_OPEN.'echo '.$out.';'.self::PHP_CLOSE;
1716 1716
         }
1717 1717
 
1718 1718
         return $out;
@@ -1738,11 +1738,11 @@  discard block
 block discarded – undo
1738 1738
     protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1739 1739
     {
1740 1740
         $output = '';
1741
-        $cmdstr = substr($in, $from, $to - $from);
1742
-        preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*' . $this->rdr . '|\s*;)?/i', $cmdstr, $match);
1741
+        $cmdstr = substr($in, $from, $to-$from);
1742
+        preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*'.$this->rdr.'|\s*;)?/i', $cmdstr, $match);
1743 1743
 
1744 1744
         if (empty($match[1])) {
1745
-            throw new CompilationException($this, 'Parse error, invalid function name : ' . substr($cmdstr, 0, 15));
1745
+            throw new CompilationException($this, 'Parse error, invalid function name : '.substr($cmdstr, 0, 15));
1746 1746
         }
1747 1747
 
1748 1748
         $func = $match[1];
@@ -1752,7 +1752,7 @@  discard block
 block discarded – undo
1752 1752
         }
1753 1753
 
1754 1754
         if ($this->debug) {
1755
-            echo 'FUNC FOUND (' . $func . ')' . "\n";
1755
+            echo 'FUNC FOUND ('.$func.')'."\n";
1756 1756
         }
1757 1757
 
1758 1758
         $paramsep = '';
@@ -1764,11 +1764,11 @@  discard block
 block discarded – undo
1764 1764
             $paramspos = $match[1][0][1];
1765 1765
             $paramsep  = substr($match[1][0][0], - 1) === '(' ? ')' : '';
1766 1766
             if ($paramsep === ')') {
1767
-                $paramspos += strlen($match[1][0][0]) - 1;
1767
+                $paramspos += strlen($match[1][0][0])-1;
1768 1768
                 if (substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') {
1769 1769
                     $paramsep = '';
1770 1770
                     if (strlen($match[1][0][0]) > 1) {
1771
-                        -- $paramspos;
1771
+                        --$paramspos;
1772 1772
                     }
1773 1773
                 }
1774 1774
             }
@@ -1793,8 +1793,8 @@  discard block
 block discarded – undo
1793 1793
                     return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1794 1794
                 }
1795 1795
             }
1796
-            $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos - strlen($func)));
1797
-            $paramstr   = substr($cmdstr, $paramspos + 1);
1796
+            $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos-strlen($func)));
1797
+            $paramstr   = substr($cmdstr, $paramspos+1);
1798 1798
             if (substr($paramstr, - 1, 1) === $paramsep) {
1799 1799
                 $paramstr = substr($paramstr, 0, - 1);
1800 1800
             }
@@ -1816,36 +1816,36 @@  discard block
 block discarded – undo
1816 1816
 
1817 1817
                             if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') {
1818 1818
                                 if ($this->debug) {
1819
-                                    echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT ' . $ptr . "\n";
1819
+                                    echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT '.$ptr."\n";
1820 1820
                                 }
1821 1821
                                 break 2;
1822 1822
                             } elseif ($paramstr[$ptr] === ';') {
1823
-                                ++ $ptr;
1823
+                                ++$ptr;
1824 1824
                                 if ($this->debug) {
1825
-                                    echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT ' . $ptr . "\n";
1825
+                                    echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT '.$ptr."\n";
1826 1826
                                 }
1827 1827
                                 break 2;
1828 1828
                             } elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') {
1829 1829
                                 if ($this->debug) {
1830
-                                    echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT ' . $ptr . "\n";
1830
+                                    echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT '.$ptr."\n";
1831 1831
                                 }
1832 1832
                                 break 2;
1833 1833
                             } elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
1834 1834
                                 if ($this->debug) {
1835
-                                    echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT ' . $ptr . "\n";
1835
+                                    echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT '.$ptr."\n";
1836 1836
                                 }
1837 1837
                                 break 2;
1838 1838
                             }
1839 1839
 
1840 1840
                             if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") {
1841
-                                ++ $ptr;
1841
+                                ++$ptr;
1842 1842
                             } else {
1843 1843
                                 break;
1844 1844
                             }
1845 1845
                         }
1846 1846
 
1847 1847
                         if ($this->debug) {
1848
-                            echo 'FUNC START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
1848
+                            echo 'FUNC START PARAM PARSING WITH POINTER AT '.$ptr."\n";
1849 1849
                         }
1850 1850
 
1851 1851
                         if ($func === 'if' || $func === 'elseif' || $func === 'tif') {
@@ -1857,7 +1857,7 @@  discard block
 block discarded – undo
1857 1857
                         }
1858 1858
 
1859 1859
                         if ($this->debug) {
1860
-                            echo 'PARAM PARSED, POINTER AT ' . $ptr . ' (' . substr($paramstr, $ptr - 1, 3) . ')' . "\n";
1860
+                            echo 'PARAM PARSED, POINTER AT '.$ptr.' ('.substr($paramstr, $ptr-1, 3).')'."\n";
1861 1861
                         }
1862 1862
                     }
1863 1863
                 }
@@ -1881,16 +1881,16 @@  discard block
 block discarded – undo
1881 1881
         }
1882 1882
 
1883 1883
         if ($pointer !== null) {
1884
-            $pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0);
1884
+            $pointer += (isset($paramstr) ? strlen($paramstr) : 0)+(')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1))+strlen($func)+(isset($whitespace) ? $whitespace : 0);
1885 1885
             if ($this->debug) {
1886
-                echo 'FUNC ADDS ' . ((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)) . ' TO POINTER' . "\n";
1886
+                echo 'FUNC ADDS '.((isset($paramstr) ? strlen($paramstr) : 0)+(')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1))+strlen($func)).' TO POINTER'."\n";
1887 1887
             }
1888 1888
         }
1889 1889
 
1890 1890
         if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) {
1891 1891
             // handle static method calls with security policy
1892 1892
             if (strstr($func, '::') !== false && $this->securityPolicy !== null && $this->securityPolicy->isMethodAllowed(explode('::', strtolower($func))) !== true) {
1893
-                throw new SecurityException('Call to a disallowed php function : ' . $func);
1893
+                throw new SecurityException('Call to a disallowed php function : '.$func);
1894 1894
             }
1895 1895
             $pluginType = Core::NATIVE_PLUGIN;
1896 1896
         } else {
@@ -1935,19 +1935,19 @@  discard block
 block discarded – undo
1935 1935
                     $this->customPlugins[$func]['function']
1936 1936
                 ), $state);
1937 1937
             } else {
1938
-                if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
1938
+                if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
1939 1939
                     $params = $this->mapParams($params, array(
1940
-                        'Plugin' . Core::toCamelCase($func),
1940
+                        'Plugin'.Core::toCamelCase($func),
1941 1941
                         ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1942 1942
                     ), $state);
1943
-                } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
1943
+                } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func)) !== false) {
1944 1944
                     $params = $this->mapParams($params, array(
1945
-                        Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func),
1945
+                        Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func),
1946 1946
                         ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1947 1947
                     ), $state);
1948 1948
                 } else {
1949 1949
                     $params = $this->mapParams($params, array(
1950
-                        Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
1950
+                        Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func),
1951 1951
                         ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1952 1952
                     ), $state);
1953 1953
                 }
@@ -1958,24 +1958,22 @@  discard block
 block discarded – undo
1958 1958
                 $params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state);
1959 1959
             } else {
1960 1960
                 // Custom plugin
1961
-                if (function_exists('Plugin' . Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ?
1961
+                if (function_exists('Plugin'.Core::toCamelCase($func).(($pluginType & Core::COMPILABLE_PLUGIN) ?
1962 1962
                         'Compile' : '')) !== false) {
1963
-                    $params = $this->mapParams($params, 'Plugin' . Core::toCamelCase($func) . (($pluginType &
1963
+                    $params = $this->mapParams($params, 'Plugin'.Core::toCamelCase($func).(($pluginType &
1964 1964
                             Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1965 1965
                 } // Builtin helper plugin
1966
-                elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . (
1966
+                elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).(
1967 1967
                     ($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '')) !== false) {
1968
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase
1969
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1968
+                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).(($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1970 1969
                 } // Builtin function plugin
1971 1970
                 else {
1972
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
1973
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1971
+                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).(($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1974 1972
                 }
1975 1973
             }
1976 1974
         } // Smarty modifier
1977 1975
         elseif ($pluginType & Core::SMARTY_MODIFIER) {
1978
-            $output = 'smarty_modifier_' . $func . '(' . implode(', ', $params) . ')';
1976
+            $output = 'smarty_modifier_'.$func.'('.implode(', ', $params).')';
1979 1977
         } // Proxy plugin
1980 1978
         elseif ($pluginType & Core::PROXY_PLUGIN) {
1981 1979
             $params = $this->mapParams($params, $this->getCore()->getPluginProxy()->getCallback($func), $state);
@@ -2015,19 +2013,19 @@  discard block
 block discarded – undo
2015 2013
             if ($func === 'do') {
2016 2014
                 $output = '';
2017 2015
                 if (isset($params['*'])) {
2018
-                    $output = implode(';', $params['*']) . ';';
2016
+                    $output = implode(';', $params['*']).';';
2019 2017
                 }
2020 2018
 
2021 2019
                 if (is_array($parsingParams) || $curBlock !== 'root') {
2022 2020
                     throw new CompilationException($this, 'Do can not be used inside another function or block');
2023 2021
                 }
2024 2022
 
2025
-                return self::PHP_OPEN . $output . self::PHP_CLOSE;
2023
+                return self::PHP_OPEN.$output.self::PHP_CLOSE;
2026 2024
             } else {
2027 2025
                 if (isset($params['*'])) {
2028
-                    $output = $func . '(' . implode(', ', $params['*']) . ')';
2026
+                    $output = $func.'('.implode(', ', $params['*']).')';
2029 2027
                 } else {
2030
-                    $output = $func . '()';
2028
+                    $output = $func.'()';
2031 2029
                 }
2032 2030
             }
2033 2031
         } // Block class OR Function class
@@ -2037,7 +2035,7 @@  discard block
 block discarded – undo
2037 2035
                     $callback = $this->customPlugins[$func]['callback'];
2038 2036
                     if (!is_array($callback)) {
2039 2037
                         if (!method_exists($callback, 'compile')) {
2040
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2038
+                            throw new Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2041 2039
                         }
2042 2040
                         if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
2043 2041
                             $funcCompiler = array($callback, 'compile');
@@ -2048,13 +2046,13 @@  discard block
 block discarded – undo
2048 2046
                         $funcCompiler = $callback;
2049 2047
                     }
2050 2048
                 } else {
2051
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2052
-                        $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
2053
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2054
-                        $funcCompiler = array(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func), 'compile');
2049
+                    if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
2050
+                        $funcCompiler = array('Plugin'.Core::toCamelCase($func), 'compile');
2051
+                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func)) !== false) {
2052
+                        $funcCompiler = array(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func), 'compile');
2055 2053
                     } else {
2056 2054
                         $funcCompiler = array(
2057
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
2055
+                            Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func),
2058 2056
                             'compile'
2059 2057
                         );
2060 2058
                     }
@@ -2071,34 +2069,34 @@  discard block
 block discarded – undo
2071 2069
                     $callback = $this->customPlugins[$func]['callback'];
2072 2070
                     if (!is_array($callback)) {
2073 2071
                         if (!method_exists($callback, 'process')) {
2074
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2072
+                            throw new Exception('Custom plugin '.$func.' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2075 2073
                         }
2076 2074
                         if (is_object($callback)) {
2077 2075
                             $callback = get_class($callback);
2078 2076
                         }
2079 2077
                         if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
2080
-                            $output = 'call_user_func(array(\'' . $callback . '\', \'process\'), ' . $params . ')';
2078
+                            $output = 'call_user_func(array(\''.$callback.'\', \'process\'), '.$params.')';
2081 2079
                         } else {
2082
-                            $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback . '\'), \'process\'), ' . $params . ')';
2080
+                            $output = 'call_user_func(array($this->getObjectPlugin(\''.$callback.'\'), \'process\'), '.$params.')';
2083 2081
                         }
2084 2082
                     } elseif (is_object($callback[0])) {
2085
-                        $output = 'call_user_func(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), ' . $params . ')';
2083
+                        $output = 'call_user_func(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), '.$params.')';
2086 2084
                     } elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) {
2087
-                        $output = 'call_user_func(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), ' . $params . ')';
2085
+                        $output = 'call_user_func(array(\''.$callback[0].'\', \''.$callback[1].'\'), '.$params.')';
2088 2086
                     } else {
2089
-                        $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback[0] . '\'), \'' . $callback[1] . '\'), ' . $params . ')';
2087
+                        $output = 'call_user_func(array($this->getObjectPlugin(\''.$callback[0].'\'), \''.$callback[1].'\'), '.$params.')';
2090 2088
                     }
2091 2089
                     if (empty($params)) {
2092
-                        $output = substr($output, 0, - 3) . ')';
2090
+                        $output = substr($output, 0, - 3).')';
2093 2091
                     }
2094 2092
                 } else {
2095
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2096
-                        $output = '$this->classCall(\'Plugin' . $func . '\', array(' . $params . '))';
2097
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2098
-                        $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\',
2099
-                        array(' . $params . '))';
2093
+                    if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
2094
+                        $output = '$this->classCall(\'Plugin'.$func.'\', array('.$params.'))';
2095
+                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func)) !== false) {
2096
+                        $output = '$this->classCall(\''.Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.$func.'\',
2097
+                        array(' . $params.'))';
2100 2098
                     } else {
2101
-                        $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
2099
+                        $output = '$this->classCall(\''.$func.'\', array('.$params.'))';
2102 2100
                     }
2103 2101
                 }
2104 2102
             }
@@ -2109,15 +2107,15 @@  discard block
 block discarded – undo
2109 2107
                     $funcCompiler = $this->customPlugins[$func]['callback'];
2110 2108
                 } else {
2111 2109
                     // Custom plugin
2112
-                    if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2113
-                        $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
2110
+                    if (function_exists('Plugin'.Core::toCamelCase($func).'Compile') !== false) {
2111
+                        $funcCompiler = 'Plugin'.Core::toCamelCase($func).'Compile';
2114 2112
                     } // Builtin helper plugin
2115
-                    elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2116
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2113
+                    elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).'Compile') !== false) {
2114
+                        $funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).
2117 2115
                             'Compile';
2118 2116
                     } // Builtin function plugin
2119 2117
                     else {
2120
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
2118
+                        $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).
2121 2119
                             'Compile';
2122 2120
                     }
2123 2121
                 }
@@ -2133,24 +2131,24 @@  discard block
 block discarded – undo
2133 2131
                 if ($pluginType & Core::CUSTOM_PLUGIN) {
2134 2132
                     $callback = $this->customPlugins[$func]['callback'];
2135 2133
                     if ($callback instanceof Closure) {
2136
-                        $output = 'call_user_func($this->getCustomPlugin(\'' . $func . '\'), ' . $params . ')';
2134
+                        $output = 'call_user_func($this->getCustomPlugin(\''.$func.'\'), '.$params.')';
2137 2135
                     } else {
2138
-                        $output = 'call_user_func(\'' . $callback . '\', ' . $params . ')';
2136
+                        $output = 'call_user_func(\''.$callback.'\', '.$params.')';
2139 2137
                     }
2140 2138
                 } else {
2141 2139
                     // Custom plugin
2142
-                    if (function_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2143
-                        $output = 'Plugin' . Core::toCamelCase($func) . '(' . $params .
2140
+                    if (function_exists('Plugin'.Core::toCamelCase($func)) !== false) {
2141
+                        $output = 'Plugin'.Core::toCamelCase($func).'('.$params.
2144 2142
                             ')';
2145 2143
                     } // Builtin helper plugin
2146
-                    elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !==
2144
+                    elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func)) !==
2147 2145
                         false) {
2148
-                        $output = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . '(' .
2149
-                            $params . ')';
2146
+                        $output = Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($func).'('.
2147
+                            $params.')';
2150 2148
                     } // Builtin function plugin
2151 2149
                     else {
2152
-                        $output = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '(' .
2153
-                            $params . ')';
2150
+                        $output = Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).'('.
2151
+                            $params.')';
2154 2152
                     }
2155 2153
                 }
2156 2154
             }
@@ -2168,22 +2166,22 @@  discard block
 block discarded – undo
2168 2166
                 $callback = $this->customPlugins[$func]['callback'];
2169 2167
                 if (is_array($callback)) {
2170 2168
                     if (is_object($callback[0])) {
2171
-                        $output = 'call_user_func_array(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2169
+                        $output = 'call_user_func_array(array($this->getCustomPlugin(\''.$func.'\'), \''.$callback[1].'\'), array(array('.$params.'), $this))';
2172 2170
                     } else {
2173
-                        $output = 'call_user_func_array(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2171
+                        $output = 'call_user_func_array(array(\''.$callback[0].'\', \''.$callback[1].'\'), array(array('.$params.'), $this))';
2174 2172
                     }
2175 2173
                 } else {
2176
-                    $output = $callback . '(array(' . $params . '), $this)';
2174
+                    $output = $callback.'(array('.$params.'), $this)';
2177 2175
                 }
2178 2176
             } else {
2179
-                $output = 'smarty_function_' . $func . '(array(' . $params . '), $this)';
2177
+                $output = 'smarty_function_'.$func.'(array('.$params.'), $this)';
2180 2178
             }
2181 2179
         } // Template plugin
2182 2180
         elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
2183 2181
             array_unshift($params, '$this');
2184 2182
             $params                                 = self::implode_r($params);
2185
-            $output                                 = 'Plugin' . Core::toCamelCase($func) .
2186
-                $this->templatePlugins[$func]['uuid'] . '(' . $params . ')';
2183
+            $output                                 = 'Plugin'.Core::toCamelCase($func).
2184
+                $this->templatePlugins[$func]['uuid'].'('.$params.')';
2187 2185
             $this->templatePlugins[$func]['called'] = true;
2188 2186
         }
2189 2187
 
@@ -2215,29 +2213,29 @@  discard block
 block discarded – undo
2215 2213
      */
2216 2214
     protected function parseString($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2217 2215
     {
2218
-        $substr = substr($in, $from, $to - $from);
2216
+        $substr = substr($in, $from, $to-$from);
2219 2217
         $first  = $substr[0];
2220 2218
 
2221 2219
         if ($this->debug) {
2222
-            echo 'STRING FOUND (in ' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . ')' . "\n";
2220
+            echo 'STRING FOUND (in '.htmlentities(substr($in, $from, min($to-$from, 50))).(($to-$from) > 50 ? '...' : '').')'."\n";
2223 2221
         }
2224 2222
         $strend = false;
2225
-        $o      = $from + 1;
2223
+        $o      = $from+1;
2226 2224
         while ($strend === false) {
2227 2225
             $strend = strpos($in, $first, $o);
2228 2226
             if ($strend === false) {
2229
-                throw new CompilationException($this, 'Unfinished string, started with ' . substr($in, $from, $to - $from));
2227
+                throw new CompilationException($this, 'Unfinished string, started with '.substr($in, $from, $to-$from));
2230 2228
             }
2231
-            if (substr($in, $strend - 1, 1) === '\\') {
2232
-                $o      = $strend + 1;
2229
+            if (substr($in, $strend-1, 1) === '\\') {
2230
+                $o      = $strend+1;
2233 2231
                 $strend = false;
2234 2232
             }
2235 2233
         }
2236 2234
         if ($this->debug) {
2237
-            echo 'STRING DELIMITED: ' . substr($in, $from, $strend + 1 - $from) . "\n";
2235
+            echo 'STRING DELIMITED: '.substr($in, $from, $strend+1-$from)."\n";
2238 2236
         }
2239 2237
 
2240
-        $srcOutput = substr($in, $from, $strend + 1 - $from);
2238
+        $srcOutput = substr($in, $from, $strend+1-$from);
2241 2239
 
2242 2240
         if ($pointer !== null) {
2243 2241
             $pointer += strlen($srcOutput);
@@ -2246,13 +2244,13 @@  discard block
 block discarded – undo
2246 2244
         $output = $this->replaceStringVars($srcOutput, $first);
2247 2245
 
2248 2246
         // handle modifiers
2249
-        if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend + 1 - $from), $match)) {
2247
+        if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend+1-$from), $match)) {
2250 2248
             $modstr = $match[1];
2251 2249
 
2252 2250
             if ($curBlock === 'root' && substr($modstr, - 1) === '}') {
2253 2251
                 $modstr = substr($modstr, 0, - 1);
2254 2252
             }
2255
-            $modstr = str_replace('\\' . $first, $first, $modstr);
2253
+            $modstr = str_replace('\\'.$first, $first, $modstr);
2256 2254
             $ptr    = 0;
2257 2255
             $output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr);
2258 2256
 
@@ -2260,7 +2258,7 @@  discard block
 block discarded – undo
2260 2258
             if ($pointer !== null) {
2261 2259
                 $pointer += $ptr;
2262 2260
             }
2263
-            $srcOutput .= substr($substr, $strend + 1 - $from, $ptr);
2261
+            $srcOutput .= substr($substr, $strend+1-$from, $ptr);
2264 2262
         }
2265 2263
 
2266 2264
         if (is_array($parsingParams)) {
@@ -2291,10 +2289,10 @@  discard block
 block discarded – undo
2291 2289
      */
2292 2290
     protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2293 2291
     {
2294
-        $substr = substr($in, $from, $to - $from);
2292
+        $substr = substr($in, $from, $to-$from);
2295 2293
 
2296 2294
         if ($this->debug) {
2297
-            echo 'CONST FOUND : ' . $substr . "\n";
2295
+            echo 'CONST FOUND : '.$substr."\n";
2298 2296
         }
2299 2297
 
2300 2298
         if (!preg_match('#^%([\\\\a-z0-9_:]+)#i', $substr, $m)) {
@@ -2335,7 +2333,7 @@  discard block
 block discarded – undo
2335 2333
         }
2336 2334
 
2337 2335
         if ($curBlock !== 'root') {
2338
-            return '(defined("' . $key . '") ? ' . $key . ' : null)';
2336
+            return '(defined("'.$key.'") ? '.$key.' : null)';
2339 2337
         }
2340 2338
 
2341 2339
         return $key;
@@ -2358,7 +2356,7 @@  discard block
 block discarded – undo
2358 2356
      */
2359 2357
     protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2360 2358
     {
2361
-        $substr = substr($in, $from, $to - $from);
2359
+        $substr = substr($in, $from, $to-$from);
2362 2360
 
2363 2361
         // var key
2364 2362
         $varRegex = '(\\$?\\.?[a-z0-9\\\\_:]*(?:(?:(?:\\.|->)(?:[a-z0-9\\\\_:]+|(?R))|\\[(?:[a-z0-9\\\\_:]+|(?R)|(["\'])[^\\2]*?\\2)\\]))*)';
@@ -2386,13 +2384,13 @@  discard block
 block discarded – undo
2386 2384
 
2387 2385
             if (substr($key, - 1) == '.') {
2388 2386
                 $key = substr($key, 0, - 1);
2389
-                -- $matchedLength;
2387
+                --$matchedLength;
2390 2388
             }
2391 2389
 
2392 2390
             if ($hasMethodCall) {
2393
-                $matchedLength -= strlen($match[3]) + strlen(substr($match[1], strrpos($match[1], '->')));
2394
-                $key        = substr($match[1], 1, strrpos($match[1], '->') - 1);
2395
-                $methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3];
2391
+                $matchedLength -= strlen($match[3])+strlen(substr($match[1], strrpos($match[1], '->')));
2392
+                $key        = substr($match[1], 1, strrpos($match[1], '->')-1);
2393
+                $methodCall = substr($match[1], strrpos($match[1], '->')).$match[3];
2396 2394
             }
2397 2395
 
2398 2396
             if ($hasModifiers) {
@@ -2408,9 +2406,9 @@  discard block
 block discarded – undo
2408 2406
 
2409 2407
             if ($this->debug) {
2410 2408
                 if ($hasMethodCall) {
2411
-                    echo 'METHOD CALL FOUND : $' . $key . substr($methodCall, 0, 30) . "\n";
2409
+                    echo 'METHOD CALL FOUND : $'.$key.substr($methodCall, 0, 30)."\n";
2412 2410
                 } else {
2413
-                    echo 'VAR FOUND : $' . $key . "\n";
2411
+                    echo 'VAR FOUND : $'.$key."\n";
2414 2412
                 }
2415 2413
             }
2416 2414
 
@@ -2421,7 +2419,7 @@  discard block
 block discarded – undo
2421 2419
                 $uid           = 0;
2422 2420
                 $parsed        = array($uid => '');
2423 2421
                 $current       = &$parsed;
2424
-                $curTxt        = &$parsed[$uid ++];
2422
+                $curTxt        = &$parsed[$uid++];
2425 2423
                 $tree          = array();
2426 2424
                 $chars         = str_split($key, 1);
2427 2425
                 $inSplittedVar = false;
@@ -2430,33 +2428,33 @@  discard block
 block discarded – undo
2430 2428
                 while (($char = array_shift($chars)) !== null) {
2431 2429
                     if ($char === '[') {
2432 2430
                         if (count($tree) > 0) {
2433
-                            ++ $bracketCount;
2431
+                            ++$bracketCount;
2434 2432
                         } else {
2435 2433
                             $tree[]        = &$current;
2436
-                            $current[$uid] = array($uid + 1 => '');
2437
-                            $current       = &$current[$uid ++];
2438
-                            $curTxt        = &$current[$uid ++];
2434
+                            $current[$uid] = array($uid+1 => '');
2435
+                            $current       = &$current[$uid++];
2436
+                            $curTxt        = &$current[$uid++];
2439 2437
                             continue;
2440 2438
                         }
2441 2439
                     } elseif ($char === ']') {
2442 2440
                         if ($bracketCount > 0) {
2443
-                            -- $bracketCount;
2441
+                            --$bracketCount;
2444 2442
                         } else {
2445
-                            $current = &$tree[count($tree) - 1];
2443
+                            $current = &$tree[count($tree)-1];
2446 2444
                             array_pop($tree);
2447 2445
                             if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') {
2448 2446
                                 $current[$uid] = '';
2449
-                                $curTxt        = &$current[$uid ++];
2447
+                                $curTxt        = &$current[$uid++];
2450 2448
                             }
2451 2449
                             continue;
2452 2450
                         }
2453 2451
                     } elseif ($char === '$') {
2454 2452
                         if (count($tree) == 0) {
2455
-                            $curTxt        = &$current[$uid ++];
2453
+                            $curTxt        = &$current[$uid++];
2456 2454
                             $inSplittedVar = true;
2457 2455
                         }
2458 2456
                     } elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) {
2459
-                        $curTxt        = &$current[$uid ++];
2457
+                        $curTxt        = &$current[$uid++];
2460 2458
                         $inSplittedVar = false;
2461 2459
                     }
2462 2460
 
@@ -2465,16 +2463,16 @@  discard block
 block discarded – undo
2465 2463
                 unset($uid, $current, $curTxt, $tree, $chars);
2466 2464
 
2467 2465
                 if ($this->debug) {
2468
-                    echo 'RECURSIVE VAR REPLACEMENT : ' . $key . "\n";
2466
+                    echo 'RECURSIVE VAR REPLACEMENT : '.$key."\n";
2469 2467
                 }
2470 2468
 
2471 2469
                 $key = $this->flattenVarTree($parsed);
2472 2470
 
2473 2471
                 if ($this->debug) {
2474
-                    echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2472
+                    echo 'RECURSIVE VAR REPLACEMENT DONE : '.$key."\n";
2475 2473
                 }
2476 2474
 
2477
-                $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("' . $key . '")');
2475
+                $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("'.$key.'")');
2478 2476
             } else {
2479 2477
                 $output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock);
2480 2478
             }
@@ -2499,10 +2497,10 @@  discard block
 block discarded – undo
2499 2497
                     if (substr($expMatch[2][$k], 0, 1) === '=') {
2500 2498
                         $assign = true;
2501 2499
                         if ($operator === '=') {
2502
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, can not use "==" in expressions');
2500
+                            throw new CompilationException($this, 'Invalid expression <em>'.$substr.'</em>, can not use "==" in expressions');
2503 2501
                         }
2504 2502
                         if ($curBlock !== 'root') {
2505
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2503
+                            throw new CompilationException($this, 'Invalid expression <em>'.$substr.'</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2506 2504
                         }
2507 2505
                         $operator .= '=';
2508 2506
                         $expMatch[2][$k] = substr($expMatch[2][$k], 1);
@@ -2513,22 +2511,22 @@  discard block
 block discarded – undo
2513 2511
                         $expMatch[2][$k] = substr($expMatch[2][$k], 1);
2514 2512
                     }
2515 2513
                     if (($operator === '+' || $operator === '-') && $expMatch[2][$k] === $operator) {
2516
-                        $output = '(' . $output . $operator . $operator . ')';
2514
+                        $output = '('.$output.$operator.$operator.')';
2517 2515
                         break;
2518 2516
                     } elseif (substr($expMatch[2][$k], 0, 1) === '$') {
2519
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2517
+                        $output = '('.$output.' '.$operator.' '.$this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression').')';
2520 2518
                     } elseif (substr($expMatch[2][$k], 0, 1) === '%') {
2521
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2519
+                        $output = '('.$output.' '.$operator.' '.$this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression').')';
2522 2520
                     } elseif (!empty($expMatch[2][$k])) {
2523
-                        $output = '(' . $output . ' ' . $operator . ' ' . str_replace(',', '.', $expMatch[2][$k]) . ')';
2521
+                        $output = '('.$output.' '.$operator.' '.str_replace(',', '.', $expMatch[2][$k]).')';
2524 2522
                     } else {
2525
-                        throw new CompilationException($this, 'Unfinished expression <em>' . $substr . '</em>, missing var or number after math operator');
2523
+                        throw new CompilationException($this, 'Unfinished expression <em>'.$substr.'</em>, missing var or number after math operator');
2526 2524
                     }
2527 2525
                 }
2528 2526
             }
2529 2527
 
2530 2528
             if ($this->autoEscape === true && $curBlock !== 'condition') {
2531
-                $output = '(is_string($tmp=' . $output . ') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2529
+                $output = '(is_string($tmp='.$output.') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2532 2530
             }
2533 2531
 
2534 2532
             // handle modifiers
@@ -2552,7 +2550,7 @@  discard block
 block discarded – undo
2552 2550
             } elseif ($curBlock === 'expression' || $curBlock === 'variable') {
2553 2551
                 return $output;
2554 2552
             } elseif (isset($assign)) {
2555
-                return self::PHP_OPEN . $output . ';' . self::PHP_CLOSE;
2553
+                return self::PHP_OPEN.$output.';'.self::PHP_CLOSE;
2556 2554
             }
2557 2555
 
2558 2556
             return $output;
@@ -2560,7 +2558,7 @@  discard block
 block discarded – undo
2560 2558
             if ($curBlock === 'string' || $curBlock === 'delimited_string') {
2561 2559
                 return array(0, '');
2562 2560
             }
2563
-            throw new CompilationException($this, 'Invalid variable name <em>' . $substr . '</em>');
2561
+            throw new CompilationException($this, 'Invalid variable name <em>'.$substr.'</em>');
2564 2562
         }
2565 2563
     }
2566 2564
 
@@ -2614,16 +2612,16 @@  discard block
 block discarded – undo
2614 2612
             if (empty($methMatch[2])) {
2615 2613
                 // property
2616 2614
                 if ($curBlock === 'root') {
2617
-                    $output .= '->' . $methMatch[1];
2615
+                    $output .= '->'.$methMatch[1];
2618 2616
                 } else {
2619
-                    $output = '(($tmp = ' . $output . ') ? $tmp->' . $methMatch[1] . ' : null)';
2617
+                    $output = '(($tmp = '.$output.') ? $tmp->'.$methMatch[1].' : null)';
2620 2618
                 }
2621 2619
                 $ptr += strlen($methMatch[1]);
2622 2620
             } else {
2623 2621
                 // method
2624 2622
                 if (substr($methMatch[2], 0, 2) === '()') {
2625
-                    $parsedCall = $methMatch[1] . '()';
2626
-                    $ptr += strlen($methMatch[1]) + 2;
2623
+                    $parsedCall = $methMatch[1].'()';
2624
+                    $ptr += strlen($methMatch[1])+2;
2627 2625
                 } else {
2628 2626
                     $parsedCall = $this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr);
2629 2627
                 }
@@ -2632,15 +2630,15 @@  discard block
 block discarded – undo
2632 2630
                     $method = strtolower(substr($parsedCall, 0, $argPos));
2633 2631
                     $args   = substr($parsedCall, $argPos);
2634 2632
                     if ($curBlock === 'root') {
2635
-                        $output = '$this->getSecurityPolicy()->callMethod($this, ' . $output . ', ' . var_export($method, true) . ', array' . $args . ')';
2633
+                        $output = '$this->getSecurityPolicy()->callMethod($this, '.$output.', '.var_export($method, true).', array'.$args.')';
2636 2634
                     } else {
2637
-                        $output = '(($tmp = ' . $output . ') ? $this->getSecurityPolicy()->callMethod($this, $tmp, ' . var_export($method, true) . ', array' . $args . ') : null)';
2635
+                        $output = '(($tmp = '.$output.') ? $this->getSecurityPolicy()->callMethod($this, $tmp, '.var_export($method, true).', array'.$args.') : null)';
2638 2636
                     }
2639 2637
                 } else {
2640 2638
                     if ($curBlock === 'root') {
2641
-                        $output .= '->' . $parsedCall;
2639
+                        $output .= '->'.$parsedCall;
2642 2640
                     } else {
2643
-                        $output = '(($tmp = ' . $output . ') ? $tmp->' . $parsedCall . ' : null)';
2641
+                        $output = '(($tmp = '.$output.') ? $tmp->'.$parsedCall.' : null)';
2644 2642
                     }
2645 2643
                 }
2646 2644
             }
@@ -2666,21 +2664,21 @@  discard block
 block discarded – undo
2666 2664
             return '$this->scope';
2667 2665
         }
2668 2666
         if (substr($key, 0, 1) === '.') {
2669
-            $key = 'dwoo' . $key;
2667
+            $key = 'dwoo'.$key;
2670 2668
         }
2671 2669
         if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) {
2672 2670
             $global = strtoupper($m[1]);
2673 2671
             if ($global === 'COOKIES') {
2674 2672
                 $global = 'COOKIE';
2675 2673
             }
2676
-            $key = '$_' . $global;
2674
+            $key = '$_'.$global;
2677 2675
             foreach (explode('.', ltrim($m[2], '.')) as $part) {
2678
-                $key .= '[' . var_export($part, true) . ']';
2676
+                $key .= '['.var_export($part, true).']';
2679 2677
             }
2680 2678
             if ($curBlock === 'root') {
2681 2679
                 $output = $key;
2682 2680
             } else {
2683
-                $output = '(isset(' . $key . ')?' . $key . ':null)';
2681
+                $output = '(isset('.$key.')?'.$key.':null)';
2684 2682
             }
2685 2683
         } elseif (preg_match('#dwoo\\.const\\.([a-z0-9\\\\_:]+)#i', $key, $m)) {
2686 2684
             return $this->parseConstKey($m[1], $curBlock);
@@ -2696,9 +2694,9 @@  discard block
 block discarded – undo
2696 2694
                     $output = '$tmp_key';
2697 2695
                 } else {
2698 2696
                     if ($curBlock === 'root') {
2699
-                        $output = '$this->scope["' . $key . '"]';
2697
+                        $output = '$this->scope["'.$key.'"]';
2700 2698
                     } else {
2701
-                        $output = '(isset($this->scope["' . $key . '"]) ? $this->scope["' . $key . '"] : null)';
2699
+                        $output = '(isset($this->scope["'.$key.'"]) ? $this->scope["'.$key.'"] : null)';
2702 2700
                     }
2703 2701
                 }
2704 2702
             } else {
@@ -2709,7 +2707,7 @@  discard block
 block discarded – undo
2709 2707
                     $parentCnt = 0;
2710 2708
 
2711 2709
                     while (true) {
2712
-                        ++ $parentCnt;
2710
+                        ++$parentCnt;
2713 2711
                         array_shift($m[2]);
2714 2712
                         array_shift($m[1]);
2715 2713
                         if (current($m[2]) === '_parent') {
@@ -2718,7 +2716,7 @@  discard block
 block discarded – undo
2718 2716
                         break;
2719 2717
                     }
2720 2718
 
2721
-                    $output = '$this->readParentVar(' . $parentCnt . ')';
2719
+                    $output = '$this->readParentVar('.$parentCnt.')';
2722 2720
                 } else {
2723 2721
                     if ($i === 'dwoo') {
2724 2722
                         $output = '$this->globals';
@@ -2737,28 +2735,28 @@  discard block
 block discarded – undo
2737 2735
                     while (count($m[1]) && $m[1][0] !== '->') {
2738 2736
                         $m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]);
2739 2737
                         if (substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") {
2740
-                            $output .= '[' . $m[2][0] . ']';
2738
+                            $output .= '['.$m[2][0].']';
2741 2739
                         } else {
2742
-                            $output .= '["' . $m[2][0] . '"]';
2740
+                            $output .= '["'.$m[2][0].'"]';
2743 2741
                         }
2744 2742
                         array_shift($m[2]);
2745 2743
                         array_shift($m[1]);
2746 2744
                     }
2747 2745
 
2748 2746
                     if ($curBlock !== 'root') {
2749
-                        $output = '(isset(' . $output . ') ? ' . $output . ':null)';
2747
+                        $output = '(isset('.$output.') ? '.$output.':null)';
2750 2748
                     }
2751 2749
                 }
2752 2750
 
2753 2751
                 if (count($m[2])) {
2754 2752
                     unset($m[0]);
2755
-                    $output = '$this->readVarInto(' . str_replace("\n", '', var_export($m, true)) . ', ' . $output . ', ' . ($curBlock == 'root' ? 'false' : 'true') . ')';
2753
+                    $output = '$this->readVarInto('.str_replace("\n", '', var_export($m, true)).', '.$output.', '.($curBlock == 'root' ? 'false' : 'true').')';
2756 2754
                 }
2757 2755
             }
2758 2756
         } else {
2759 2757
             preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m);
2760 2758
             unset($m[0]);
2761
-            $output = '$this->readVar(' . str_replace("\n", '', var_export($m, true)) . ')';
2759
+            $output = '$this->readVar('.str_replace("\n", '', var_export($m, true)).')';
2762 2760
         }
2763 2761
 
2764 2762
         return $output;
@@ -2778,38 +2776,38 @@  discard block
 block discarded – undo
2778 2776
         $out = $recursed ? '".$this->readVarInto(' : '';
2779 2777
         foreach ($tree as $bit) {
2780 2778
             if (is_array($bit)) {
2781
-                $out .= '.' . $this->flattenVarTree($bit, false);
2779
+                $out .= '.'.$this->flattenVarTree($bit, false);
2782 2780
             } else {
2783 2781
                 $key = str_replace('"', '\\"', $bit);
2784 2782
 
2785 2783
                 if (substr($key, 0, 1) === '$') {
2786
-                    $out .= '".' . $this->parseVar($key, 0, strlen($key), false, 'variable') . '."';
2784
+                    $out .= '".'.$this->parseVar($key, 0, strlen($key), false, 'variable').'."';
2787 2785
                 } else {
2788 2786
                     $cnt = substr_count($key, '$');
2789 2787
 
2790 2788
                     if ($this->debug) {
2791
-                        echo 'PARSING SUBVARS IN : ' . $key . "\n";
2789
+                        echo 'PARSING SUBVARS IN : '.$key."\n";
2792 2790
                     }
2793 2791
                     if ($cnt > 0) {
2794
-                        while (-- $cnt >= 0) {
2792
+                        while (--$cnt >= 0) {
2795 2793
                             if (isset($last)) {
2796
-                                $last = strrpos($key, '$', - (strlen($key) - $last + 1));
2794
+                                $last = strrpos($key, '$', - (strlen($key)-$last+1));
2797 2795
                             } else {
2798 2796
                                 $last = strrpos($key, '$');
2799 2797
                             }
2800
-                            preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2798
+                            preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*'.'((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2801 2799
 
2802 2800
                             $len = strlen($submatch[0]);
2803 2801
                             $key = substr_replace(
2804 2802
                                 $key, preg_replace_callback(
2805
-                                    '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2803
+                                    '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)'.'((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2806 2804
                                         $this,
2807 2805
                                         'replaceVarKeyHelper'
2808 2806
                                     ), substr($key, $last, $len)
2809 2807
                                 ), $last, $len
2810 2808
                             );
2811 2809
                             if ($this->debug) {
2812
-                                echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2810
+                                echo 'RECURSIVE VAR REPLACEMENT DONE : '.$key."\n";
2813 2811
                             }
2814 2812
                         }
2815 2813
                         unset($last);
@@ -2835,7 +2833,7 @@  discard block
 block discarded – undo
2835 2833
      */
2836 2834
     protected function replaceVarKeyHelper($match)
2837 2835
     {
2838
-        return '".' . $this->parseVar($match[0], 0, strlen($match[0]), false, 'variable') . '."';
2836
+        return '".'.$this->parseVar($match[0], 0, strlen($match[0]), false, 'variable').'."';
2839 2837
     }
2840 2838
 
2841 2839
     /**
@@ -2855,7 +2853,7 @@  discard block
 block discarded – undo
2855 2853
      */
2856 2854
     protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2857 2855
     {
2858
-        $substr = substr($in, $from, $to - $from);
2856
+        $substr = substr($in, $from, $to-$from);
2859 2857
 
2860 2858
         $end = strlen($substr);
2861 2859
 
@@ -2929,48 +2927,48 @@  discard block
 block discarded – undo
2929 2927
 
2930 2928
         if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') {
2931 2929
             if ($this->debug) {
2932
-                echo 'BOOLEAN(FALSE) PARSED' . "\n";
2930
+                echo 'BOOLEAN(FALSE) PARSED'."\n";
2933 2931
             }
2934 2932
             $substr = 'false';
2935 2933
             $type   = self::T_BOOL;
2936 2934
         } elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') {
2937 2935
             if ($this->debug) {
2938
-                echo 'BOOLEAN(TRUE) PARSED' . "\n";
2936
+                echo 'BOOLEAN(TRUE) PARSED'."\n";
2939 2937
             }
2940 2938
             $substr = 'true';
2941 2939
             $type   = self::T_BOOL;
2942 2940
         } elseif ($substr === 'null' || $substr === 'NULL') {
2943 2941
             if ($this->debug) {
2944
-                echo 'NULL PARSED' . "\n";
2942
+                echo 'NULL PARSED'."\n";
2945 2943
             }
2946 2944
             $substr = 'null';
2947 2945
             $type   = self::T_NULL;
2948 2946
         } elseif (is_numeric($substr)) {
2949
-            $substr = (float)$substr;
2950
-            if ((int)$substr == $substr) {
2951
-                $substr = (int)$substr;
2947
+            $substr = (float) $substr;
2948
+            if ((int) $substr == $substr) {
2949
+                $substr = (int) $substr;
2952 2950
             }
2953 2951
             $type = self::T_NUMERIC;
2954 2952
             if ($this->debug) {
2955
-                echo 'NUMBER (' . $substr . ') PARSED' . "\n";
2953
+                echo 'NUMBER ('.$substr.') PARSED'."\n";
2956 2954
             }
2957 2955
         } elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) {
2958 2956
             if ($this->debug) {
2959 2957
                 echo 'SIMPLE MATH PARSED . "\n"';
2960 2958
             }
2961 2959
             $type   = self::T_MATH;
2962
-            $substr = '(' . $substr . ')';
2960
+            $substr = '('.$substr.')';
2963 2961
         } elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) {
2964 2962
             if ($this->debug) {
2965
-                echo 'BREAKCHAR (' . $substr . ') PARSED' . "\n";
2963
+                echo 'BREAKCHAR ('.$substr.') PARSED'."\n";
2966 2964
             }
2967 2965
             $type = self::T_BREAKCHAR;
2968 2966
             //$substr = '"'.$substr.'"';
2969 2967
         } else {
2970
-            $substr = $this->replaceStringVars('\'' . str_replace('\'', '\\\'', $substr) . '\'', '\'', $curBlock);
2968
+            $substr = $this->replaceStringVars('\''.str_replace('\'', '\\\'', $substr).'\'', '\'', $curBlock);
2971 2969
             $type   = self::T_UNQUOTED_STRING;
2972 2970
             if ($this->debug) {
2973
-                echo 'BLABBER (' . $substr . ') CASTED AS STRING' . "\n";
2971
+                echo 'BLABBER ('.$substr.') CASTED AS STRING'."\n";
2974 2972
             }
2975 2973
         }
2976 2974
 
@@ -3000,28 +2998,28 @@  discard block
 block discarded – undo
3000 2998
     {
3001 2999
         $pos = 0;
3002 3000
         if ($this->debug) {
3003
-            echo 'STRING VAR REPLACEMENT : ' . $string . "\n";
3001
+            echo 'STRING VAR REPLACEMENT : '.$string."\n";
3004 3002
         }
3005 3003
         // replace vars
3006 3004
         while (($pos = strpos($string, '$', $pos)) !== false) {
3007
-            $prev = substr($string, $pos - 1, 1);
3005
+            $prev = substr($string, $pos-1, 1);
3008 3006
             if ($prev === '\\') {
3009
-                ++ $pos;
3007
+                ++$pos;
3010 3008
                 continue;
3011 3009
             }
3012 3010
 
3013 3011
             $var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3014 3012
             $len = $var[0];
3015
-            $var = $this->parse(str_replace('\\' . $first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3013
+            $var = $this->parse(str_replace('\\'.$first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3016 3014
 
3017
-            if ($prev === '`' && substr($string, $pos + $len, 1) === '`') {
3018
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos - 1, $len + 2);
3015
+            if ($prev === '`' && substr($string, $pos+$len, 1) === '`') {
3016
+                $string = substr_replace($string, $first.'.'.$var[1].'.'.$first, $pos-1, $len+2);
3019 3017
             } else {
3020
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos, $len);
3018
+                $string = substr_replace($string, $first.'.'.$var[1].'.'.$first, $pos, $len);
3021 3019
             }
3022
-            $pos += strlen($var[1]) + 2;
3020
+            $pos += strlen($var[1])+2;
3023 3021
             if ($this->debug) {
3024
-                echo 'STRING VAR REPLACEMENT DONE : ' . $string . "\n";
3022
+                echo 'STRING VAR REPLACEMENT DONE : '.$string."\n";
3025 3023
             }
3026 3024
         }
3027 3025
 
@@ -3057,7 +3055,7 @@  discard block
 block discarded – undo
3057 3055
     protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null)
3058 3056
     {
3059 3057
         if ($this->debug) {
3060
-            echo 'PARSING MODIFIERS : ' . $m[3] . "\n";
3058
+            echo 'PARSING MODIFIERS : '.$m[3]."\n";
3061 3059
         }
3062 3060
 
3063 3061
         if ($pointer !== null) {
@@ -3081,7 +3079,7 @@  discard block
 block discarded – undo
3081 3079
             }
3082 3080
             if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) {
3083 3081
                 if ($this->debug) {
3084
-                    echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND' . "\n";
3082
+                    echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND'."\n";
3085 3083
                 }
3086 3084
                 $continue = false;
3087 3085
                 if ($pointer !== null) {
@@ -3092,7 +3090,7 @@  discard block
 block discarded – undo
3092 3090
             $cmdstr   = $cmdstrsrc;
3093 3091
             $paramsep = ':';
3094 3092
             if (!preg_match('/^(@{0,2}[a-z_][a-z0-9_]*)(:)?/i', $cmdstr, $match)) {
3095
-                throw new CompilationException($this, 'Invalid modifier name, started with : ' . substr($cmdstr, 0, 10));
3093
+                throw new CompilationException($this, 'Invalid modifier name, started with : '.substr($cmdstr, 0, 10));
3096 3094
             }
3097 3095
             $paramspos = !empty($match[2]) ? strlen($match[1]) : false;
3098 3096
             $func      = $match[1];
@@ -3102,10 +3100,10 @@  discard block
 block discarded – undo
3102 3100
                 $cmdstrsrc = substr($cmdstrsrc, strlen($func));
3103 3101
                 $params    = array();
3104 3102
                 if ($this->debug) {
3105
-                    echo 'MODIFIER (' . $func . ') CALLED WITH NO PARAMS' . "\n";
3103
+                    echo 'MODIFIER ('.$func.') CALLED WITH NO PARAMS'."\n";
3106 3104
                 }
3107 3105
             } else {
3108
-                $paramstr = substr($cmdstr, $paramspos + 1);
3106
+                $paramstr = substr($cmdstr, $paramspos+1);
3109 3107
                 if (substr($paramstr, - 1, 1) === $paramsep) {
3110 3108
                     $paramstr = substr($paramstr, 0, - 1);
3111 3109
                 }
@@ -3114,41 +3112,41 @@  discard block
 block discarded – undo
3114 3112
                 $params = array();
3115 3113
                 while ($ptr < strlen($paramstr)) {
3116 3114
                     if ($this->debug) {
3117
-                        echo 'MODIFIER (' . $func . ') START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
3115
+                        echo 'MODIFIER ('.$func.') START PARAM PARSING WITH POINTER AT '.$ptr."\n";
3118 3116
                     }
3119 3117
                     if ($this->debug) {
3120
-                        echo $paramstr . '--' . $ptr . '--' . strlen($paramstr) . '--modifier' . "\n";
3118
+                        echo $paramstr.'--'.$ptr.'--'.strlen($paramstr).'--modifier'."\n";
3121 3119
                     }
3122 3120
                     $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr);
3123 3121
                     if ($this->debug) {
3124
-                        echo 'PARAM PARSED, POINTER AT ' . $ptr . "\n";
3122
+                        echo 'PARAM PARSED, POINTER AT '.$ptr."\n";
3125 3123
                     }
3126 3124
 
3127 3125
                     if ($ptr >= strlen($paramstr)) {
3128 3126
                         if ($this->debug) {
3129
-                            echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED' . "\n";
3127
+                            echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED'."\n";
3130 3128
                         }
3131 3129
                         break;
3132 3130
                     }
3133 3131
 
3134 3132
                     if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
3135 3133
                         if ($this->debug) {
3136
-                            echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT ' . $ptr . "\n";
3134
+                            echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT '.$ptr."\n";
3137 3135
                         }
3138 3136
                         if ($paramstr[$ptr] !== '|') {
3139 3137
                             $continue = false;
3140 3138
                             if ($pointer !== null) {
3141
-                                $pointer -= strlen($paramstr) - $ptr;
3139
+                                $pointer -= strlen($paramstr)-$ptr;
3142 3140
                             }
3143 3141
                         }
3144
-                        ++ $ptr;
3142
+                        ++$ptr;
3145 3143
                         break;
3146 3144
                     }
3147 3145
                     if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') {
3148
-                        ++ $ptr;
3146
+                        ++$ptr;
3149 3147
                     }
3150 3148
                 }
3151
-                $cmdstrsrc = substr($cmdstrsrc, strlen($func) + 1 + $ptr);
3149
+                $cmdstrsrc = substr($cmdstrsrc, strlen($func)+1+$ptr);
3152 3150
                 foreach ($params as $k => $p) {
3153 3151
                     if (is_array($p) && is_array($p[1])) {
3154 3152
                         $state |= 2;
@@ -3188,9 +3186,9 @@  discard block
 block discarded – undo
3188 3186
                 $params = self::implode_r($params);
3189 3187
 
3190 3188
                 if ($mapped) {
3191
-                    $output = '$this->arrayMap(\'' . $func . '\', array(' . $params . '))';
3189
+                    $output = '$this->arrayMap(\''.$func.'\', array('.$params.'))';
3192 3190
                 } else {
3193
-                    $output = $func . '(' . $params . ')';
3191
+                    $output = $func.'('.$params.')';
3194 3192
                 }
3195 3193
             } elseif ($pluginType & Core::PROXY_PLUGIN) {
3196 3194
                 $params = $this->mapParams($params, $this->getCore()->getPluginProxy()->getCallback($func), $state);
@@ -3208,19 +3206,19 @@  discard block
 block discarded – undo
3208 3206
                     $callback = $this->customPlugins[$func]['callback'];
3209 3207
                     if (is_array($callback)) {
3210 3208
                         if (is_object($callback[0])) {
3211
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(' . $params . '))';
3209
+                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->getCustomPlugin(\''.$func.'\'), \''.$callback[1].'\'), array('.$params.'))';
3212 3210
                         } else {
3213
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3211
+                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))';
3214 3212
                         }
3215 3213
                     } elseif ($mapped) {
3216
-                        $output = '$this->arrayMap(\'' . $callback . '\', array(' . $params . '))';
3214
+                        $output = '$this->arrayMap(\''.$callback.'\', array('.$params.'))';
3217 3215
                     } else {
3218
-                        $output = $callback . '(' . $params . ')';
3216
+                        $output = $callback.'('.$params.')';
3219 3217
                     }
3220 3218
                 } elseif ($mapped) {
3221
-                    $output = '$this->arrayMap(\'smarty_modifier_' . $func . '\', array(' . $params . '))';
3219
+                    $output = '$this->arrayMap(\'smarty_modifier_'.$func.'\', array('.$params.'))';
3222 3220
                 } else {
3223
-                    $output = 'smarty_modifier_' . $func . '(' . $params . ')';
3221
+                    $output = 'smarty_modifier_'.$func.'('.$params.')';
3224 3222
                 }
3225 3223
             } else {
3226 3224
                 if ($pluginType & Core::CUSTOM_PLUGIN) {
@@ -3230,17 +3228,17 @@  discard block
 block discarded – undo
3230 3228
                         $callback   = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3231 3229
                     }
3232 3230
                 } else {
3233
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false || function_exists('Plugin' .
3234
-                            Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3231
+                    if (class_exists('Plugin'.Core::toCamelCase($func)) !== false || function_exists('Plugin'.
3232
+                            Core::toCamelCase($func).(($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3235 3233
                         !== false) {
3236
-                        $pluginName = 'Plugin' . Core::toCamelCase($func);
3234
+                        $pluginName = 'Plugin'.Core::toCamelCase($func);
3237 3235
                     } else {
3238
-                        $pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func);
3236
+                        $pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func);
3239 3237
                     }
3240 3238
                     if ($pluginType & Core::CLASS_PLUGIN) {
3241 3239
                         $callback = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3242 3240
                     } else {
3243
-                        $callback = $pluginName . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3241
+                        $callback = $pluginName.(($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3244 3242
                     }
3245 3243
                 }
3246 3244
                 $params = $this->mapParams($params, $callback, $state);
@@ -3258,10 +3256,10 @@  discard block
 block discarded – undo
3258 3256
                         if ($pluginType & Core::CUSTOM_PLUGIN) {
3259 3257
                             $funcCompiler = $this->customPlugins[$func]['callback'];
3260 3258
                         } else {
3261
-                            if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
3262
-                                $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
3259
+                            if (function_exists('Plugin'.Core::toCamelCase($func).'Compile') !== false) {
3260
+                                $funcCompiler = 'Plugin'.Core::toCamelCase($func).'Compile';
3263 3261
                             } else {
3264
-                                $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
3262
+                                $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).
3265 3263
                                     'Compile';
3266 3264
                             }
3267 3265
                         }
@@ -3272,9 +3270,9 @@  discard block
 block discarded – undo
3272 3270
 
3273 3271
                         $params = self::implode_r($params);
3274 3272
                         if ($mapped) {
3275
-                            $output = '$this->arrayMap(\'' . $pluginName . '\', array(' . $params . '))';
3273
+                            $output = '$this->arrayMap(\''.$pluginName.'\', array('.$params.'))';
3276 3274
                         } else {
3277
-                            $output = $pluginName . '(' . $params . ')';
3275
+                            $output = $pluginName.'('.$params.')';
3278 3276
                         }
3279 3277
                     }
3280 3278
                 } else {
@@ -3286,7 +3284,7 @@  discard block
 block discarded – undo
3286 3284
                             $callback = $this->customPlugins[$func]['callback'];
3287 3285
                             if (!is_array($callback)) {
3288 3286
                                 if (!method_exists($callback, 'compile')) {
3289
-                                    throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3287
+                                    throw new Exception('Custom plugin '.$func.' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3290 3288
                                 }
3291 3289
                                 if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
3292 3290
                                     $funcCompiler = array($callback, 'compile');
@@ -3297,10 +3295,10 @@  discard block
 block discarded – undo
3297 3295
                                 $funcCompiler = $callback;
3298 3296
                             }
3299 3297
                         } else {
3300
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3301
-                                $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
3298
+                            if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
3299
+                                $funcCompiler = array('Plugin'.Core::toCamelCase($func), 'compile');
3302 3300
                             } else {
3303
-                                $funcCompiler = array(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func), 'compile');
3301
+                                $funcCompiler = array(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func), 'compile');
3304 3302
                             }
3305 3303
                             array_unshift($params, $this);
3306 3304
                         }
@@ -3311,26 +3309,26 @@  discard block
 block discarded – undo
3311 3309
                         if ($pluginType & Core::CUSTOM_PLUGIN) {
3312 3310
                             if (is_object($callback[0])) {
3313 3311
                                 if (is_array($this->getCore()->getCustomPlugin($func))) {
3314
-                                    $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3312
+                                    $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->plugins[\''.$func.'\'][\'callback\'][0], \''.$callback[1].'\'), array('.$params.'))';
3315 3313
                                 } else {
3316
-                                    $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(' . $params . '))';
3314
+                                    $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array($this->getCustomPlugin(\''.$func.'\'), \''.$callback[1].'\'), array('.$params.'))';
3317 3315
                                 }
3318 3316
                             } else {
3319
-                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3317
+                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array').'(array(\''.$callback[0].'\', \''.$callback[1].'\'), array('.$params.'))';
3320 3318
                             }
3321 3319
                         } elseif ($mapped) {
3322 3320
                             $output = '$this->arrayMap(array($this->getObjectPlugin(\''.
3323
-                                Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '\'),
3324
-                            \'process\'), array(' . $params . '))';
3321
+                                Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func).'\'),
3322
+                            \'process\'), array(' . $params.'))';
3325 3323
                         } else {
3326
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3327
-                                $output = '$this->classCall(\'Plugin' . Core::toCamelCase($func) . '\', array(' . $params . '))';
3328
-                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3329
-                                $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . $func . '\', array(' . $params . '))';
3330
-                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3331
-                                $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', array(' . $params . '))';
3324
+                            if (class_exists('Plugin'.Core::toCamelCase($func)) !== false) {
3325
+                                $output = '$this->classCall(\'Plugin'.Core::toCamelCase($func).'\', array('.$params.'))';
3326
+                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($func)) !== false) {
3327
+                                $output = '$this->classCall(\''.Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.$func.'\', array('.$params.'))';
3328
+                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($func)) !== false) {
3329
+                                $output = '$this->classCall(\''.Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.$func.'\', array('.$params.'))';
3332 3330
                             } else {
3333
-                                $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
3331
+                                $output = '$this->classCall(\''.$func.'\', array('.$params.'))';
3334 3332
                             }
3335 3333
                         }
3336 3334
                     }
@@ -3343,7 +3341,7 @@  discard block
 block discarded – undo
3343 3341
         } elseif ($curBlock === 'var' || $m[1] === null) {
3344 3342
             return $output;
3345 3343
         } elseif ($curBlock === 'string' || $curBlock === 'root') {
3346
-            return $m[1] . '.' . $output . '.' . $m[1] . (isset($add) ? $add : null);
3344
+            return $m[1].'.'.$output.'.'.$m[1].(isset($add) ? $add : null);
3347 3345
         }
3348 3346
 
3349 3347
         return '';
@@ -3366,14 +3364,14 @@  discard block
 block discarded – undo
3366 3364
             if (is_array($p)) {
3367 3365
                 $out2 = 'array(';
3368 3366
                 foreach ($p as $k2 => $v) {
3369
-                    $out2 .= var_export($k2, true) . ' => ' . (is_array($v) ? 'array(' . self::implode_r($v, true) . ')' : $v) . ', ';
3367
+                    $out2 .= var_export($k2, true).' => '.(is_array($v) ? 'array('.self::implode_r($v, true).')' : $v).', ';
3370 3368
                 }
3371
-                $p = rtrim($out2, ', ') . ')';
3369
+                $p = rtrim($out2, ', ').')';
3372 3370
             }
3373 3371
             if ($recursiveCall) {
3374
-                $out .= var_export($k, true) . ' => ' . $p . ', ';
3372
+                $out .= var_export($k, true).' => '.$p.', ';
3375 3373
             } else {
3376
-                $out .= $p . ', ';
3374
+                $out .= $p.', ';
3377 3375
             }
3378 3376
         }
3379 3377
 
@@ -3397,7 +3395,7 @@  discard block
 block discarded – undo
3397 3395
         if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || ($this->securityPolicy !== null && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
3398 3396
             $phpFunc = true;
3399 3397
         } elseif ($this->securityPolicy !== null && function_exists($name) && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) === false) {
3400
-            throw new SecurityException('Call to a disallowed php function : ' . $name);
3398
+            throw new SecurityException('Call to a disallowed php function : '.$name);
3401 3399
         }
3402 3400
 
3403 3401
         while ($pluginType <= 0) {
@@ -3408,61 +3406,61 @@  discard block
 block discarded – undo
3408 3406
             elseif (isset($this->customPlugins[$name])) {
3409 3407
                 $pluginType = $this->customPlugins[$name]['type'] | Core::CUSTOM_PLUGIN;
3410 3408
             } // Class blocks plugin
3411
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3409
+            elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($name)) !== false) {
3412 3410
                 $pluginType = Core::CLASS_PLUGIN;
3413
-                if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3411
+                if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3414 3412
                     $pluginType += Core::BLOCK_PLUGIN;
3415 3413
                 }
3416
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name));
3414
+                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.Core::toCamelCase($name));
3417 3415
                 if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3418 3416
                     $pluginType |= Core::COMPILABLE_PLUGIN;
3419 3417
                 }
3420 3418
             } // Class functions plugin
3421
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3422
-                $pluginType = Core::FUNC_PLUGIN + Core::CLASS_PLUGIN;
3423
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name));
3419
+            elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($name)) !== false) {
3420
+                $pluginType = Core::FUNC_PLUGIN+Core::CLASS_PLUGIN;
3421
+                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($name));
3424 3422
                 if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3425 3423
                     $pluginType |= Core::COMPILABLE_PLUGIN;
3426 3424
                 }
3427 3425
             } // Class without namespace
3428
-            elseif (class_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3426
+            elseif (class_exists('Plugin'.Core::toCamelCase($name)) !== false) {
3429 3427
                 $pluginType = Core::CLASS_PLUGIN;
3430
-                if (is_subclass_of('Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3428
+                if (is_subclass_of('Plugin'.Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3431 3429
                     $pluginType += Core::BLOCK_PLUGIN;
3432 3430
                 }
3433
-                $interfaces = class_implements('Plugin' . Core::toCamelCase($name));
3431
+                $interfaces = class_implements('Plugin'.Core::toCamelCase($name));
3434 3432
                 if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3435 3433
                     $pluginType |= Core::COMPILABLE_PLUGIN;
3436 3434
                 }
3437 3435
             } // Function plugin (with/without namespaces)
3438
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase ($name)) !==
3439
-                false || function_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3436
+            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($name)) !==
3437
+                false || function_exists('Plugin'.Core::toCamelCase($name)) !== false) {
3440 3438
                 $pluginType = Core::FUNC_PLUGIN;
3441 3439
             } // Function plugin compile (with/without namespaces)
3442
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name) .
3443
-                    'Compile') !== false || function_exists('Plugin' . Core::toCamelCase($name) . 'Compile') !==
3440
+            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin'.Core::toCamelCase($name).
3441
+                    'Compile') !== false || function_exists('Plugin'.Core::toCamelCase($name).'Compile') !==
3444 3442
                 false) {
3445 3443
                 $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3446 3444
             } // Helper plugin class compile
3447
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3445
+            elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($name)) !== false) {
3448 3446
                 $pluginType = Core::CLASS_PLUGIN | Core::COMPILABLE_PLUGIN;
3449 3447
             } // Helper plugin function compile
3450
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name) . 'Compile') !== false) {
3448
+            elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS.'Plugin'.Core::toCamelCase($name).'Compile') !== false) {
3451 3449
                 $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3452 3450
             } // Smarty modifier
3453
-            elseif (function_exists('smarty_modifier_' . $name) !== false) {
3451
+            elseif (function_exists('smarty_modifier_'.$name) !== false) {
3454 3452
                 $pluginType = Core::SMARTY_MODIFIER;
3455 3453
             } // Smarty function
3456
-            elseif (function_exists('smarty_function_' . $name) !== false) {
3454
+            elseif (function_exists('smarty_function_'.$name) !== false) {
3457 3455
                 $pluginType = Core::SMARTY_FUNCTION;
3458 3456
             } // Smarty block
3459
-            elseif (function_exists('smarty_block_' . $name) !== false) {
3457
+            elseif (function_exists('smarty_block_'.$name) !== false) {
3460 3458
                 $pluginType = Core::SMARTY_BLOCK;
3461 3459
             } // Everything else
3462 3460
             else {
3463 3461
                 if ($pluginType === - 1) {
3464 3462
                     try {
3465
-                        $this->getCore()->getLoader()->loadPlugin('Plugin' . Core::toCamelCase($name));
3463
+                        $this->getCore()->getLoader()->loadPlugin('Plugin'.Core::toCamelCase($name));
3466 3464
                     }
3467 3465
                     catch (Exception $e) {
3468 3466
                         if (isset($phpFunc)) {
@@ -3475,9 +3473,9 @@  discard block
 block discarded – undo
3475 3473
                         }
3476 3474
                     }
3477 3475
                 } else {
3478
-                    throw new Exception('Plugin "' . $name . '" could not be found, type:' . $pluginType);
3476
+                    throw new Exception('Plugin "'.$name.'" could not be found, type:'.$pluginType);
3479 3477
                 }
3480
-                ++ $pluginType;
3478
+                ++$pluginType;
3481 3479
             }
3482 3480
         }
3483 3481
 
@@ -3546,15 +3544,15 @@  discard block
 block discarded – undo
3546 3544
         }
3547 3545
 
3548 3546
         // loops over the param map and assigns values from the template or default value for unset optional params
3549
-        foreach ($map as $k => $v){
3547
+        foreach ($map as $k => $v) {
3550 3548
             if ($v[0] === '*') {
3551 3549
                 // "rest" array parameter, fill every remaining params in it and then break
3552 3550
                 if (count($ps) === 0) {
3553 3551
                     if ($v[1] === false) {
3554 3552
                         throw new CompilationException(
3555
-                            $this, 'Rest argument missing for ' . str_replace(
3553
+                            $this, 'Rest argument missing for '.str_replace(
3556 3554
                                 array(
3557
-                                    Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3555
+                                    Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin',
3558 3556
                                 'Compile'
3559 3557
                                 ), '', (is_array($callback) ? $callback[0] : $callback)
3560 3558
                             )
@@ -3587,7 +3585,7 @@  discard block
 block discarded – undo
3587 3585
                 // parameter is not defined and not optional, throw error
3588 3586
                 if (is_array($callback)) {
3589 3587
                     if (is_object($callback[0])) {
3590
-                        $name = get_class($callback[0]) . '::' . $callback[1];
3588
+                        $name = get_class($callback[0]).'::'.$callback[1];
3591 3589
                     } else {
3592 3590
                         $name = $callback[0];
3593 3591
                     }
@@ -3596,9 +3594,9 @@  discard block
 block discarded – undo
3596 3594
                 }
3597 3595
 
3598 3596
                 throw new CompilationException(
3599
-                    $this, 'Argument ' . $k . '/' . $v[0] . ' missing for ' . str_replace(
3597
+                    $this, 'Argument '.$k.'/'.$v[0].' missing for '.str_replace(
3600 3598
                         array(
3601
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3599
+                            Core::NAMESPACE_PLUGINS_FUNCTIONS.'Plugin',
3602 3600
                         'Compile'
3603 3601
                         ), '', $name
3604 3602
                     )
Please login to merge, or discard this patch.
Indentation   +3645 added lines, -3645 removed lines patch added patch discarded remove patch
@@ -31,3651 +31,3651 @@
 block discarded – undo
31 31
  */
32 32
 class Compiler implements ICompiler
33 33
 {
34
-    /**
35
-     * Constant that represents a php opening tag.
36
-     * use it in case it needs to be adjusted
37
-     *
38
-     * @var string
39
-     */
40
-    const PHP_OPEN = '<?php ';
41
-
42
-    /**
43
-     * Constant that represents a php closing tag.
44
-     * use it in case it needs to be adjusted
45
-     *
46
-     * @var string
47
-     */
48
-    const PHP_CLOSE = '?>';
49
-
50
-    /**
51
-     * Boolean flag to enable or disable debugging output.
52
-     *
53
-     * @var bool
54
-     */
55
-    public $debug = false;
56
-
57
-    /**
58
-     * Left script delimiter.
59
-     *
60
-     * @var string
61
-     */
62
-    protected $ld = '{';
63
-
64
-    /**
65
-     * Left script delimiter with escaped regex meta characters.
66
-     *
67
-     * @var string
68
-     */
69
-    protected $ldr = '\\{';
70
-
71
-    /**
72
-     * Right script delimiter.
73
-     *
74
-     * @var string
75
-     */
76
-    protected $rd = '}';
77
-
78
-    /**
79
-     * Right script delimiter with escaped regex meta characters.
80
-     *
81
-     * @var string
82
-     */
83
-    protected $rdr = '\\}';
84
-
85
-    /**
86
-     * Defines whether the nested comments should be parsed as nested or not.
87
-     * defaults to false (classic block comment parsing as in all languages)
88
-     *
89
-     * @var bool
90
-     */
91
-    protected $allowNestedComments = false;
92
-
93
-    /**
94
-     * Defines whether opening and closing tags can contain spaces before valid data or not.
95
-     * turn to true if you want to be sloppy with the syntax, but when set to false it allows
96
-     * to skip javascript and css tags as long as they are in the form "{ something", which is
97
-     * nice. default is false.
98
-     *
99
-     * @var bool
100
-     */
101
-    protected $allowLooseOpenings = false;
102
-
103
-    /**
104
-     * Defines whether the compiler will automatically html-escape variables or not.
105
-     * default is false
106
-     *
107
-     * @var bool
108
-     */
109
-    protected $autoEscape = false;
110
-
111
-    /**
112
-     * Security policy object.
113
-     *
114
-     * @var SecurityPolicy
115
-     */
116
-    protected $securityPolicy;
117
-
118
-    /**
119
-     * Stores the custom plugins registered with this compiler.
120
-     *
121
-     * @var array
122
-     */
123
-    protected $customPlugins = array();
124
-
125
-    /**
126
-     * Stores the template plugins registered with this compiler.
127
-     *
128
-     * @var array
129
-     */
130
-    protected $templatePlugins = array();
131
-
132
-    /**
133
-     * Stores the pre- and post-processors callbacks.
134
-     *
135
-     * @var array
136
-     */
137
-    protected $processors = array('pre' => array(), 'post' => array());
138
-
139
-    /**
140
-     * Stores a list of plugins that are used in the currently compiled
141
-     * template, and that are not compilable. these plugins will be loaded
142
-     * during the template's runtime if required.
143
-     * it is a 1D array formatted as key:pluginName value:pluginType
144
-     *
145
-     * @var array
146
-     */
147
-    protected $usedPlugins;
148
-
149
-    /**
150
-     * Stores the template undergoing compilation.
151
-     *
152
-     * @var string
153
-     */
154
-    protected $template;
155
-
156
-    /**
157
-     * Stores the current pointer position inside the template.
158
-     *
159
-     * @var int
160
-     */
161
-    protected $pointer;
162
-
163
-    /**
164
-     * Stores the current line count inside the template for debugging purposes.
165
-     *
166
-     * @var int
167
-     */
168
-    protected $line;
169
-
170
-    /**
171
-     * Stores the current template source while compiling it.
172
-     *
173
-     * @var string
174
-     */
175
-    protected $templateSource;
176
-
177
-    /**
178
-     * Stores the data within which the scope moves.
179
-     *
180
-     * @var array
181
-     */
182
-    protected $data;
183
-
184
-    /**
185
-     * Variable scope of the compiler, set to null if
186
-     * it can not be resolved to a static string (i.e. if some
187
-     * plugin defines a new scope based on a variable array key).
188
-     *
189
-     * @var mixed
190
-     */
191
-    protected $scope;
192
-
193
-    /**
194
-     * Variable scope tree, that allows to rebuild the current
195
-     * scope if required, i.e. when going to a parent level.
196
-     *
197
-     * @var array
198
-     */
199
-    protected $scopeTree;
200
-
201
-    /**
202
-     * Block plugins stack, accessible through some methods.
203
-     *
204
-     * @see findBlock
205
-     * @see getCurrentBlock
206
-     * @see addBlock
207
-     * @see addCustomBlock
208
-     * @see injectBlock
209
-     * @see removeBlock
210
-     * @see removeTopBlock
211
-     * @var array
212
-     */
213
-    protected $stack = array();
214
-
215
-    /**
216
-     * Current block at the top of the block plugins stack,
217
-     * accessible through getCurrentBlock.
218
-     *
219
-     * @see getCurrentBlock
220
-     * @var array
221
-     */
222
-    protected $curBlock;
223
-
224
-    /**
225
-     * Current dwoo object that uses this compiler, or null.
226
-     *
227
-     * @var Core
228
-     */
229
-    public $core;
230
-
231
-    /**
232
-     * Holds an instance of this class, used by getInstance when you don't
233
-     * provide a custom compiler in order to save resources.
234
-     *
235
-     * @var Compiler
236
-     */
237
-    protected static $instance;
238
-
239
-    /**
240
-     * Token types.
241
-     *
242
-     * @var int
243
-     */
244
-    const T_UNQUOTED_STRING = 1;
245
-    const T_NUMERIC         = 2;
246
-    const T_NULL            = 4;
247
-    const T_BOOL            = 8;
248
-    const T_MATH            = 16;
249
-    const T_BREAKCHAR       = 32;
250
-
251
-    /**
252
-     * Compiler constructor.
253
-     * saves the created instance so that child templates get the same one
254
-     */
255
-    public function __construct()
256
-    {
257
-        self::$instance = $this;
258
-    }
259
-
260
-    /**
261
-     * Sets the delimiters to use in the templates.
262
-     * delimiters can be multi-character strings but should not be one of those as they will
263
-     * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and
264
-     * finally "#" only if you intend to use config-vars with the #var# syntax.
265
-     *
266
-     * @param string $left  left delimiter
267
-     * @param string $right right delimiter
268
-     */
269
-    public function setDelimiters($left, $right)
270
-    {
271
-        $this->ld  = $left;
272
-        $this->rd  = $right;
273
-        $this->ldr = preg_quote($left, '/');
274
-        $this->rdr = preg_quote($right, '/');
275
-    }
276
-
277
-    /**
278
-     * Returns the left and right template delimiters.
279
-     *
280
-     * @return array containing the left and the right delimiters
281
-     */
282
-    public function getDelimiters()
283
-    {
284
-        return array($this->ld, $this->rd);
285
-    }
286
-
287
-    /**
288
-     * Sets the way to handle nested comments, if set to true
289
-     * {* foo {* some other *} comment *} will be stripped correctly.
290
-     * if false it will remove {* foo {* some other *} and leave "comment *}" alone,
291
-     * this is the default behavior
292
-     *
293
-     * @param bool $allow allow nested comments or not, defaults to true (but the default internal value is false)
294
-     */
295
-    public function setNestedCommentsHandling($allow = true)
296
-    {
297
-        $this->allowNestedComments = (bool)$allow;
298
-    }
299
-
300
-    /**
301
-     * Returns the nested comments handling setting.
302
-     *
303
-     * @see    setNestedCommentsHandling
304
-     * @return bool true if nested comments are allowed
305
-     */
306
-    public function getNestedCommentsHandling()
307
-    {
308
-        return $this->allowNestedComments;
309
-    }
310
-
311
-    /**
312
-     * Sets the tag openings handling strictness, if set to true, template tags can
313
-     * contain spaces before the first function/string/variable such as { $foo} is valid.
314
-     * if set to false (default setting), { $foo} is invalid but that is however a good thing
315
-     * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering
316
-     * an error, same goes for javascript.
317
-     *
318
-     * @param bool $allow true to allow loose handling, false to restore default setting
319
-     */
320
-    public function setLooseOpeningHandling($allow = false)
321
-    {
322
-        $this->allowLooseOpenings = (bool)$allow;
323
-    }
324
-
325
-    /**
326
-     * Returns the tag openings handling strictness setting.
327
-     *
328
-     * @see    setLooseOpeningHandling
329
-     * @return bool true if loose tags are allowed
330
-     */
331
-    public function getLooseOpeningHandling()
332
-    {
333
-        return $this->allowLooseOpenings;
334
-    }
335
-
336
-    /**
337
-     * Changes the auto escape setting.
338
-     * if enabled, the compiler will automatically html-escape variables,
339
-     * unless they are passed through the safe function such as {$var|safe}
340
-     * or {safe $var}
341
-     * default setting is disabled/false
342
-     *
343
-     * @param bool $enabled set to true to enable, false to disable
344
-     */
345
-    public function setAutoEscape($enabled)
346
-    {
347
-        $this->autoEscape = (bool)$enabled;
348
-    }
349
-
350
-    /**
351
-     * Returns the auto escape setting.
352
-     * default setting is disabled/false
353
-     *
354
-     * @return bool
355
-     */
356
-    public function getAutoEscape()
357
-    {
358
-        return $this->autoEscape;
359
-    }
360
-
361
-    /**
362
-     * Adds a preprocessor to the compiler, it will be called
363
-     * before the template is compiled.
364
-     *
365
-     * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to
366
-     *                        true
367
-     * @param bool  $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else
368
-     *                        you must provide a valid callback
369
-     */
370
-    public function addPreProcessor($callback, $autoload = false)
371
-    {
372
-        if ($autoload) {
373
-            $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', Core::toCamelCase($callback));
374
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . $name;
375
-
376
-            if (class_exists($class)) {
377
-                $callback = array(new $class($this), 'process');
378
-            } elseif (function_exists($class)) {
379
-                $callback = $class;
380
-            } else {
381
-                $callback = array('autoload' => true, 'class' => $class, 'name' => $name);
382
-            }
383
-
384
-            $this->processors['pre'][] = $callback;
385
-        } else {
386
-            $this->processors['pre'][] = $callback;
387
-        }
388
-    }
389
-
390
-    /**
391
-     * Removes a preprocessor from the compiler.
392
-     *
393
-     * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded
394
-     */
395
-    public function removePreProcessor($callback)
396
-    {
397
-        if (($index = array_search($callback, $this->processors['pre'], true)) !== false) {
398
-            unset($this->processors['pre'][$index]);
399
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
400
-                    $callback),
401
-                $this->processors['pre'], true)) !== false) {
402
-            unset($this->processors['pre'][$index]);
403
-        } else {
404
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
405
-            foreach ($this->processors['pre'] as $index => $proc) {
406
-                if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
407
-                    unset($this->processors['pre'][$index]);
408
-                    break;
409
-                }
410
-            }
411
-        }
412
-    }
413
-
414
-    /**
415
-     * Adds a postprocessor to the compiler, it will be called
416
-     * before the template is compiled.
417
-     *
418
-     * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to
419
-     *                        true
420
-     * @param bool  $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else
421
-     *                        you must provide a valid callback
422
-     */
423
-    public function addPostProcessor($callback, $autoload = false)
424
-    {
425
-        if ($autoload) {
426
-            $name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
427
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . Core::toCamelCase($name);
428
-
429
-            if (class_exists($class)) {
430
-                $callback = array(new $class($this), 'process');
431
-            } elseif (function_exists($class)) {
432
-                $callback = $class;
433
-            } else {
434
-                $callback = array('autoload' => true, 'class' => $class, 'name' => $name);
435
-            }
436
-
437
-            $this->processors['post'][] = $callback;
438
-        } else {
439
-            $this->processors['post'][] = $callback;
440
-        }
441
-    }
442
-
443
-    /**
444
-     * Removes a postprocessor from the compiler.
445
-     *
446
-     * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded
447
-     */
448
-    public function removePostProcessor($callback)
449
-    {
450
-        if (($index = array_search($callback, $this->processors['post'], true)) !== false) {
451
-            unset($this->processors['post'][$index]);
452
-        } elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
453
-                    $callback),
454
-                $this->processors['post'], true)) !== false) {
455
-            unset($this->processors['post'][$index]);
456
-        } else {
457
-            $class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
458
-            foreach ($this->processors['post'] as $index => $proc) {
459
-                if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
460
-                    unset($this->processors['post'][$index]);
461
-                    break;
462
-                }
463
-            }
464
-        }
465
-    }
466
-
467
-    /**
468
-     * Internal function to autoload processors at runtime if required.
469
-     *
470
-     * @param string $class the class/function name
471
-     * @param string $name  the plugin name (without Dwoo_Plugin_ prefix)
472
-     *
473
-     * @return array|string
474
-     * @throws Exception
475
-     */
476
-    protected function loadProcessor($class, $name)
477
-    {
478
-        if (!class_exists($class) && !function_exists($class)) {
479
-            try {
480
-                $this->getCore()->getLoader()->loadPlugin($name);
481
-            }
482
-            catch (Exception $e) {
483
-                throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
484
-            }
485
-        }
486
-
487
-        if (class_exists($class)) {
488
-            return array(new $class($this), 'process');
489
-        }
490
-
491
-        if (function_exists($class)) {
492
-            return $class;
493
-        }
494
-
495
-        throw new Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"');
496
-    }
497
-
498
-    /**
499
-     * Adds an used plugin, this is reserved for use by the {template} plugin.
500
-     * this is required so that plugin loading bubbles up from loaded
501
-     * template files to the current one
502
-     *
503
-     * @private
504
-     *
505
-     * @param string $name function name
506
-     * @param int    $type plugin type (Core::*_PLUGIN)
507
-     */
508
-    public function addUsedPlugin($name, $type)
509
-    {
510
-        $this->usedPlugins[$name] = $type;
511
-    }
512
-
513
-    /**
514
-     * Returns all the plugins this template uses.
515
-     *
516
-     * @private
517
-     * @return  array the list of used plugins in the parsed template
518
-     */
519
-    public function getUsedPlugins()
520
-    {
521
-        return $this->usedPlugins;
522
-    }
523
-
524
-    /**
525
-     * Adds a template plugin, this is reserved for use by the {template} plugin.
526
-     * this is required because the template functions are not declared yet
527
-     * during compilation, so we must have a way of validating their argument
528
-     * signature without using the reflection api
529
-     *
530
-     * @private
531
-     *
532
-     * @param string $name   function name
533
-     * @param array  $params parameter array to help validate the function call
534
-     * @param string $uuid   unique id of the function
535
-     * @param string $body   function php code
536
-     */
537
-    public function addTemplatePlugin($name, array $params, $uuid, $body = null)
538
-    {
539
-        $this->templatePlugins[$name] = array('params' => $params, 'body' => $body, 'uuid' => $uuid);
540
-    }
541
-
542
-    /**
543
-     * Returns all the parsed sub-templates.
544
-     *
545
-     * @private
546
-     * @return  array the parsed sub-templates
547
-     */
548
-    public function getTemplatePlugins()
549
-    {
550
-        return $this->templatePlugins;
551
-    }
552
-
553
-    /**
554
-     * Marks a template plugin as being called, which means its source must be included in the compiled template.
555
-     *
556
-     * @param string $name function name
557
-     */
558
-    public function useTemplatePlugin($name)
559
-    {
560
-        $this->templatePlugins[$name]['called'] = true;
561
-    }
562
-
563
-    /**
564
-     * Adds the custom plugins loaded into Dwoo to the compiler so it can load them.
565
-     *
566
-     * @see Core::addPlugin
567
-     *
568
-     * @param array $customPlugins an array of custom plugins
569
-     */
570
-    public function setCustomPlugins(array $customPlugins)
571
-    {
572
-        $this->customPlugins = $customPlugins;
573
-    }
574
-
575
-    /**
576
-     * Sets the security policy object to enforce some php security settings.
577
-     * use this if untrusted persons can modify templates,
578
-     * set it on the Dwoo object as it will be passed onto the compiler automatically
579
-     *
580
-     * @param SecurityPolicy $policy the security policy object
581
-     */
582
-    public function setSecurityPolicy(SecurityPolicy $policy = null)
583
-    {
584
-        $this->securityPolicy = $policy;
585
-    }
586
-
587
-    /**
588
-     * Returns the current security policy object or null by default.
589
-     *
590
-     * @return SecurityPolicy|null the security policy object if any
591
-     */
592
-    public function getSecurityPolicy()
593
-    {
594
-        return $this->securityPolicy;
595
-    }
596
-
597
-    /**
598
-     * Sets the pointer position.
599
-     *
600
-     * @param int  $position the new pointer position
601
-     * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
602
-     */
603
-    public function setPointer($position, $isOffset = false)
604
-    {
605
-        if ($isOffset) {
606
-            $this->pointer += $position;
607
-        } else {
608
-            $this->pointer = $position;
609
-        }
610
-    }
611
-
612
-    /**
613
-     * Returns the current pointer position, only available during compilation of a template.
614
-     *
615
-     * @return int
616
-     */
617
-    public function getPointer()
618
-    {
619
-        return $this->pointer;
620
-    }
621
-
622
-    /**
623
-     * Sets the line number.
624
-     *
625
-     * @param int  $number   the new line number
626
-     * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
627
-     */
628
-    public function setLine($number, $isOffset = false)
629
-    {
630
-        if ($isOffset) {
631
-            $this->line += $number;
632
-        } else {
633
-            $this->line = $number;
634
-        }
635
-    }
636
-
637
-    /**
638
-     * Returns the current line number, only available during compilation of a template.
639
-     *
640
-     * @return int
641
-     */
642
-    public function getLine()
643
-    {
644
-        return $this->line;
645
-    }
646
-
647
-    /**
648
-     * Returns the dwoo object that initiated this template compilation, only available during compilation of a
649
-     * template.
650
-     *
651
-     * @return Core
652
-     */
653
-    public function getCore()
654
-    {
655
-        return $this->core;
656
-    }
657
-
658
-    /**
659
-     * Overwrites the template that is being compiled.
660
-     *
661
-     * @param string $newSource   the template source that must replace the current one
662
-     * @param bool   $fromPointer if set to true, only the source from the current pointer position is replaced
663
-     *
664
-     * @return void
665
-     */
666
-    public function setTemplateSource($newSource, $fromPointer = false)
667
-    {
668
-        if ($fromPointer === true) {
669
-            $this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource;
670
-        } else {
671
-            $this->templateSource = $newSource;
672
-        }
673
-    }
674
-
675
-    /**
676
-     * Returns the template that is being compiled.
677
-     *
678
-     * @param mixed $fromPointer if set to true, only the source from the current pointer
679
-     *                           position is returned, if a number is given it overrides the current pointer
680
-     *
681
-     * @return string the template or partial template
682
-     */
683
-    public function getTemplateSource($fromPointer = false)
684
-    {
685
-        if ($fromPointer === true) {
686
-            return substr($this->templateSource, $this->pointer);
687
-        } elseif (is_numeric($fromPointer)) {
688
-            return substr($this->templateSource, $fromPointer);
689
-        } else {
690
-            return $this->templateSource;
691
-        }
692
-    }
693
-
694
-    /**
695
-     * Resets the compilation pointer, effectively restarting the compilation process.
696
-     * this is useful if a plugin modifies the template source since it might need to be recompiled
697
-     */
698
-    public function recompile()
699
-    {
700
-        $this->setPointer(0);
701
-    }
702
-
703
-    /**
704
-     * Compiles the provided string down to php code.
705
-     *
706
-     * @param Core      $core
707
-     * @param ITemplate $template the template to compile
708
-     *
709
-     * @return string a compiled php string
710
-     * @throws CompilationException
711
-     */
712
-    public function compile(Core $core, ITemplate $template)
713
-    {
714
-        // init vars
715
-        //		$compiled = '';
716
-        $tpl                  = $template->getSource();
717
-        $ptr                  = 0;
718
-        $this->core           = $core;
719
-        $this->template       = $template;
720
-        $this->templateSource = &$tpl;
721
-        $this->pointer        = &$ptr;
722
-
723
-        while (true) {
724
-            // if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed
725
-            if ($ptr === 0) {
726
-                // resets variables
727
-                $this->usedPlugins     = array();
728
-                $this->data            = array();
729
-                $this->scope           = &$this->data;
730
-                $this->scopeTree       = array();
731
-                $this->stack           = array();
732
-                $this->line            = 1;
733
-                $this->templatePlugins = array();
734
-                // add top level block
735
-                $compiled                 = $this->addBlock('TopLevelBlock', array(), 0);
736
-                $this->stack[0]['buffer'] = '';
737
-
738
-                if ($this->debug) {
739
-                    echo "\n";
740
-                    echo 'COMPILER INIT' . "\n";
741
-                }
742
-
743
-                if ($this->debug) {
744
-                    echo 'PROCESSING PREPROCESSORS (' . count($this->processors['pre']) . ')' . "\n";
745
-                }
746
-
747
-                // runs preprocessors
748
-                foreach ($this->processors['pre'] as $preProc) {
749
-                    if (is_array($preProc) && isset($preProc['autoload'])) {
750
-                        $preProc = $this->loadProcessor($preProc['class'], $preProc['name']);
751
-                    }
752
-                    if (is_array($preProc) && $preProc[0] instanceof Processor) {
753
-                        $tpl = call_user_func($preProc, $tpl);
754
-                    } else {
755
-                        $tpl = call_user_func($preProc, $this, $tpl);
756
-                    }
757
-                }
758
-                unset($preProc);
759
-
760
-                // show template source if debug
761
-                if ($this->debug) {
762
-                    echo '<pre>'.print_r(htmlentities($tpl), true).'</pre>'."\n";
763
-                }
764
-
765
-                // strips php tags if required by the security policy
766
-                if ($this->securityPolicy !== null) {
767
-                    $search = array('{<\?php.*?\?>}');
768
-                    if (ini_get('short_open_tags')) {
769
-                        $search = array('{<\?.*?\?>}', '{<%.*?%>}');
770
-                    }
771
-                    switch ($this->securityPolicy->getPhpHandling()) {
772
-                        case SecurityPolicy::PHP_ALLOW:
773
-                            break;
774
-                        case SecurityPolicy::PHP_ENCODE:
775
-                            $tpl = preg_replace_callback($search, array($this, 'phpTagEncodingHelper'), $tpl);
776
-                            break;
777
-                        case SecurityPolicy::PHP_REMOVE:
778
-                            $tpl = preg_replace($search, '', $tpl);
779
-                    }
780
-                }
781
-            }
782
-
783
-            $pos = strpos($tpl, $this->ld, $ptr);
784
-
785
-            if ($pos === false) {
786
-                $this->push(substr($tpl, $ptr), 0);
787
-                break;
788
-            } elseif (substr($tpl, $pos - 1, 1) === '\\' && substr($tpl, $pos - 2, 1) !== '\\') {
789
-                $this->push(substr($tpl, $ptr, $pos - $ptr - 1) . $this->ld);
790
-                $ptr = $pos + strlen($this->ld);
791
-            } elseif (preg_match('/^' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', substr($tpl, $pos), $litOpen)) {
792
-                if (!preg_match('/' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
793
-                    throw new CompilationException($this, 'The {literal} blocks must be closed explicitly with {/literal}');
794
-                }
795
-                $endpos = $litClose[0][1];
796
-                $this->push(substr($tpl, $ptr, $pos - $ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos - $pos - strlen($litOpen[0])));
797
-                $ptr = $endpos + strlen($litClose[0][0]);
798
-            } else {
799
-                if (substr($tpl, $pos - 2, 1) === '\\' && substr($tpl, $pos - 1, 1) === '\\') {
800
-                    $this->push(substr($tpl, $ptr, $pos - $ptr - 1));
801
-                    $ptr = $pos;
802
-                }
803
-
804
-                $this->push(substr($tpl, $ptr, $pos - $ptr));
805
-                $ptr = $pos;
806
-
807
-                $pos += strlen($this->ld);
808
-                if ($this->allowLooseOpenings) {
809
-                    while (substr($tpl, $pos, 1) === ' ') {
810
-                        $pos += 1;
811
-                    }
812
-                } else {
813
-                    if (substr($tpl, $pos, 1) === ' ' || substr($tpl, $pos, 1) === "\r" || substr($tpl, $pos, 1) === "\n" || substr($tpl, $pos, 1) === "\t") {
814
-                        $ptr = $pos;
815
-                        $this->push($this->ld);
816
-                        continue;
817
-                    }
818
-                }
819
-
820
-                // check that there is an end tag present
821
-                if (strpos($tpl, $this->rd, $pos) === false) {
822
-                    throw new CompilationException($this, 'A template tag was not closed, started with "' . substr($tpl, $ptr, 30) . '"');
823
-                }
824
-
825
-                $ptr += strlen($this->ld);
826
-                $subptr = $ptr;
827
-
828
-                while (true) {
829
-                    $parsed = $this->parse($tpl, $subptr, null, false, 'root', $subptr);
830
-
831
-                    // reload loop if the compiler was reset
832
-                    if ($ptr === 0) {
833
-                        continue 2;
834
-                    }
835
-
836
-                    $len = $subptr - $ptr;
837
-                    $this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n"));
838
-                    $ptr += $len;
839
-
840
-                    if ($parsed === false) {
841
-                        break;
842
-                    }
843
-                }
844
-            }
845
-        }
846
-
847
-        $compiled .= $this->removeBlock('TopLevelBlock');
848
-
849
-        if ($this->debug) {
850
-            echo 'PROCESSING POSTPROCESSORS' . "\n";
851
-        }
852
-
853
-        foreach ($this->processors['post'] as $postProc) {
854
-            if (is_array($postProc) && isset($postProc['autoload'])) {
855
-                $postProc = $this->loadProcessor($postProc['class'], $postProc['name']);
856
-            }
857
-            if (is_array($postProc) && $postProc[0] instanceof Processor) {
858
-                $compiled = call_user_func($postProc, $compiled);
859
-            } else {
860
-                $compiled = call_user_func($postProc, $this, $compiled);
861
-            }
862
-        }
863
-        unset($postProc);
864
-
865
-        if ($this->debug) {
866
-            echo 'COMPILATION COMPLETE : MEM USAGE : ' . memory_get_usage() . "\n";
867
-        }
868
-
869
-        $output = "<?php\n/* template head */\n";
870
-
871
-        // build plugin preloader
872
-        foreach ($this->getUsedPlugins() as $plugin => $type) {
873
-            if ($type & Core::CUSTOM_PLUGIN) {
874
-                continue;
875
-            }
876
-
877
-            switch ($type) {
878
-                case Core::CLASS_PLUGIN:
879
-                case Core::CLASS_PLUGIN + Core::BLOCK_PLUGIN:
880
-                    if (class_exists('Plugin' . $plugin) !== false) {
881
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
882
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
883
-                    } else {
884
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_BLOCKS . "Plugin" . $plugin . "')===false)".
885
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
886
-                    }
887
-                    break;
888
-                case Core::CLASS_PLUGIN + Core::FUNC_PLUGIN:
889
-                    if (class_exists('Plugin' . $plugin) !== false) {
890
-                        $output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
891
-                            "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
892
-                    } else {
893
-                        $output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
894
-                            "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
895
-                    }
896
-                    break;
897
-                case Core::FUNC_PLUGIN:
898
-                    if (function_exists('Plugin' . $plugin) !== false) {
899
-                        $output .= "if (function_exists('" . "Plugin" . $plugin . "')===false)".
900
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
901
-                    } else {
902
-                        $output .= "if (function_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
903
-                        "\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
904
-                    }
905
-                    break;
906
-                case Core::SMARTY_MODIFIER:
907
-                    $output .= "if (function_exists('smarty_modifier_$plugin')===false)".
908
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
909
-                    break;
910
-                case Core::SMARTY_FUNCTION:
911
-                    $output .= "if (function_exists('smarty_function_$plugin')===false)".
912
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
913
-                    break;
914
-                case Core::SMARTY_BLOCK:
915
-                    $output .= "if (function_exists('smarty_block_$plugin')===false)".
916
-                    "\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
917
-                    break;
918
-                case Core::PROXY_PLUGIN:
919
-                    $output .= $this->getCore()->getPluginProxy()->getLoader($plugin);
920
-                    break;
921
-                default:
922
-                    throw new CompilationException($this, 'Type error for ' . $plugin . ' with type' . $type);
923
-            }
924
-        }
925
-
926
-        foreach ($this->templatePlugins as $function => $attr) {
927
-            if (isset($attr['called']) && $attr['called'] === true && !isset($attr['checked'])) {
928
-                $this->resolveSubTemplateDependencies($function);
929
-            }
930
-        }
931
-        foreach ($this->templatePlugins as $function) {
932
-            if (isset($function['called']) && $function['called'] === true) {
933
-                $output .= $function['body'] . PHP_EOL;
934
-            }
935
-        }
936
-
937
-        $output .= $compiled . "\n?>";
938
-
939
-        $output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*' . preg_quote(self::PHP_CLOSE, '/') . preg_quote(self::PHP_OPEN, '/') . ')/', ";\n", $output);
940
-        $output = str_replace(self::PHP_CLOSE . self::PHP_OPEN, "\n", $output);
941
-
942
-        // handle <?xml tag at the beginning
943
-        $output = preg_replace('#(/\* template body \*/ \?>\s*)<\?xml#is', '$1<?php echo \'<?xml\'; ?>', $output);
944
-
945
-        // add another line break after PHP closing tags that have a line break following,
946
-        // as we do not know whether it's intended, and PHP will strip it otherwise
947
-        $output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0' . "\n", $output);
948
-
949
-        if ($this->debug) {
950
-            echo '=============================================================================================' . "\n";
951
-            $lines = preg_split('{\r\n|\n|<br />}', $output);
952
-            array_shift($lines);
953
-            foreach ($lines as $i => $line) {
954
-                echo ($i + 1) . '. ' . $line . "\r\n";
955
-            }
956
-            echo '=============================================================================================' . "\n";
957
-        }
958
-
959
-        $this->template = $this->dwoo = null;
960
-        $tpl            = null;
961
-
962
-        return $output;
963
-    }
964
-
965
-    /**
966
-     * Checks what sub-templates are used in every sub-template so that we're sure they are all compiled.
967
-     *
968
-     * @param string $function the sub-template name
969
-     */
970
-    protected function resolveSubTemplateDependencies($function)
971
-    {
972
-        if ($this->debug) {
973
-            echo 'Compiler::' . __FUNCTION__ . "\n";
974
-        }
975
-
976
-        $body = $this->templatePlugins[$function]['body'];
977
-        foreach ($this->templatePlugins as $func => $attr) {
978
-            if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS .
979
-            'Plugin' . Core::toCamelCase($func)) !== false) {
980
-                $this->templatePlugins[$func]['called'] = true;
981
-                $this->resolveSubTemplateDependencies($func);
982
-            }
983
-        }
984
-        $this->templatePlugins[$function]['checked'] = true;
985
-    }
986
-
987
-    /**
988
-     * Adds compiled content to the current block.
989
-     *
990
-     * @param string $content   the content to push
991
-     * @param int    $lineCount newlines count in content, optional
992
-     *
993
-     * @throws CompilationException
994
-     */
995
-    public function push($content, $lineCount = null)
996
-    {
997
-        if ($lineCount === null) {
998
-            $lineCount = substr_count($content, "\n");
999
-        }
1000
-
1001
-        if ($this->curBlock['buffer'] === null && count($this->stack) > 1) {
1002
-            // buffer is not initialized yet (the block has just been created)
1003
-            $this->stack[count($this->stack) - 2]['buffer'] .= (string)$content;
1004
-            $this->curBlock['buffer'] = '';
1005
-        } else {
1006
-            if (!isset($this->curBlock['buffer'])) {
1007
-                throw new CompilationException($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere');
1008
-            }
1009
-            // append current content to current block's buffer
1010
-            $this->curBlock['buffer'] .= (string)$content;
1011
-        }
1012
-        $this->line += $lineCount;
1013
-    }
1014
-
1015
-    /**
1016
-     * Sets the scope.
1017
-     * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that
1018
-     * variables are compiled in a more evaluative way than just $this->scope['key']
1019
-     *
1020
-     * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1021
-     * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1022
-     *
1023
-     * @return array the current scope tree
1024
-     */
1025
-    public function setScope($scope, $absolute = false)
1026
-    {
1027
-        $old = $this->scopeTree;
1028
-
1029
-        if ($scope === null) {
1030
-            unset($this->scope);
1031
-            $this->scope = null;
1032
-        }
1033
-
1034
-        if (is_array($scope) === false) {
1035
-            $scope = explode('.', $scope);
1036
-        }
1037
-
1038
-        if ($absolute === true) {
1039
-            $this->scope     = &$this->data;
1040
-            $this->scopeTree = array();
1041
-        }
1042
-
1043
-        while (($bit = array_shift($scope)) !== null) {
1044
-            if ($bit === '_parent' || $bit === '_') {
1045
-                array_pop($this->scopeTree);
1046
-                reset($this->scopeTree);
1047
-                $this->scope = &$this->data;
1048
-                $cnt         = count($this->scopeTree);
1049
-                for ($i = 0; $i < $cnt; ++ $i) {
1050
-                    $this->scope = &$this->scope[$this->scopeTree[$i]];
1051
-                }
1052
-            } elseif ($bit === '_root' || $bit === '__') {
1053
-                $this->scope     = &$this->data;
1054
-                $this->scopeTree = array();
1055
-            } elseif (isset($this->scope[$bit])) {
1056
-                $this->scope       = &$this->scope[$bit];
1057
-                $this->scopeTree[] = $bit;
1058
-            } else {
1059
-                $this->scope[$bit] = array();
1060
-                $this->scope       = &$this->scope[$bit];
1061
-                $this->scopeTree[] = $bit;
1062
-            }
1063
-        }
1064
-
1065
-        return $old;
1066
-    }
1067
-
1068
-    /**
1069
-     * Adds a block to the top of the block stack.
1070
-     *
1071
-     * @param string $type      block type (name)
1072
-     * @param array  $params    the parameters array
1073
-     * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1074
-     *
1075
-     * @return string the preProcessing() method's output
1076
-     */
1077
-    public function addBlock($type, array $params, $paramtype)
1078
-    {
1079
-        if ($this->debug) {
1080
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1081
-        }
1082
-
1083
-        $class = current(array_filter([
1084
-            'Plugin' . Core::toCamelCase($type),
1085
-            Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type)
1086
-        ], 'class_exists'));
1087
-        if (false === $class) {
1088
-            $this->getCore()->getLoader()->loadPlugin($type);
1089
-        }
1090
-        $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1091
-
1092
-        $this->stack[]  = array(
1093
-            'type'   => $type,
1094
-            'params' => $params,
1095
-            'custom' => false,
1096
-            'class'  => $class,
1097
-            'buffer' => null
1098
-        );
1099
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1100
-
1101
-        return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1102
-    }
1103
-
1104
-    /**
1105
-     * Adds a custom block to the top of the block stack.
1106
-     *
1107
-     * @param string $type      block type (name)
1108
-     * @param array  $params    the parameters array
1109
-     * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1110
-     *
1111
-     * @return string the preProcessing() method's output
1112
-     */
1113
-    public function addCustomBlock($type, array $params, $paramtype)
1114
-    {
1115
-        $callback = $this->customPlugins[$type]['callback'];
1116
-        if (is_array($callback)) {
1117
-            $class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0];
1118
-        } else {
1119
-            $class = $callback;
1120
-        }
1121
-
1122
-        $params = $this->mapParams($params, array($class, 'init'), $paramtype);
1123
-
1124
-        $this->stack[]  = array(
1125
-            'type'   => $type,
1126
-            'params' => $params,
1127
-            'custom' => true,
1128
-            'class'  => $class,
1129
-            'buffer' => null
1130
-        );
1131
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1132
-
1133
-        return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1134
-    }
1135
-
1136
-    /**
1137
-     * Injects a block at the top of the plugin stack without calling its preProcessing method.
1138
-     * used by {else} blocks to re-add themselves after having closed everything up to their parent
1139
-     *
1140
-     * @param string $type   block type (name)
1141
-     * @param array  $params parameters array
1142
-     */
1143
-    public function injectBlock($type, array $params)
1144
-    {
1145
-        if ($this->debug) {
1146
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1147
-        }
1148
-
1149
-        $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1150
-        if (class_exists($class) === false) {
1151
-            $this->getCore()->getLoader()->loadPlugin($type);
1152
-        }
1153
-        $this->stack[]  = array(
1154
-            'type'   => $type,
1155
-            'params' => $params,
1156
-            'custom' => false,
1157
-            'class'  => $class,
1158
-            'buffer' => null
1159
-        );
1160
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1161
-    }
1162
-
1163
-    /**
1164
-     * Removes the closest-to-top block of the given type and all other
1165
-     * blocks encountered while going down the block stack.
1166
-     *
1167
-     * @param string $type block type (name)
1168
-     *
1169
-     * @return string the output of all postProcessing() method's return values of the closed blocks
1170
-     * @throws CompilationException
1171
-     */
1172
-    public function removeBlock($type)
1173
-    {
1174
-        if ($this->debug) {
1175
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1176
-        }
1177
-
1178
-        $output = '';
1179
-
1180
-        $pluginType = $this->getPluginType($type);
1181
-        if ($pluginType & Core::SMARTY_BLOCK) {
1182
-            $type = 'Smartyinterface';
1183
-        }
1184
-        while (true) {
1185
-            while ($top = array_pop($this->stack)) {
1186
-                if ($top['custom']) {
1187
-                    $class = $top['class'];
1188
-                } else {
1189
-                    $class = current(array_filter([
1190
-                        'Plugin' . Core::toCamelCase($top['type']),
1191
-                        Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($top['type'])
1192
-                    ], 'class_exists'));
1193
-                }
1194
-                if (count($this->stack)) {
1195
-                    $this->curBlock = &$this->stack[count($this->stack) - 1];
1196
-                    $this->push(call_user_func(array(
1197
-                        $class,
1198
-                        'postProcessing'
1199
-                    ), $this, $top['params'], '', '', $top['buffer']), 0);
1200
-                } else {
1201
-                    $null           = null;
1202
-                    $this->curBlock = &$null;
1203
-                    $output         = call_user_func(
1204
-                        array(
1205
-                        $class,
1206
-                        'postProcessing'
1207
-                        ), $this, $top['params'], '', '', $top['buffer']
1208
-                    );
1209
-                }
1210
-
1211
-                if ($top['type'] === $type) {
1212
-                    break 2;
1213
-                }
1214
-            }
1215
-
1216
-            throw new CompilationException($this, 'Syntax malformation, a block of type "' . $type . '" was closed but was not opened');
1217
-        }
1218
-
1219
-        return $output;
1220
-    }
1221
-
1222
-    /**
1223
-     * Returns a reference to the first block of the given type encountered and
1224
-     * optionally closes all blocks until it finds it
1225
-     * this is mainly used by {else} plugins to close everything that was opened
1226
-     * between their parent and themselves.
1227
-     *
1228
-     * @param string $type       the block type (name)
1229
-     * @param bool   $closeAlong whether to close all blocks encountered while going down the block stack or not
1230
-     *
1231
-     * @return mixed &array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1232
-     *               'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1233
-     * @throws CompilationException
1234
-     */
1235
-    public function &findBlock($type, $closeAlong = false)
1236
-    {
1237
-        if ($closeAlong === true) {
1238
-            while ($b = end($this->stack)) {
1239
-                if ($b['type'] === $type) {
1240
-                    return $this->stack[key($this->stack)];
1241
-                }
1242
-                $this->push($this->removeTopBlock(), 0);
1243
-            }
1244
-        } else {
1245
-            end($this->stack);
1246
-            while ($b = current($this->stack)) {
1247
-                if ($b['type'] === $type) {
1248
-                    return $this->stack[key($this->stack)];
1249
-                }
1250
-                prev($this->stack);
1251
-            }
1252
-        }
1253
-
1254
-        throw new CompilationException($this, 'A parent block of type "' . $type . '" is required and can not be found');
1255
-    }
1256
-
1257
-    /**
1258
-     * Returns a reference to the current block array.
1259
-     *
1260
-     * @return array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1261
-     *                'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1262
-     */
1263
-    public function &getCurrentBlock()
1264
-    {
1265
-        return $this->curBlock;
1266
-    }
1267
-
1268
-    /**
1269
-     * Removes the block at the top of the stack and calls its postProcessing() method.
1270
-     *
1271
-     * @return string the postProcessing() method's output
1272
-     * @throws CompilationException
1273
-     */
1274
-    public function removeTopBlock()
1275
-    {
1276
-        if ($this->debug) {
1277
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1278
-        }
1279
-
1280
-        $o = array_pop($this->stack);
1281
-        if ($o === null) {
1282
-            throw new CompilationException($this, 'Syntax malformation, a block of unknown type was closed but was not opened.');
1283
-        }
1284
-        if ($o['custom']) {
1285
-            $class = $o['class'];
1286
-        } else {
1287
-            $class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($o['type']);
1288
-        }
1289
-
1290
-        $this->curBlock = &$this->stack[count($this->stack) - 1];
1291
-
1292
-        return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']);
1293
-    }
1294
-
1295
-    /**
1296
-     * Returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out
1297
-     * of the given parameter array.
1298
-     *
1299
-     * @param array $params parameter array
1300
-     *
1301
-     * @return array filtered parameters
1302
-     */
1303
-    public function getCompiledParams(array $params)
1304
-    {
1305
-        foreach ($params as $k => $p) {
1306
-            if (is_array($p)) {
1307
-                $params[$k] = $p[0];
1308
-            }
1309
-        }
1310
-
1311
-        return $params;
1312
-    }
1313
-
1314
-    /**
1315
-     * Returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given
1316
-     * parameter array.
1317
-     *
1318
-     * @param array $params parameter array
1319
-     *
1320
-     * @return array filtered parameters
1321
-     */
1322
-    public function getRealParams(array $params)
1323
-    {
1324
-        foreach ($params as $k => $p) {
1325
-            if (is_array($p)) {
1326
-                $params[$k] = $p[1];
1327
-            }
1328
-        }
1329
-
1330
-        return $params;
1331
-    }
1332
-
1333
-    /**
1334
-     * Returns the token of each parameter out of the given parameter array.
1335
-     *
1336
-     * @param array $params parameter array
1337
-     *
1338
-     * @return array tokens
1339
-     */
1340
-    public function getParamTokens(array $params)
1341
-    {
1342
-        foreach ($params as $k => $p) {
1343
-            if (is_array($p)) {
1344
-                $params[$k] = isset($p[2]) ? $p[2] : 0;
1345
-            }
1346
-        }
1347
-
1348
-        return $params;
1349
-    }
1350
-
1351
-    /**
1352
-     * Entry point of the parser, it redirects calls to other parse* functions.
1353
-     *
1354
-     * @param string $in            the string within which we must parse something
1355
-     * @param int    $from          the starting offset of the parsed area
1356
-     * @param int    $to            the ending offset of the parsed area
1357
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1358
-     *                              default
1359
-     * @param string $curBlock      the current parser-block being processed
1360
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1361
-     *                              or null by default
1362
-     *
1363
-     * @return string parsed values
1364
-     * @throws CompilationException
1365
-     */
1366
-    protected function parse($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1367
-    {
1368
-        if ($this->debug) {
1369
-            echo 'Compiler::' . __FUNCTION__ . "\n";
1370
-        }
1371
-
1372
-        if ($to === null) {
1373
-            $to = strlen($in);
1374
-        }
1375
-        $first = substr($in, $from, 1);
1376
-
1377
-        if ($first === false) {
1378
-            throw new CompilationException($this, 'Unexpected EOF, a template tag was not closed');
1379
-        }
1380
-
1381
-        while ($first === ' ' || $first === "\n" || $first === "\t" || $first === "\r") {
1382
-            if ($curBlock === 'root' && substr($in, $from, strlen($this->rd)) === $this->rd) {
1383
-                // end template tag
1384
-                $pointer += strlen($this->rd);
1385
-                if ($this->debug) {
1386
-                    echo 'TEMPLATE PARSING ENDED' . "\n";
1387
-                }
1388
-
1389
-                return false;
1390
-            }
1391
-            ++ $from;
1392
-            if ($pointer !== null) {
1393
-                ++ $pointer;
1394
-            }
1395
-            if ($from >= $to) {
1396
-                if (is_array($parsingParams)) {
1397
-                    return $parsingParams;
1398
-                } else {
1399
-                    return '';
1400
-                }
1401
-            }
1402
-            $first = $in[$from];
1403
-        }
1404
-
1405
-        $substr = substr($in, $from, $to - $from);
1406
-
1407
-        if ($this->debug) {
1408
-            echo 'PARSE CALL : PARSING "' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . '" @ ' . $from . ':' . $to . ' in ' . $curBlock . ' : pointer=' . $pointer . "\n";
1409
-        }
1410
-        $parsed = '';
1411
-
1412
-        if ($curBlock === 'root' && $first === '*') {
1413
-            $src      = $this->getTemplateSource();
1414
-            $startpos = $this->getPointer() - strlen($this->ld);
1415
-            if (substr($src, $startpos, strlen($this->ld)) === $this->ld) {
1416
-                if ($startpos > 0) {
1417
-                    do {
1418
-                        $char = substr($src, -- $startpos, 1);
1419
-                        if ($char == "\n") {
1420
-                            ++ $startpos;
1421
-                            $whitespaceStart = true;
1422
-                            break;
1423
-                        }
1424
-                    }
1425
-                    while ($startpos > 0 && ($char == ' ' || $char == "\t"));
1426
-                }
1427
-
1428
-                if (!isset($whitespaceStart)) {
1429
-                    $startpos = $this->getPointer();
1430
-                } else {
1431
-                    $pointer -= $this->getPointer() - $startpos;
1432
-                }
1433
-
1434
-                if ($this->allowNestedComments && strpos($src, $this->ld . '*', $this->getPointer()) !== false) {
1435
-                    $comOpen  = $this->ld . '*';
1436
-                    $comClose = '*' . $this->rd;
1437
-                    $level    = 1;
1438
-                    $ptr      = $this->getPointer();
1439
-
1440
-                    while ($level > 0 && $ptr < strlen($src)) {
1441
-                        $open  = strpos($src, $comOpen, $ptr);
1442
-                        $close = strpos($src, $comClose, $ptr);
1443
-
1444
-                        if ($open !== false && $close !== false) {
1445
-                            if ($open < $close) {
1446
-                                $ptr = $open + strlen($comOpen);
1447
-                                ++ $level;
1448
-                            } else {
1449
-                                $ptr = $close + strlen($comClose);
1450
-                                -- $level;
1451
-                            }
1452
-                        } elseif ($open !== false) {
1453
-                            $ptr = $open + strlen($comOpen);
1454
-                            ++ $level;
1455
-                        } elseif ($close !== false) {
1456
-                            $ptr = $close + strlen($comClose);
1457
-                            -- $level;
1458
-                        } else {
1459
-                            $ptr = strlen($src);
1460
-                        }
1461
-                    }
1462
-                    $endpos = $ptr - strlen('*' . $this->rd);
1463
-                } else {
1464
-                    $endpos = strpos($src, '*' . $this->rd, $startpos);
1465
-                    if ($endpos == false) {
1466
-                        throw new CompilationException($this, 'Un-ended comment');
1467
-                    }
1468
-                }
1469
-                $pointer += $endpos - $startpos + strlen('*' . $this->rd);
1470
-                if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos + strlen('*' . $this->rd)), $m)) {
1471
-                    $pointer += strlen($m[0]);
1472
-                    $this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld)));
1473
-                }
1474
-
1475
-                return false;
1476
-            }
1477
-        }
1478
-
1479
-        if ($first === '$') {
1480
-            // var
1481
-            $out    = $this->parseVar($in, $from, $to, $parsingParams, $curBlock, $pointer);
1482
-            $parsed = 'var';
1483
-        } elseif ($first === '%' && preg_match('#^%[a-z_\\\\]#i', $substr)) {
1484
-            // Short constant
1485
-            $out = $this->parseConst($in, $from, $to, $parsingParams, $curBlock, $pointer);
1486
-        } elseif (($first === '"' || $first === "'") && !(is_array($parsingParams) && preg_match('#^([\'"])[a-z0-9_]+\1\s*=>?(?:\s+|[^=])#i', $substr))) {
1487
-            // string
1488
-            $out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer);
1489
-        } elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?(' . (is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|') . '\s*\(|\s*' . $this->rdr . '|\s*;)/i', $substr)) {
1490
-            // func
1491
-            $out    = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer);
1492
-            $parsed = 'func';
1493
-        } elseif ($first === ';') {
1494
-            // instruction end
1495
-            if ($this->debug) {
1496
-                echo 'END OF INSTRUCTION' . "\n";
1497
-            }
1498
-            if ($pointer !== null) {
1499
-                ++ $pointer;
1500
-            }
1501
-
1502
-            return $this->parse($in, $from + 1, $to, false, 'root', $pointer);
1503
-        } elseif ($curBlock === 'root' && preg_match('#^/([a-z_][a-z0-9_]*)?#i', $substr, $match)) {
1504
-            // close block
1505
-            if (!empty($match[1]) && $match[1] == 'else') {
1506
-                throw new CompilationException($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed');
1507
-            }
1508
-            if (!empty($match[1]) && $match[1] == 'elseif') {
1509
-                throw new CompilationException($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them');
1510
-            }
1511
-            if ($pointer !== null) {
1512
-                $pointer += strlen($match[0]);
1513
-            }
1514
-            if (empty($match[1])) {
1515
-                if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') {
1516
-                    $pointer -= strlen($match[0]);
1517
-                }
1518
-                if ($this->debug) {
1519
-                    echo 'TOP BLOCK CLOSED' . "\n";
1520
-                }
1521
-
1522
-                return $this->removeTopBlock();
1523
-            } else {
1524
-                if ($this->debug) {
1525
-                    echo 'BLOCK OF TYPE ' . $match[1] . ' CLOSED' . "\n";
1526
-                }
1527
-
1528
-                return $this->removeBlock($match[1]);
1529
-            }
1530
-        } elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) {
1531
-            // end template tag
1532
-            if ($this->debug) {
1533
-                echo 'TAG PARSING ENDED' . "\n";
1534
-            }
1535
-            $pointer += strlen($this->rd);
1536
-
1537
-            return false;
1538
-        } elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*=' . ($curBlock === 'array' ? '>?' : '') . ')(?:\s+|[^=]).*#i', $substr, $match)) {
1539
-            // named parameter
1540
-            if ($this->debug) {
1541
-                echo 'NAMED PARAM FOUND' . "\n";
1542
-            }
1543
-            $len = strlen($match[1]);
1544
-            while (substr($in, $from + $len, 1) === ' ') {
1545
-                ++ $len;
1546
-            }
1547
-            if ($pointer !== null) {
1548
-                $pointer += $len;
1549
-            }
1550
-
1551
-            $output = array(
1552
-                trim($match[1], " \t\r\n=>'\""),
1553
-                $this->parse($in, $from + $len, $to, false, 'namedparam', $pointer)
1554
-            );
1555
-
1556
-            $parsingParams[] = $output;
1557
-
1558
-            return $parsingParams;
1559
-        } elseif (preg_match('#^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*::\$[a-z0-9_]+)#i', $substr, $match)) {
1560
-            // static member access
1561
-            $parsed = 'var';
1562
-            if (is_array($parsingParams)) {
1563
-                $parsingParams[] = array($match[1], $match[1]);
1564
-                $out             = $parsingParams;
1565
-            } else {
1566
-                $out = $match[1];
1567
-            }
1568
-            $pointer += strlen($match[1]);
1569
-        } elseif ($substr !== '' && (is_array($parsingParams) || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'expression')) {
1570
-            // unquoted string, bool or number
1571
-            $out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1572
-        } else {
1573
-            // parse error
1574
-            throw new CompilationException($this, 'Parse error in "' . substr($in, $from, $to - $from) . '"');
1575
-        }
1576
-
1577
-        if (empty($out)) {
1578
-            return '';
1579
-        }
1580
-
1581
-        $substr = substr($in, $pointer, $to - $pointer);
1582
-
1583
-        // var parsed, check if any var-extension applies
1584
-        if ($parsed === 'var') {
1585
-            if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) {
1586
-                if ($this->debug) {
1587
-                    echo 'PARSING POST-VAR EXPRESSION ' . $substr . "\n";
1588
-                }
1589
-                // parse expressions
1590
-                $pointer += strlen($match[0]) - 1;
1591
-                if (is_array($parsingParams)) {
1592
-                    if ($match[2] == '$') {
1593
-                        $expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer);
1594
-                    } else {
1595
-                        $expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer);
1596
-                    }
1597
-                    $out[count($out) - 1][0] .= $match[1] . $expr[0][0];
1598
-                    $out[count($out) - 1][1] .= $match[1] . $expr[0][1];
1599
-                } else {
1600
-                    if ($match[2] == '$') {
1601
-                        $expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer);
1602
-                    } else {
1603
-                        $expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer);
1604
-                    }
1605
-                    if (is_array($out) && is_array($expr)) {
1606
-                        $out[0] .= $match[1] . $expr[0];
1607
-                        $out[1] .= $match[1] . $expr[1];
1608
-                    } elseif (is_array($out)) {
1609
-                        $out[0] .= $match[1] . $expr;
1610
-                        $out[1] .= $match[1] . $expr;
1611
-                    } elseif (is_array($expr)) {
1612
-                        $out .= $match[1] . $expr[0];
1613
-                    } else {
1614
-                        $out .= $match[1] . $expr;
1615
-                    }
1616
-                }
1617
-            } elseif ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) {
1618
-                if ($this->debug) {
1619
-                    echo 'PARSING POST-VAR ASSIGNMENT ' . $substr . "\n";
1620
-                }
1621
-                // parse assignment
1622
-                $value    = $match[2];
1623
-                $operator = trim($match[1]);
1624
-                if (substr($value, 0, 1) == '=') {
1625
-                    throw new CompilationException($this, 'Unexpected "=" in <em>' . $substr . '</em>');
1626
-                }
1627
-
1628
-                if ($pointer !== null) {
1629
-                    $pointer += strlen($match[1]);
1630
-                }
1631
-
1632
-                if ($operator !== '++' && $operator !== '--') {
1633
-                    $parts = array();
1634
-                    $ptr   = 0;
1635
-                    $parts = $this->parse($value, 0, strlen($value), $parts, 'condition', $ptr);
1636
-                    $pointer += $ptr;
1637
-
1638
-                    // load if plugin
1639
-                    try {
1640
-                        $this->getPluginType('if');
1641
-                    }
1642
-                    catch (Exception $e) {
1643
-                        throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1644
-                    }
1645
-
1646
-                    $parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS . 'PluginIf', 'init'), 1);
1647
-                    $tokens = $this->getParamTokens($parts);
1648
-                    $parts  = $this->getCompiledParams($parts);
1649
-
1650
-                    $value = PluginIf::replaceKeywords($parts['*'], $tokens['*'], $this);
1651
-                    $echo  = '';
1652
-                } else {
1653
-                    $value = array();
1654
-                    $echo  = 'echo ';
1655
-                }
1656
-
1657
-                if ($this->autoEscape) {
1658
-                    $out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out);
1659
-                }
1660
-                $out = self::PHP_OPEN . $echo . $out . $operator . implode(' ', $value) . self::PHP_CLOSE;
1661
-            } elseif ($curBlock === 'array' && is_array($parsingParams) && preg_match('#^(\s*=>?\s*)#', $substr, $match)) {
1662
-                // parse namedparam with var as name (only for array)
1663
-                if ($this->debug) {
1664
-                    echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND' . "\n";
1665
-                }
1666
-                $len = strlen($match[1]);
1667
-                $var = $out[count($out) - 1];
1668
-                $pointer += $len;
1669
-
1670
-                $output = array($var[0], $this->parse($substr, $len, null, false, 'namedparam', $pointer));
1671
-
1672
-                $parsingParams[] = $output;
1673
-
1674
-                return $parsingParams;
1675
-            }
1676
-        }
1677
-
1678
-        if ($curBlock !== 'modifier' && ($parsed === 'func' || $parsed === 'var') && preg_match('#^(\|@?[a-z0-9_]+(:.*)?)+#i', $substr, $match)) {
1679
-            // parse modifier on funcs or vars
1680
-            $srcPointer = $pointer;
1681
-            if (is_array($parsingParams)) {
1682
-                $tmp                     = $this->replaceModifiers(
1683
-                    array(
1684
-                    null,
1685
-                    null,
1686
-                    $out[count($out) - 1][0],
1687
-                    $match[0]
1688
-                    ), $curBlock, $pointer
1689
-                );
1690
-                $out[count($out) - 1][0] = $tmp;
1691
-                $out[count($out) - 1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer);
1692
-            } else {
1693
-                $out = $this->replaceModifiers(array(null, null, $out, $match[0]), $curBlock, $pointer);
1694
-            }
1695
-        }
1696
-
1697
-        // func parsed, check if any func-extension applies
1698
-        if ($parsed === 'func' && preg_match('#^->[a-z0-9_]+(\s*\(.+|->[a-z_].*)?#is', $substr, $match)) {
1699
-            // parse method call or property read
1700
-            $ptr = 0;
1701
-
1702
-            if (is_array($parsingParams)) {
1703
-                $output = $this->parseMethodCall($out[count($out) - 1][1], $match[0], $curBlock, $ptr);
1704
-
1705
-                $out[count($out) - 1][0] = $output;
1706
-                $out[count($out) - 1][1] .= substr($match[0], 0, $ptr);
1707
-            } else {
1708
-                $out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr);
1709
-            }
1710
-
1711
-            $pointer += $ptr;
1712
-        }
1713
-
1714
-        if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) {
1715
-            return self::PHP_OPEN . 'echo ' . $out . ';' . self::PHP_CLOSE;
1716
-        }
1717
-
1718
-        return $out;
1719
-    }
1720
-
1721
-    /**
1722
-     * Parses a function call.
1723
-     *
1724
-     * @param string $in            the string within which we must parse something
1725
-     * @param int    $from          the starting offset of the parsed area
1726
-     * @param int    $to            the ending offset of the parsed area
1727
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1728
-     *                              default
1729
-     * @param string $curBlock      the current parser-block being processed
1730
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1731
-     *                              or null by default
1732
-     *
1733
-     * @return string parsed values
1734
-     * @throws CompilationException
1735
-     * @throws Exception
1736
-     * @throws SecurityException
1737
-     */
1738
-    protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1739
-    {
1740
-        $output = '';
1741
-        $cmdstr = substr($in, $from, $to - $from);
1742
-        preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*' . $this->rdr . '|\s*;)?/i', $cmdstr, $match);
1743
-
1744
-        if (empty($match[1])) {
1745
-            throw new CompilationException($this, 'Parse error, invalid function name : ' . substr($cmdstr, 0, 15));
1746
-        }
1747
-
1748
-        $func = $match[1];
1749
-
1750
-        if (!empty($match[2])) {
1751
-            $cmdstr = $match[1];
1752
-        }
1753
-
1754
-        if ($this->debug) {
1755
-            echo 'FUNC FOUND (' . $func . ')' . "\n";
1756
-        }
1757
-
1758
-        $paramsep = '';
1759
-
1760
-        if (is_array($parsingParams) || $curBlock != 'root') {
1761
-            $paramspos = strpos($cmdstr, '(');
1762
-            $paramsep  = ')';
1763
-        } elseif (preg_match_all('#^\s*[\\\\:a-z0-9_]+(\s*\(|\s+[^(])#i', $cmdstr, $match, PREG_OFFSET_CAPTURE)) {
1764
-            $paramspos = $match[1][0][1];
1765
-            $paramsep  = substr($match[1][0][0], - 1) === '(' ? ')' : '';
1766
-            if ($paramsep === ')') {
1767
-                $paramspos += strlen($match[1][0][0]) - 1;
1768
-                if (substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') {
1769
-                    $paramsep = '';
1770
-                    if (strlen($match[1][0][0]) > 1) {
1771
-                        -- $paramspos;
1772
-                    }
1773
-                }
1774
-            }
1775
-        } else {
1776
-            $paramspos = false;
1777
-        }
1778
-
1779
-        $state = 0;
1780
-
1781
-        if ($paramspos === false) {
1782
-            $params = array();
1783
-
1784
-            if ($curBlock !== 'root') {
1785
-                return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1786
-            }
1787
-        } else {
1788
-            if ($curBlock === 'condition') {
1789
-                // load if plugin
1790
-                $this->getPluginType('if');
1791
-
1792
-                if (PluginIf::replaceKeywords(array($func), array(self::T_UNQUOTED_STRING), $this) !== array($func)) {
1793
-                    return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1794
-                }
1795
-            }
1796
-            $whitespace = strlen(substr($cmdstr, strlen($func), $paramspos - strlen($func)));
1797
-            $paramstr   = substr($cmdstr, $paramspos + 1);
1798
-            if (substr($paramstr, - 1, 1) === $paramsep) {
1799
-                $paramstr = substr($paramstr, 0, - 1);
1800
-            }
1801
-
1802
-            if (strlen($paramstr) === 0) {
1803
-                $params   = array();
1804
-                $paramstr = '';
1805
-            } else {
1806
-                $ptr    = 0;
1807
-                $params = array();
1808
-                if ($func === 'empty') {
1809
-                    $params = $this->parseVar($paramstr, $ptr, strlen($paramstr), $params, 'root', $ptr);
1810
-                } else {
1811
-                    while ($ptr < strlen($paramstr)) {
1812
-                        while (true) {
1813
-                            if ($ptr >= strlen($paramstr)) {
1814
-                                break 2;
1815
-                            }
1816
-
1817
-                            if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') {
1818
-                                if ($this->debug) {
1819
-                                    echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT ' . $ptr . "\n";
1820
-                                }
1821
-                                break 2;
1822
-                            } elseif ($paramstr[$ptr] === ';') {
1823
-                                ++ $ptr;
1824
-                                if ($this->debug) {
1825
-                                    echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT ' . $ptr . "\n";
1826
-                                }
1827
-                                break 2;
1828
-                            } elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') {
1829
-                                if ($this->debug) {
1830
-                                    echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT ' . $ptr . "\n";
1831
-                                }
1832
-                                break 2;
1833
-                            } elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
1834
-                                if ($this->debug) {
1835
-                                    echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT ' . $ptr . "\n";
1836
-                                }
1837
-                                break 2;
1838
-                            }
1839
-
1840
-                            if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") {
1841
-                                ++ $ptr;
1842
-                            } else {
1843
-                                break;
1844
-                            }
1845
-                        }
1846
-
1847
-                        if ($this->debug) {
1848
-                            echo 'FUNC START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
1849
-                        }
1850
-
1851
-                        if ($func === 'if' || $func === 'elseif' || $func === 'tif') {
1852
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'condition', $ptr);
1853
-                        } elseif ($func === 'array') {
1854
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'array', $ptr);
1855
-                        } else {
1856
-                            $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'function', $ptr);
1857
-                        }
1858
-
1859
-                        if ($this->debug) {
1860
-                            echo 'PARAM PARSED, POINTER AT ' . $ptr . ' (' . substr($paramstr, $ptr - 1, 3) . ')' . "\n";
1861
-                        }
1862
-                    }
1863
-                }
1864
-                $paramstr = substr($paramstr, 0, $ptr);
1865
-                $state    = 0;
1866
-                foreach ($params as $k => $p) {
1867
-                    if (is_array($p) && is_array($p[1])) {
1868
-                        $state |= 2;
1869
-                    } else {
1870
-                        if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m) && $func !== 'array') {
1871
-                            $params[$k] = array($m[2], array('true', 'true'));
1872
-                        } else {
1873
-                            if ($state & 2 && $func !== 'array') {
1874
-                                throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
1875
-                            }
1876
-                            $state |= 1;
1877
-                        }
1878
-                    }
1879
-                }
1880
-            }
1881
-        }
1882
-
1883
-        if ($pointer !== null) {
1884
-            $pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0);
1885
-            if ($this->debug) {
1886
-                echo 'FUNC ADDS ' . ((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)) . ' TO POINTER' . "\n";
1887
-            }
1888
-        }
1889
-
1890
-        if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) {
1891
-            // handle static method calls with security policy
1892
-            if (strstr($func, '::') !== false && $this->securityPolicy !== null && $this->securityPolicy->isMethodAllowed(explode('::', strtolower($func))) !== true) {
1893
-                throw new SecurityException('Call to a disallowed php function : ' . $func);
1894
-            }
1895
-            $pluginType = Core::NATIVE_PLUGIN;
1896
-        } else {
1897
-            $pluginType = $this->getPluginType($func);
1898
-        }
1899
-
1900
-        // Blocks plugin
1901
-        if ($pluginType & Core::BLOCK_PLUGIN) {
1902
-            if ($curBlock !== 'root' || is_array($parsingParams)) {
1903
-                throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1904
-            }
1905
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1906
-                return $this->addCustomBlock($func, $params, $state);
1907
-            } else {
1908
-                return $this->addBlock($func, $params, $state);
1909
-            }
1910
-        } elseif ($pluginType & Core::SMARTY_BLOCK) {
1911
-            if ($curBlock !== 'root' || is_array($parsingParams)) {
1912
-                throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1913
-            }
1914
-
1915
-            if ($state & 2) {
1916
-                array_unshift($params, array('__functype', array($pluginType, $pluginType)));
1917
-                array_unshift($params, array('__funcname', array($func, $func)));
1918
-            } else {
1919
-                array_unshift($params, array($pluginType, $pluginType));
1920
-                array_unshift($params, array($func, $func));
1921
-            }
1922
-
1923
-            return $this->addBlock('smartyinterface', $params, $state);
1924
-        }
1925
-
1926
-        // Native & Smarty plugins
1927
-        if ($pluginType & Core::NATIVE_PLUGIN || $pluginType & Core::SMARTY_FUNCTION || $pluginType & Core::SMARTY_BLOCK) {
1928
-            $params = $this->mapParams($params, null, $state);
1929
-        } // PHP class plugin
1930
-        elseif ($pluginType & Core::CLASS_PLUGIN) {
1931
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1932
-                $params = $this->mapParams(
1933
-                    $params, array(
1934
-                    $this->customPlugins[$func]['class'],
1935
-                    $this->customPlugins[$func]['function']
1936
-                ), $state);
1937
-            } else {
1938
-                if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
1939
-                    $params = $this->mapParams($params, array(
1940
-                        'Plugin' . Core::toCamelCase($func),
1941
-                        ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1942
-                    ), $state);
1943
-                } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
1944
-                    $params = $this->mapParams($params, array(
1945
-                        Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func),
1946
-                        ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1947
-                    ), $state);
1948
-                } else {
1949
-                    $params = $this->mapParams($params, array(
1950
-                        Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
1951
-                        ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1952
-                    ), $state);
1953
-                }
1954
-            }
1955
-        } // PHP function plugin
1956
-        elseif ($pluginType & Core::FUNC_PLUGIN) {
1957
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
1958
-                $params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state);
1959
-            } else {
1960
-                // Custom plugin
1961
-                if (function_exists('Plugin' . Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ?
1962
-                        'Compile' : '')) !== false) {
1963
-                    $params = $this->mapParams($params, 'Plugin' . Core::toCamelCase($func) . (($pluginType &
1964
-                            Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1965
-                } // Builtin helper plugin
1966
-                elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . (
1967
-                    ($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '')) !== false) {
1968
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase
1969
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1970
-                } // Builtin function plugin
1971
-                else {
1972
-                    $params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
1973
-                        ($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1974
-                }
1975
-            }
1976
-        } // Smarty modifier
1977
-        elseif ($pluginType & Core::SMARTY_MODIFIER) {
1978
-            $output = 'smarty_modifier_' . $func . '(' . implode(', ', $params) . ')';
1979
-        } // Proxy plugin
1980
-        elseif ($pluginType & Core::PROXY_PLUGIN) {
1981
-            $params = $this->mapParams($params, $this->getCore()->getPluginProxy()->getCallback($func), $state);
1982
-        } // Template plugin
1983
-        elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
1984
-            // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
1985
-            $map = array();
1986
-            foreach ($this->templatePlugins[$func]['params'] as $param => $defValue) {
1987
-                if ($param == 'rest') {
1988
-                    $param = '*';
1989
-                }
1990
-                $hasDefault = $defValue !== null;
1991
-                if ($defValue === 'null') {
1992
-                    $defValue = null;
1993
-                } elseif ($defValue === 'false') {
1994
-                    $defValue = false;
1995
-                } elseif ($defValue === 'true') {
1996
-                    $defValue = true;
1997
-                } elseif (preg_match('#^([\'"]).*?\1$#', $defValue)) {
1998
-                    $defValue = substr($defValue, 1, - 1);
1999
-                }
2000
-                $map[] = array($param, $hasDefault, $defValue);
2001
-            }
2002
-
2003
-            $params = $this->mapParams($params, null, $state, $map);
2004
-        }
2005
-
2006
-        // only keep php-syntax-safe values for non-block plugins
2007
-        $tokens = array();
2008
-        foreach ($params as $k => $p) {
2009
-            $tokens[$k] = isset($p[2]) ? $p[2] : 0;
2010
-            $params[$k] = $p[0];
2011
-        }
2012
-
2013
-        // Native plugin
2014
-        if ($pluginType & Core::NATIVE_PLUGIN) {
2015
-            if ($func === 'do') {
2016
-                $output = '';
2017
-                if (isset($params['*'])) {
2018
-                    $output = implode(';', $params['*']) . ';';
2019
-                }
2020
-
2021
-                if (is_array($parsingParams) || $curBlock !== 'root') {
2022
-                    throw new CompilationException($this, 'Do can not be used inside another function or block');
2023
-                }
2024
-
2025
-                return self::PHP_OPEN . $output . self::PHP_CLOSE;
2026
-            } else {
2027
-                if (isset($params['*'])) {
2028
-                    $output = $func . '(' . implode(', ', $params['*']) . ')';
2029
-                } else {
2030
-                    $output = $func . '()';
2031
-                }
2032
-            }
2033
-        } // Block class OR Function class
2034
-        elseif ($pluginType & Core::CLASS_PLUGIN || ($pluginType & Core::FUNC_PLUGIN && $pluginType & Core::CLASS_PLUGIN)) {
2035
-            if ($pluginType & Core::COMPILABLE_PLUGIN) {
2036
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2037
-                    $callback = $this->customPlugins[$func]['callback'];
2038
-                    if (!is_array($callback)) {
2039
-                        if (!method_exists($callback, 'compile')) {
2040
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2041
-                        }
2042
-                        if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
2043
-                            $funcCompiler = array($callback, 'compile');
2044
-                        } else {
2045
-                            $funcCompiler = array(new $callback(), 'compile');
2046
-                        }
2047
-                    } else {
2048
-                        $funcCompiler = $callback;
2049
-                    }
2050
-                } else {
2051
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2052
-                        $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
2053
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2054
-                        $funcCompiler = array(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func), 'compile');
2055
-                    } else {
2056
-                        $funcCompiler = array(
2057
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
2058
-                            'compile'
2059
-                        );
2060
-                    }
2061
-                    array_unshift($params, $this);
2062
-                }
2063
-                // @TODO: Is it a real fix ?
2064
-                if ($func === 'tif') {
2065
-                    $params[] = $tokens;
2066
-                }
2067
-                $output = call_user_func_array($funcCompiler, $params);
2068
-            } else {
2069
-                $params = self::implode_r($params);
2070
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2071
-                    $callback = $this->customPlugins[$func]['callback'];
2072
-                    if (!is_array($callback)) {
2073
-                        if (!method_exists($callback, 'process')) {
2074
-                            throw new Exception('Custom plugin ' . $func . ' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2075
-                        }
2076
-                        if (is_object($callback)) {
2077
-                            $callback = get_class($callback);
2078
-                        }
2079
-                        if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
2080
-                            $output = 'call_user_func(array(\'' . $callback . '\', \'process\'), ' . $params . ')';
2081
-                        } else {
2082
-                            $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback . '\'), \'process\'), ' . $params . ')';
2083
-                        }
2084
-                    } elseif (is_object($callback[0])) {
2085
-                        $output = 'call_user_func(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), ' . $params . ')';
2086
-                    } elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) {
2087
-                        $output = 'call_user_func(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), ' . $params . ')';
2088
-                    } else {
2089
-                        $output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback[0] . '\'), \'' . $callback[1] . '\'), ' . $params . ')';
2090
-                    }
2091
-                    if (empty($params)) {
2092
-                        $output = substr($output, 0, - 3) . ')';
2093
-                    }
2094
-                } else {
2095
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2096
-                        $output = '$this->classCall(\'Plugin' . $func . '\', array(' . $params . '))';
2097
-                    } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2098
-                        $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\',
34
+	/**
35
+	 * Constant that represents a php opening tag.
36
+	 * use it in case it needs to be adjusted
37
+	 *
38
+	 * @var string
39
+	 */
40
+	const PHP_OPEN = '<?php ';
41
+
42
+	/**
43
+	 * Constant that represents a php closing tag.
44
+	 * use it in case it needs to be adjusted
45
+	 *
46
+	 * @var string
47
+	 */
48
+	const PHP_CLOSE = '?>';
49
+
50
+	/**
51
+	 * Boolean flag to enable or disable debugging output.
52
+	 *
53
+	 * @var bool
54
+	 */
55
+	public $debug = false;
56
+
57
+	/**
58
+	 * Left script delimiter.
59
+	 *
60
+	 * @var string
61
+	 */
62
+	protected $ld = '{';
63
+
64
+	/**
65
+	 * Left script delimiter with escaped regex meta characters.
66
+	 *
67
+	 * @var string
68
+	 */
69
+	protected $ldr = '\\{';
70
+
71
+	/**
72
+	 * Right script delimiter.
73
+	 *
74
+	 * @var string
75
+	 */
76
+	protected $rd = '}';
77
+
78
+	/**
79
+	 * Right script delimiter with escaped regex meta characters.
80
+	 *
81
+	 * @var string
82
+	 */
83
+	protected $rdr = '\\}';
84
+
85
+	/**
86
+	 * Defines whether the nested comments should be parsed as nested or not.
87
+	 * defaults to false (classic block comment parsing as in all languages)
88
+	 *
89
+	 * @var bool
90
+	 */
91
+	protected $allowNestedComments = false;
92
+
93
+	/**
94
+	 * Defines whether opening and closing tags can contain spaces before valid data or not.
95
+	 * turn to true if you want to be sloppy with the syntax, but when set to false it allows
96
+	 * to skip javascript and css tags as long as they are in the form "{ something", which is
97
+	 * nice. default is false.
98
+	 *
99
+	 * @var bool
100
+	 */
101
+	protected $allowLooseOpenings = false;
102
+
103
+	/**
104
+	 * Defines whether the compiler will automatically html-escape variables or not.
105
+	 * default is false
106
+	 *
107
+	 * @var bool
108
+	 */
109
+	protected $autoEscape = false;
110
+
111
+	/**
112
+	 * Security policy object.
113
+	 *
114
+	 * @var SecurityPolicy
115
+	 */
116
+	protected $securityPolicy;
117
+
118
+	/**
119
+	 * Stores the custom plugins registered with this compiler.
120
+	 *
121
+	 * @var array
122
+	 */
123
+	protected $customPlugins = array();
124
+
125
+	/**
126
+	 * Stores the template plugins registered with this compiler.
127
+	 *
128
+	 * @var array
129
+	 */
130
+	protected $templatePlugins = array();
131
+
132
+	/**
133
+	 * Stores the pre- and post-processors callbacks.
134
+	 *
135
+	 * @var array
136
+	 */
137
+	protected $processors = array('pre' => array(), 'post' => array());
138
+
139
+	/**
140
+	 * Stores a list of plugins that are used in the currently compiled
141
+	 * template, and that are not compilable. these plugins will be loaded
142
+	 * during the template's runtime if required.
143
+	 * it is a 1D array formatted as key:pluginName value:pluginType
144
+	 *
145
+	 * @var array
146
+	 */
147
+	protected $usedPlugins;
148
+
149
+	/**
150
+	 * Stores the template undergoing compilation.
151
+	 *
152
+	 * @var string
153
+	 */
154
+	protected $template;
155
+
156
+	/**
157
+	 * Stores the current pointer position inside the template.
158
+	 *
159
+	 * @var int
160
+	 */
161
+	protected $pointer;
162
+
163
+	/**
164
+	 * Stores the current line count inside the template for debugging purposes.
165
+	 *
166
+	 * @var int
167
+	 */
168
+	protected $line;
169
+
170
+	/**
171
+	 * Stores the current template source while compiling it.
172
+	 *
173
+	 * @var string
174
+	 */
175
+	protected $templateSource;
176
+
177
+	/**
178
+	 * Stores the data within which the scope moves.
179
+	 *
180
+	 * @var array
181
+	 */
182
+	protected $data;
183
+
184
+	/**
185
+	 * Variable scope of the compiler, set to null if
186
+	 * it can not be resolved to a static string (i.e. if some
187
+	 * plugin defines a new scope based on a variable array key).
188
+	 *
189
+	 * @var mixed
190
+	 */
191
+	protected $scope;
192
+
193
+	/**
194
+	 * Variable scope tree, that allows to rebuild the current
195
+	 * scope if required, i.e. when going to a parent level.
196
+	 *
197
+	 * @var array
198
+	 */
199
+	protected $scopeTree;
200
+
201
+	/**
202
+	 * Block plugins stack, accessible through some methods.
203
+	 *
204
+	 * @see findBlock
205
+	 * @see getCurrentBlock
206
+	 * @see addBlock
207
+	 * @see addCustomBlock
208
+	 * @see injectBlock
209
+	 * @see removeBlock
210
+	 * @see removeTopBlock
211
+	 * @var array
212
+	 */
213
+	protected $stack = array();
214
+
215
+	/**
216
+	 * Current block at the top of the block plugins stack,
217
+	 * accessible through getCurrentBlock.
218
+	 *
219
+	 * @see getCurrentBlock
220
+	 * @var array
221
+	 */
222
+	protected $curBlock;
223
+
224
+	/**
225
+	 * Current dwoo object that uses this compiler, or null.
226
+	 *
227
+	 * @var Core
228
+	 */
229
+	public $core;
230
+
231
+	/**
232
+	 * Holds an instance of this class, used by getInstance when you don't
233
+	 * provide a custom compiler in order to save resources.
234
+	 *
235
+	 * @var Compiler
236
+	 */
237
+	protected static $instance;
238
+
239
+	/**
240
+	 * Token types.
241
+	 *
242
+	 * @var int
243
+	 */
244
+	const T_UNQUOTED_STRING = 1;
245
+	const T_NUMERIC         = 2;
246
+	const T_NULL            = 4;
247
+	const T_BOOL            = 8;
248
+	const T_MATH            = 16;
249
+	const T_BREAKCHAR       = 32;
250
+
251
+	/**
252
+	 * Compiler constructor.
253
+	 * saves the created instance so that child templates get the same one
254
+	 */
255
+	public function __construct()
256
+	{
257
+		self::$instance = $this;
258
+	}
259
+
260
+	/**
261
+	 * Sets the delimiters to use in the templates.
262
+	 * delimiters can be multi-character strings but should not be one of those as they will
263
+	 * make it very hard to work with templates or might even break the compiler entirely : "\", "$", "|", ":" and
264
+	 * finally "#" only if you intend to use config-vars with the #var# syntax.
265
+	 *
266
+	 * @param string $left  left delimiter
267
+	 * @param string $right right delimiter
268
+	 */
269
+	public function setDelimiters($left, $right)
270
+	{
271
+		$this->ld  = $left;
272
+		$this->rd  = $right;
273
+		$this->ldr = preg_quote($left, '/');
274
+		$this->rdr = preg_quote($right, '/');
275
+	}
276
+
277
+	/**
278
+	 * Returns the left and right template delimiters.
279
+	 *
280
+	 * @return array containing the left and the right delimiters
281
+	 */
282
+	public function getDelimiters()
283
+	{
284
+		return array($this->ld, $this->rd);
285
+	}
286
+
287
+	/**
288
+	 * Sets the way to handle nested comments, if set to true
289
+	 * {* foo {* some other *} comment *} will be stripped correctly.
290
+	 * if false it will remove {* foo {* some other *} and leave "comment *}" alone,
291
+	 * this is the default behavior
292
+	 *
293
+	 * @param bool $allow allow nested comments or not, defaults to true (but the default internal value is false)
294
+	 */
295
+	public function setNestedCommentsHandling($allow = true)
296
+	{
297
+		$this->allowNestedComments = (bool)$allow;
298
+	}
299
+
300
+	/**
301
+	 * Returns the nested comments handling setting.
302
+	 *
303
+	 * @see    setNestedCommentsHandling
304
+	 * @return bool true if nested comments are allowed
305
+	 */
306
+	public function getNestedCommentsHandling()
307
+	{
308
+		return $this->allowNestedComments;
309
+	}
310
+
311
+	/**
312
+	 * Sets the tag openings handling strictness, if set to true, template tags can
313
+	 * contain spaces before the first function/string/variable such as { $foo} is valid.
314
+	 * if set to false (default setting), { $foo} is invalid but that is however a good thing
315
+	 * as it allows css (i.e. #foo { color:red; }) to be parsed silently without triggering
316
+	 * an error, same goes for javascript.
317
+	 *
318
+	 * @param bool $allow true to allow loose handling, false to restore default setting
319
+	 */
320
+	public function setLooseOpeningHandling($allow = false)
321
+	{
322
+		$this->allowLooseOpenings = (bool)$allow;
323
+	}
324
+
325
+	/**
326
+	 * Returns the tag openings handling strictness setting.
327
+	 *
328
+	 * @see    setLooseOpeningHandling
329
+	 * @return bool true if loose tags are allowed
330
+	 */
331
+	public function getLooseOpeningHandling()
332
+	{
333
+		return $this->allowLooseOpenings;
334
+	}
335
+
336
+	/**
337
+	 * Changes the auto escape setting.
338
+	 * if enabled, the compiler will automatically html-escape variables,
339
+	 * unless they are passed through the safe function such as {$var|safe}
340
+	 * or {safe $var}
341
+	 * default setting is disabled/false
342
+	 *
343
+	 * @param bool $enabled set to true to enable, false to disable
344
+	 */
345
+	public function setAutoEscape($enabled)
346
+	{
347
+		$this->autoEscape = (bool)$enabled;
348
+	}
349
+
350
+	/**
351
+	 * Returns the auto escape setting.
352
+	 * default setting is disabled/false
353
+	 *
354
+	 * @return bool
355
+	 */
356
+	public function getAutoEscape()
357
+	{
358
+		return $this->autoEscape;
359
+	}
360
+
361
+	/**
362
+	 * Adds a preprocessor to the compiler, it will be called
363
+	 * before the template is compiled.
364
+	 *
365
+	 * @param mixed $callback either a valid callback to the preprocessor or a simple name if the autoload is set to
366
+	 *                        true
367
+	 * @param bool  $autoload if set to true, the preprocessor is auto-loaded from one of the plugin directories, else
368
+	 *                        you must provide a valid callback
369
+	 */
370
+	public function addPreProcessor($callback, $autoload = false)
371
+	{
372
+		if ($autoload) {
373
+			$name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', Core::toCamelCase($callback));
374
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . $name;
375
+
376
+			if (class_exists($class)) {
377
+				$callback = array(new $class($this), 'process');
378
+			} elseif (function_exists($class)) {
379
+				$callback = $class;
380
+			} else {
381
+				$callback = array('autoload' => true, 'class' => $class, 'name' => $name);
382
+			}
383
+
384
+			$this->processors['pre'][] = $callback;
385
+		} else {
386
+			$this->processors['pre'][] = $callback;
387
+		}
388
+	}
389
+
390
+	/**
391
+	 * Removes a preprocessor from the compiler.
392
+	 *
393
+	 * @param mixed $callback either a valid callback to the preprocessor or a simple name if it was autoloaded
394
+	 */
395
+	public function removePreProcessor($callback)
396
+	{
397
+		if (($index = array_search($callback, $this->processors['pre'], true)) !== false) {
398
+			unset($this->processors['pre'][$index]);
399
+		} elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
400
+					$callback),
401
+				$this->processors['pre'], true)) !== false) {
402
+			unset($this->processors['pre'][$index]);
403
+		} else {
404
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
405
+			foreach ($this->processors['pre'] as $index => $proc) {
406
+				if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
407
+					unset($this->processors['pre'][$index]);
408
+					break;
409
+				}
410
+			}
411
+		}
412
+	}
413
+
414
+	/**
415
+	 * Adds a postprocessor to the compiler, it will be called
416
+	 * before the template is compiled.
417
+	 *
418
+	 * @param mixed $callback either a valid callback to the postprocessor or a simple name if the autoload is set to
419
+	 *                        true
420
+	 * @param bool  $autoload if set to true, the postprocessor is auto-loaded from one of the plugin directories, else
421
+	 *                        you must provide a valid callback
422
+	 */
423
+	public function addPostProcessor($callback, $autoload = false)
424
+	{
425
+		if ($autoload) {
426
+			$name  = str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
427
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . Core::toCamelCase($name);
428
+
429
+			if (class_exists($class)) {
430
+				$callback = array(new $class($this), 'process');
431
+			} elseif (function_exists($class)) {
432
+				$callback = $class;
433
+			} else {
434
+				$callback = array('autoload' => true, 'class' => $class, 'name' => $name);
435
+			}
436
+
437
+			$this->processors['post'][] = $callback;
438
+		} else {
439
+			$this->processors['post'][] = $callback;
440
+		}
441
+	}
442
+
443
+	/**
444
+	 * Removes a postprocessor from the compiler.
445
+	 *
446
+	 * @param mixed $callback either a valid callback to the postprocessor or a simple name if it was autoloaded
447
+	 */
448
+	public function removePostProcessor($callback)
449
+	{
450
+		if (($index = array_search($callback, $this->processors['post'], true)) !== false) {
451
+			unset($this->processors['post'][$index]);
452
+		} elseif (($index = array_search(Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '',
453
+					$callback),
454
+				$this->processors['post'], true)) !== false) {
455
+			unset($this->processors['post'][$index]);
456
+		} else {
457
+			$class = Core::NAMESPACE_PLUGINS_PROCESSORS . str_replace(Core::NAMESPACE_PLUGINS_PROCESSORS, '', $callback);
458
+			foreach ($this->processors['post'] as $index => $proc) {
459
+				if (is_array($proc) && ($proc[0] instanceof $class) || (isset($proc['class']) && $proc['class'] == $class)) {
460
+					unset($this->processors['post'][$index]);
461
+					break;
462
+				}
463
+			}
464
+		}
465
+	}
466
+
467
+	/**
468
+	 * Internal function to autoload processors at runtime if required.
469
+	 *
470
+	 * @param string $class the class/function name
471
+	 * @param string $name  the plugin name (without Dwoo_Plugin_ prefix)
472
+	 *
473
+	 * @return array|string
474
+	 * @throws Exception
475
+	 */
476
+	protected function loadProcessor($class, $name)
477
+	{
478
+		if (!class_exists($class) && !function_exists($class)) {
479
+			try {
480
+				$this->getCore()->getLoader()->loadPlugin($name);
481
+			}
482
+			catch (Exception $e) {
483
+				throw new Exception('Processor ' . $name . ' could not be found in your plugin directories, please ensure it is in a file named ' . $name . '.php in the plugin directory');
484
+			}
485
+		}
486
+
487
+		if (class_exists($class)) {
488
+			return array(new $class($this), 'process');
489
+		}
490
+
491
+		if (function_exists($class)) {
492
+			return $class;
493
+		}
494
+
495
+		throw new Exception('Wrong processor name, when using autoload the processor must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Processor_name"');
496
+	}
497
+
498
+	/**
499
+	 * Adds an used plugin, this is reserved for use by the {template} plugin.
500
+	 * this is required so that plugin loading bubbles up from loaded
501
+	 * template files to the current one
502
+	 *
503
+	 * @private
504
+	 *
505
+	 * @param string $name function name
506
+	 * @param int    $type plugin type (Core::*_PLUGIN)
507
+	 */
508
+	public function addUsedPlugin($name, $type)
509
+	{
510
+		$this->usedPlugins[$name] = $type;
511
+	}
512
+
513
+	/**
514
+	 * Returns all the plugins this template uses.
515
+	 *
516
+	 * @private
517
+	 * @return  array the list of used plugins in the parsed template
518
+	 */
519
+	public function getUsedPlugins()
520
+	{
521
+		return $this->usedPlugins;
522
+	}
523
+
524
+	/**
525
+	 * Adds a template plugin, this is reserved for use by the {template} plugin.
526
+	 * this is required because the template functions are not declared yet
527
+	 * during compilation, so we must have a way of validating their argument
528
+	 * signature without using the reflection api
529
+	 *
530
+	 * @private
531
+	 *
532
+	 * @param string $name   function name
533
+	 * @param array  $params parameter array to help validate the function call
534
+	 * @param string $uuid   unique id of the function
535
+	 * @param string $body   function php code
536
+	 */
537
+	public function addTemplatePlugin($name, array $params, $uuid, $body = null)
538
+	{
539
+		$this->templatePlugins[$name] = array('params' => $params, 'body' => $body, 'uuid' => $uuid);
540
+	}
541
+
542
+	/**
543
+	 * Returns all the parsed sub-templates.
544
+	 *
545
+	 * @private
546
+	 * @return  array the parsed sub-templates
547
+	 */
548
+	public function getTemplatePlugins()
549
+	{
550
+		return $this->templatePlugins;
551
+	}
552
+
553
+	/**
554
+	 * Marks a template plugin as being called, which means its source must be included in the compiled template.
555
+	 *
556
+	 * @param string $name function name
557
+	 */
558
+	public function useTemplatePlugin($name)
559
+	{
560
+		$this->templatePlugins[$name]['called'] = true;
561
+	}
562
+
563
+	/**
564
+	 * Adds the custom plugins loaded into Dwoo to the compiler so it can load them.
565
+	 *
566
+	 * @see Core::addPlugin
567
+	 *
568
+	 * @param array $customPlugins an array of custom plugins
569
+	 */
570
+	public function setCustomPlugins(array $customPlugins)
571
+	{
572
+		$this->customPlugins = $customPlugins;
573
+	}
574
+
575
+	/**
576
+	 * Sets the security policy object to enforce some php security settings.
577
+	 * use this if untrusted persons can modify templates,
578
+	 * set it on the Dwoo object as it will be passed onto the compiler automatically
579
+	 *
580
+	 * @param SecurityPolicy $policy the security policy object
581
+	 */
582
+	public function setSecurityPolicy(SecurityPolicy $policy = null)
583
+	{
584
+		$this->securityPolicy = $policy;
585
+	}
586
+
587
+	/**
588
+	 * Returns the current security policy object or null by default.
589
+	 *
590
+	 * @return SecurityPolicy|null the security policy object if any
591
+	 */
592
+	public function getSecurityPolicy()
593
+	{
594
+		return $this->securityPolicy;
595
+	}
596
+
597
+	/**
598
+	 * Sets the pointer position.
599
+	 *
600
+	 * @param int  $position the new pointer position
601
+	 * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
602
+	 */
603
+	public function setPointer($position, $isOffset = false)
604
+	{
605
+		if ($isOffset) {
606
+			$this->pointer += $position;
607
+		} else {
608
+			$this->pointer = $position;
609
+		}
610
+	}
611
+
612
+	/**
613
+	 * Returns the current pointer position, only available during compilation of a template.
614
+	 *
615
+	 * @return int
616
+	 */
617
+	public function getPointer()
618
+	{
619
+		return $this->pointer;
620
+	}
621
+
622
+	/**
623
+	 * Sets the line number.
624
+	 *
625
+	 * @param int  $number   the new line number
626
+	 * @param bool $isOffset if set to true, the position acts as an offset and not an absolute position
627
+	 */
628
+	public function setLine($number, $isOffset = false)
629
+	{
630
+		if ($isOffset) {
631
+			$this->line += $number;
632
+		} else {
633
+			$this->line = $number;
634
+		}
635
+	}
636
+
637
+	/**
638
+	 * Returns the current line number, only available during compilation of a template.
639
+	 *
640
+	 * @return int
641
+	 */
642
+	public function getLine()
643
+	{
644
+		return $this->line;
645
+	}
646
+
647
+	/**
648
+	 * Returns the dwoo object that initiated this template compilation, only available during compilation of a
649
+	 * template.
650
+	 *
651
+	 * @return Core
652
+	 */
653
+	public function getCore()
654
+	{
655
+		return $this->core;
656
+	}
657
+
658
+	/**
659
+	 * Overwrites the template that is being compiled.
660
+	 *
661
+	 * @param string $newSource   the template source that must replace the current one
662
+	 * @param bool   $fromPointer if set to true, only the source from the current pointer position is replaced
663
+	 *
664
+	 * @return void
665
+	 */
666
+	public function setTemplateSource($newSource, $fromPointer = false)
667
+	{
668
+		if ($fromPointer === true) {
669
+			$this->templateSource = substr($this->templateSource, 0, $this->pointer) . $newSource;
670
+		} else {
671
+			$this->templateSource = $newSource;
672
+		}
673
+	}
674
+
675
+	/**
676
+	 * Returns the template that is being compiled.
677
+	 *
678
+	 * @param mixed $fromPointer if set to true, only the source from the current pointer
679
+	 *                           position is returned, if a number is given it overrides the current pointer
680
+	 *
681
+	 * @return string the template or partial template
682
+	 */
683
+	public function getTemplateSource($fromPointer = false)
684
+	{
685
+		if ($fromPointer === true) {
686
+			return substr($this->templateSource, $this->pointer);
687
+		} elseif (is_numeric($fromPointer)) {
688
+			return substr($this->templateSource, $fromPointer);
689
+		} else {
690
+			return $this->templateSource;
691
+		}
692
+	}
693
+
694
+	/**
695
+	 * Resets the compilation pointer, effectively restarting the compilation process.
696
+	 * this is useful if a plugin modifies the template source since it might need to be recompiled
697
+	 */
698
+	public function recompile()
699
+	{
700
+		$this->setPointer(0);
701
+	}
702
+
703
+	/**
704
+	 * Compiles the provided string down to php code.
705
+	 *
706
+	 * @param Core      $core
707
+	 * @param ITemplate $template the template to compile
708
+	 *
709
+	 * @return string a compiled php string
710
+	 * @throws CompilationException
711
+	 */
712
+	public function compile(Core $core, ITemplate $template)
713
+	{
714
+		// init vars
715
+		//		$compiled = '';
716
+		$tpl                  = $template->getSource();
717
+		$ptr                  = 0;
718
+		$this->core           = $core;
719
+		$this->template       = $template;
720
+		$this->templateSource = &$tpl;
721
+		$this->pointer        = &$ptr;
722
+
723
+		while (true) {
724
+			// if pointer is at the beginning, reset everything, that allows a plugin to externally reset the compiler if everything must be reparsed
725
+			if ($ptr === 0) {
726
+				// resets variables
727
+				$this->usedPlugins     = array();
728
+				$this->data            = array();
729
+				$this->scope           = &$this->data;
730
+				$this->scopeTree       = array();
731
+				$this->stack           = array();
732
+				$this->line            = 1;
733
+				$this->templatePlugins = array();
734
+				// add top level block
735
+				$compiled                 = $this->addBlock('TopLevelBlock', array(), 0);
736
+				$this->stack[0]['buffer'] = '';
737
+
738
+				if ($this->debug) {
739
+					echo "\n";
740
+					echo 'COMPILER INIT' . "\n";
741
+				}
742
+
743
+				if ($this->debug) {
744
+					echo 'PROCESSING PREPROCESSORS (' . count($this->processors['pre']) . ')' . "\n";
745
+				}
746
+
747
+				// runs preprocessors
748
+				foreach ($this->processors['pre'] as $preProc) {
749
+					if (is_array($preProc) && isset($preProc['autoload'])) {
750
+						$preProc = $this->loadProcessor($preProc['class'], $preProc['name']);
751
+					}
752
+					if (is_array($preProc) && $preProc[0] instanceof Processor) {
753
+						$tpl = call_user_func($preProc, $tpl);
754
+					} else {
755
+						$tpl = call_user_func($preProc, $this, $tpl);
756
+					}
757
+				}
758
+				unset($preProc);
759
+
760
+				// show template source if debug
761
+				if ($this->debug) {
762
+					echo '<pre>'.print_r(htmlentities($tpl), true).'</pre>'."\n";
763
+				}
764
+
765
+				// strips php tags if required by the security policy
766
+				if ($this->securityPolicy !== null) {
767
+					$search = array('{<\?php.*?\?>}');
768
+					if (ini_get('short_open_tags')) {
769
+						$search = array('{<\?.*?\?>}', '{<%.*?%>}');
770
+					}
771
+					switch ($this->securityPolicy->getPhpHandling()) {
772
+						case SecurityPolicy::PHP_ALLOW:
773
+							break;
774
+						case SecurityPolicy::PHP_ENCODE:
775
+							$tpl = preg_replace_callback($search, array($this, 'phpTagEncodingHelper'), $tpl);
776
+							break;
777
+						case SecurityPolicy::PHP_REMOVE:
778
+							$tpl = preg_replace($search, '', $tpl);
779
+					}
780
+				}
781
+			}
782
+
783
+			$pos = strpos($tpl, $this->ld, $ptr);
784
+
785
+			if ($pos === false) {
786
+				$this->push(substr($tpl, $ptr), 0);
787
+				break;
788
+			} elseif (substr($tpl, $pos - 1, 1) === '\\' && substr($tpl, $pos - 2, 1) !== '\\') {
789
+				$this->push(substr($tpl, $ptr, $pos - $ptr - 1) . $this->ld);
790
+				$ptr = $pos + strlen($this->ld);
791
+			} elseif (preg_match('/^' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . 'literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', substr($tpl, $pos), $litOpen)) {
792
+				if (!preg_match('/' . $this->ldr . ($this->allowLooseOpenings ? '\s*' : '') . '\/literal' . ($this->allowLooseOpenings ? '\s*' : '') . $this->rdr . '/s', $tpl, $litClose, PREG_OFFSET_CAPTURE, $pos)) {
793
+					throw new CompilationException($this, 'The {literal} blocks must be closed explicitly with {/literal}');
794
+				}
795
+				$endpos = $litClose[0][1];
796
+				$this->push(substr($tpl, $ptr, $pos - $ptr) . substr($tpl, $pos + strlen($litOpen[0]), $endpos - $pos - strlen($litOpen[0])));
797
+				$ptr = $endpos + strlen($litClose[0][0]);
798
+			} else {
799
+				if (substr($tpl, $pos - 2, 1) === '\\' && substr($tpl, $pos - 1, 1) === '\\') {
800
+					$this->push(substr($tpl, $ptr, $pos - $ptr - 1));
801
+					$ptr = $pos;
802
+				}
803
+
804
+				$this->push(substr($tpl, $ptr, $pos - $ptr));
805
+				$ptr = $pos;
806
+
807
+				$pos += strlen($this->ld);
808
+				if ($this->allowLooseOpenings) {
809
+					while (substr($tpl, $pos, 1) === ' ') {
810
+						$pos += 1;
811
+					}
812
+				} else {
813
+					if (substr($tpl, $pos, 1) === ' ' || substr($tpl, $pos, 1) === "\r" || substr($tpl, $pos, 1) === "\n" || substr($tpl, $pos, 1) === "\t") {
814
+						$ptr = $pos;
815
+						$this->push($this->ld);
816
+						continue;
817
+					}
818
+				}
819
+
820
+				// check that there is an end tag present
821
+				if (strpos($tpl, $this->rd, $pos) === false) {
822
+					throw new CompilationException($this, 'A template tag was not closed, started with "' . substr($tpl, $ptr, 30) . '"');
823
+				}
824
+
825
+				$ptr += strlen($this->ld);
826
+				$subptr = $ptr;
827
+
828
+				while (true) {
829
+					$parsed = $this->parse($tpl, $subptr, null, false, 'root', $subptr);
830
+
831
+					// reload loop if the compiler was reset
832
+					if ($ptr === 0) {
833
+						continue 2;
834
+					}
835
+
836
+					$len = $subptr - $ptr;
837
+					$this->push($parsed, substr_count(substr($tpl, $ptr, $len), "\n"));
838
+					$ptr += $len;
839
+
840
+					if ($parsed === false) {
841
+						break;
842
+					}
843
+				}
844
+			}
845
+		}
846
+
847
+		$compiled .= $this->removeBlock('TopLevelBlock');
848
+
849
+		if ($this->debug) {
850
+			echo 'PROCESSING POSTPROCESSORS' . "\n";
851
+		}
852
+
853
+		foreach ($this->processors['post'] as $postProc) {
854
+			if (is_array($postProc) && isset($postProc['autoload'])) {
855
+				$postProc = $this->loadProcessor($postProc['class'], $postProc['name']);
856
+			}
857
+			if (is_array($postProc) && $postProc[0] instanceof Processor) {
858
+				$compiled = call_user_func($postProc, $compiled);
859
+			} else {
860
+				$compiled = call_user_func($postProc, $this, $compiled);
861
+			}
862
+		}
863
+		unset($postProc);
864
+
865
+		if ($this->debug) {
866
+			echo 'COMPILATION COMPLETE : MEM USAGE : ' . memory_get_usage() . "\n";
867
+		}
868
+
869
+		$output = "<?php\n/* template head */\n";
870
+
871
+		// build plugin preloader
872
+		foreach ($this->getUsedPlugins() as $plugin => $type) {
873
+			if ($type & Core::CUSTOM_PLUGIN) {
874
+				continue;
875
+			}
876
+
877
+			switch ($type) {
878
+				case Core::CLASS_PLUGIN:
879
+				case Core::CLASS_PLUGIN + Core::BLOCK_PLUGIN:
880
+					if (class_exists('Plugin' . $plugin) !== false) {
881
+						$output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
882
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
883
+					} else {
884
+						$output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_BLOCKS . "Plugin" . $plugin . "')===false)".
885
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
886
+					}
887
+					break;
888
+				case Core::CLASS_PLUGIN + Core::FUNC_PLUGIN:
889
+					if (class_exists('Plugin' . $plugin) !== false) {
890
+						$output .= "if (class_exists('" . "Plugin" . $plugin . "')===false)".
891
+							"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
892
+					} else {
893
+						$output .= "if (class_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
894
+							"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
895
+					}
896
+					break;
897
+				case Core::FUNC_PLUGIN:
898
+					if (function_exists('Plugin' . $plugin) !== false) {
899
+						$output .= "if (function_exists('" . "Plugin" . $plugin . "')===false)".
900
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
901
+					} else {
902
+						$output .= "if (function_exists('" . Core::NAMESPACE_PLUGINS_FUNCTIONS . "Plugin" . $plugin . "')===false)".
903
+						"\n\t\$this->getLoader()->loadPlugin('Plugin$plugin');\n";
904
+					}
905
+					break;
906
+				case Core::SMARTY_MODIFIER:
907
+					$output .= "if (function_exists('smarty_modifier_$plugin')===false)".
908
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
909
+					break;
910
+				case Core::SMARTY_FUNCTION:
911
+					$output .= "if (function_exists('smarty_function_$plugin')===false)".
912
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
913
+					break;
914
+				case Core::SMARTY_BLOCK:
915
+					$output .= "if (function_exists('smarty_block_$plugin')===false)".
916
+					"\n\t\$this->getLoader()->loadPlugin('$plugin');\n";
917
+					break;
918
+				case Core::PROXY_PLUGIN:
919
+					$output .= $this->getCore()->getPluginProxy()->getLoader($plugin);
920
+					break;
921
+				default:
922
+					throw new CompilationException($this, 'Type error for ' . $plugin . ' with type' . $type);
923
+			}
924
+		}
925
+
926
+		foreach ($this->templatePlugins as $function => $attr) {
927
+			if (isset($attr['called']) && $attr['called'] === true && !isset($attr['checked'])) {
928
+				$this->resolveSubTemplateDependencies($function);
929
+			}
930
+		}
931
+		foreach ($this->templatePlugins as $function) {
932
+			if (isset($function['called']) && $function['called'] === true) {
933
+				$output .= $function['body'] . PHP_EOL;
934
+			}
935
+		}
936
+
937
+		$output .= $compiled . "\n?>";
938
+
939
+		$output = preg_replace('/(?<!;|\}|\*\/|\n|\{)(\s*' . preg_quote(self::PHP_CLOSE, '/') . preg_quote(self::PHP_OPEN, '/') . ')/', ";\n", $output);
940
+		$output = str_replace(self::PHP_CLOSE . self::PHP_OPEN, "\n", $output);
941
+
942
+		// handle <?xml tag at the beginning
943
+		$output = preg_replace('#(/\* template body \*/ \?>\s*)<\?xml#is', '$1<?php echo \'<?xml\'; ?>', $output);
944
+
945
+		// add another line break after PHP closing tags that have a line break following,
946
+		// as we do not know whether it's intended, and PHP will strip it otherwise
947
+		$output = preg_replace('/(?<!"|<\?xml)\s*\?>\n/', '$0' . "\n", $output);
948
+
949
+		if ($this->debug) {
950
+			echo '=============================================================================================' . "\n";
951
+			$lines = preg_split('{\r\n|\n|<br />}', $output);
952
+			array_shift($lines);
953
+			foreach ($lines as $i => $line) {
954
+				echo ($i + 1) . '. ' . $line . "\r\n";
955
+			}
956
+			echo '=============================================================================================' . "\n";
957
+		}
958
+
959
+		$this->template = $this->dwoo = null;
960
+		$tpl            = null;
961
+
962
+		return $output;
963
+	}
964
+
965
+	/**
966
+	 * Checks what sub-templates are used in every sub-template so that we're sure they are all compiled.
967
+	 *
968
+	 * @param string $function the sub-template name
969
+	 */
970
+	protected function resolveSubTemplateDependencies($function)
971
+	{
972
+		if ($this->debug) {
973
+			echo 'Compiler::' . __FUNCTION__ . "\n";
974
+		}
975
+
976
+		$body = $this->templatePlugins[$function]['body'];
977
+		foreach ($this->templatePlugins as $func => $attr) {
978
+			if ($func !== $function && !isset($attr['called']) && strpos($body, Core::NAMESPACE_PLUGINS_FUNCTIONS .
979
+			'Plugin' . Core::toCamelCase($func)) !== false) {
980
+				$this->templatePlugins[$func]['called'] = true;
981
+				$this->resolveSubTemplateDependencies($func);
982
+			}
983
+		}
984
+		$this->templatePlugins[$function]['checked'] = true;
985
+	}
986
+
987
+	/**
988
+	 * Adds compiled content to the current block.
989
+	 *
990
+	 * @param string $content   the content to push
991
+	 * @param int    $lineCount newlines count in content, optional
992
+	 *
993
+	 * @throws CompilationException
994
+	 */
995
+	public function push($content, $lineCount = null)
996
+	{
997
+		if ($lineCount === null) {
998
+			$lineCount = substr_count($content, "\n");
999
+		}
1000
+
1001
+		if ($this->curBlock['buffer'] === null && count($this->stack) > 1) {
1002
+			// buffer is not initialized yet (the block has just been created)
1003
+			$this->stack[count($this->stack) - 2]['buffer'] .= (string)$content;
1004
+			$this->curBlock['buffer'] = '';
1005
+		} else {
1006
+			if (!isset($this->curBlock['buffer'])) {
1007
+				throw new CompilationException($this, 'The template has been closed too early, you probably have an extra block-closing tag somewhere');
1008
+			}
1009
+			// append current content to current block's buffer
1010
+			$this->curBlock['buffer'] .= (string)$content;
1011
+		}
1012
+		$this->line += $lineCount;
1013
+	}
1014
+
1015
+	/**
1016
+	 * Sets the scope.
1017
+	 * set to null if the scope becomes "unstable" (i.e. too variable or unknown) so that
1018
+	 * variables are compiled in a more evaluative way than just $this->scope['key']
1019
+	 *
1020
+	 * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1021
+	 * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1022
+	 *
1023
+	 * @return array the current scope tree
1024
+	 */
1025
+	public function setScope($scope, $absolute = false)
1026
+	{
1027
+		$old = $this->scopeTree;
1028
+
1029
+		if ($scope === null) {
1030
+			unset($this->scope);
1031
+			$this->scope = null;
1032
+		}
1033
+
1034
+		if (is_array($scope) === false) {
1035
+			$scope = explode('.', $scope);
1036
+		}
1037
+
1038
+		if ($absolute === true) {
1039
+			$this->scope     = &$this->data;
1040
+			$this->scopeTree = array();
1041
+		}
1042
+
1043
+		while (($bit = array_shift($scope)) !== null) {
1044
+			if ($bit === '_parent' || $bit === '_') {
1045
+				array_pop($this->scopeTree);
1046
+				reset($this->scopeTree);
1047
+				$this->scope = &$this->data;
1048
+				$cnt         = count($this->scopeTree);
1049
+				for ($i = 0; $i < $cnt; ++ $i) {
1050
+					$this->scope = &$this->scope[$this->scopeTree[$i]];
1051
+				}
1052
+			} elseif ($bit === '_root' || $bit === '__') {
1053
+				$this->scope     = &$this->data;
1054
+				$this->scopeTree = array();
1055
+			} elseif (isset($this->scope[$bit])) {
1056
+				$this->scope       = &$this->scope[$bit];
1057
+				$this->scopeTree[] = $bit;
1058
+			} else {
1059
+				$this->scope[$bit] = array();
1060
+				$this->scope       = &$this->scope[$bit];
1061
+				$this->scopeTree[] = $bit;
1062
+			}
1063
+		}
1064
+
1065
+		return $old;
1066
+	}
1067
+
1068
+	/**
1069
+	 * Adds a block to the top of the block stack.
1070
+	 *
1071
+	 * @param string $type      block type (name)
1072
+	 * @param array  $params    the parameters array
1073
+	 * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1074
+	 *
1075
+	 * @return string the preProcessing() method's output
1076
+	 */
1077
+	public function addBlock($type, array $params, $paramtype)
1078
+	{
1079
+		if ($this->debug) {
1080
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1081
+		}
1082
+
1083
+		$class = current(array_filter([
1084
+			'Plugin' . Core::toCamelCase($type),
1085
+			Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type)
1086
+		], 'class_exists'));
1087
+		if (false === $class) {
1088
+			$this->getCore()->getLoader()->loadPlugin($type);
1089
+		}
1090
+		$params = $this->mapParams($params, array($class, 'init'), $paramtype);
1091
+
1092
+		$this->stack[]  = array(
1093
+			'type'   => $type,
1094
+			'params' => $params,
1095
+			'custom' => false,
1096
+			'class'  => $class,
1097
+			'buffer' => null
1098
+		);
1099
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1100
+
1101
+		return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1102
+	}
1103
+
1104
+	/**
1105
+	 * Adds a custom block to the top of the block stack.
1106
+	 *
1107
+	 * @param string $type      block type (name)
1108
+	 * @param array  $params    the parameters array
1109
+	 * @param int    $paramtype the parameters type (see mapParams), 0, 1 or 2
1110
+	 *
1111
+	 * @return string the preProcessing() method's output
1112
+	 */
1113
+	public function addCustomBlock($type, array $params, $paramtype)
1114
+	{
1115
+		$callback = $this->customPlugins[$type]['callback'];
1116
+		if (is_array($callback)) {
1117
+			$class = is_object($callback[0]) ? get_class($callback[0]) : $callback[0];
1118
+		} else {
1119
+			$class = $callback;
1120
+		}
1121
+
1122
+		$params = $this->mapParams($params, array($class, 'init'), $paramtype);
1123
+
1124
+		$this->stack[]  = array(
1125
+			'type'   => $type,
1126
+			'params' => $params,
1127
+			'custom' => true,
1128
+			'class'  => $class,
1129
+			'buffer' => null
1130
+		);
1131
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1132
+
1133
+		return call_user_func(array($class, 'preProcessing'), $this, $params, '', '', $type);
1134
+	}
1135
+
1136
+	/**
1137
+	 * Injects a block at the top of the plugin stack without calling its preProcessing method.
1138
+	 * used by {else} blocks to re-add themselves after having closed everything up to their parent
1139
+	 *
1140
+	 * @param string $type   block type (name)
1141
+	 * @param array  $params parameters array
1142
+	 */
1143
+	public function injectBlock($type, array $params)
1144
+	{
1145
+		if ($this->debug) {
1146
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1147
+		}
1148
+
1149
+		$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($type);
1150
+		if (class_exists($class) === false) {
1151
+			$this->getCore()->getLoader()->loadPlugin($type);
1152
+		}
1153
+		$this->stack[]  = array(
1154
+			'type'   => $type,
1155
+			'params' => $params,
1156
+			'custom' => false,
1157
+			'class'  => $class,
1158
+			'buffer' => null
1159
+		);
1160
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1161
+	}
1162
+
1163
+	/**
1164
+	 * Removes the closest-to-top block of the given type and all other
1165
+	 * blocks encountered while going down the block stack.
1166
+	 *
1167
+	 * @param string $type block type (name)
1168
+	 *
1169
+	 * @return string the output of all postProcessing() method's return values of the closed blocks
1170
+	 * @throws CompilationException
1171
+	 */
1172
+	public function removeBlock($type)
1173
+	{
1174
+		if ($this->debug) {
1175
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1176
+		}
1177
+
1178
+		$output = '';
1179
+
1180
+		$pluginType = $this->getPluginType($type);
1181
+		if ($pluginType & Core::SMARTY_BLOCK) {
1182
+			$type = 'Smartyinterface';
1183
+		}
1184
+		while (true) {
1185
+			while ($top = array_pop($this->stack)) {
1186
+				if ($top['custom']) {
1187
+					$class = $top['class'];
1188
+				} else {
1189
+					$class = current(array_filter([
1190
+						'Plugin' . Core::toCamelCase($top['type']),
1191
+						Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($top['type'])
1192
+					], 'class_exists'));
1193
+				}
1194
+				if (count($this->stack)) {
1195
+					$this->curBlock = &$this->stack[count($this->stack) - 1];
1196
+					$this->push(call_user_func(array(
1197
+						$class,
1198
+						'postProcessing'
1199
+					), $this, $top['params'], '', '', $top['buffer']), 0);
1200
+				} else {
1201
+					$null           = null;
1202
+					$this->curBlock = &$null;
1203
+					$output         = call_user_func(
1204
+						array(
1205
+						$class,
1206
+						'postProcessing'
1207
+						), $this, $top['params'], '', '', $top['buffer']
1208
+					);
1209
+				}
1210
+
1211
+				if ($top['type'] === $type) {
1212
+					break 2;
1213
+				}
1214
+			}
1215
+
1216
+			throw new CompilationException($this, 'Syntax malformation, a block of type "' . $type . '" was closed but was not opened');
1217
+		}
1218
+
1219
+		return $output;
1220
+	}
1221
+
1222
+	/**
1223
+	 * Returns a reference to the first block of the given type encountered and
1224
+	 * optionally closes all blocks until it finds it
1225
+	 * this is mainly used by {else} plugins to close everything that was opened
1226
+	 * between their parent and themselves.
1227
+	 *
1228
+	 * @param string $type       the block type (name)
1229
+	 * @param bool   $closeAlong whether to close all blocks encountered while going down the block stack or not
1230
+	 *
1231
+	 * @return mixed &array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1232
+	 *               'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1233
+	 * @throws CompilationException
1234
+	 */
1235
+	public function &findBlock($type, $closeAlong = false)
1236
+	{
1237
+		if ($closeAlong === true) {
1238
+			while ($b = end($this->stack)) {
1239
+				if ($b['type'] === $type) {
1240
+					return $this->stack[key($this->stack)];
1241
+				}
1242
+				$this->push($this->removeTopBlock(), 0);
1243
+			}
1244
+		} else {
1245
+			end($this->stack);
1246
+			while ($b = current($this->stack)) {
1247
+				if ($b['type'] === $type) {
1248
+					return $this->stack[key($this->stack)];
1249
+				}
1250
+				prev($this->stack);
1251
+			}
1252
+		}
1253
+
1254
+		throw new CompilationException($this, 'A parent block of type "' . $type . '" is required and can not be found');
1255
+	}
1256
+
1257
+	/**
1258
+	 * Returns a reference to the current block array.
1259
+	 *
1260
+	 * @return array the array is as such: array('type'=>pluginName, 'params'=>parameter array,
1261
+	 *                'custom'=>bool defining whether it's a custom plugin or not, for internal use)
1262
+	 */
1263
+	public function &getCurrentBlock()
1264
+	{
1265
+		return $this->curBlock;
1266
+	}
1267
+
1268
+	/**
1269
+	 * Removes the block at the top of the stack and calls its postProcessing() method.
1270
+	 *
1271
+	 * @return string the postProcessing() method's output
1272
+	 * @throws CompilationException
1273
+	 */
1274
+	public function removeTopBlock()
1275
+	{
1276
+		if ($this->debug) {
1277
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1278
+		}
1279
+
1280
+		$o = array_pop($this->stack);
1281
+		if ($o === null) {
1282
+			throw new CompilationException($this, 'Syntax malformation, a block of unknown type was closed but was not opened.');
1283
+		}
1284
+		if ($o['custom']) {
1285
+			$class = $o['class'];
1286
+		} else {
1287
+			$class = Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($o['type']);
1288
+		}
1289
+
1290
+		$this->curBlock = &$this->stack[count($this->stack) - 1];
1291
+
1292
+		return call_user_func(array($class, 'postProcessing'), $this, $o['params'], '', '', $o['buffer']);
1293
+	}
1294
+
1295
+	/**
1296
+	 * Returns the compiled parameters (for example a variable's compiled parameter will be "$this->scope['key']") out
1297
+	 * of the given parameter array.
1298
+	 *
1299
+	 * @param array $params parameter array
1300
+	 *
1301
+	 * @return array filtered parameters
1302
+	 */
1303
+	public function getCompiledParams(array $params)
1304
+	{
1305
+		foreach ($params as $k => $p) {
1306
+			if (is_array($p)) {
1307
+				$params[$k] = $p[0];
1308
+			}
1309
+		}
1310
+
1311
+		return $params;
1312
+	}
1313
+
1314
+	/**
1315
+	 * Returns the real parameters (for example a variable's real parameter will be its key, etc) out of the given
1316
+	 * parameter array.
1317
+	 *
1318
+	 * @param array $params parameter array
1319
+	 *
1320
+	 * @return array filtered parameters
1321
+	 */
1322
+	public function getRealParams(array $params)
1323
+	{
1324
+		foreach ($params as $k => $p) {
1325
+			if (is_array($p)) {
1326
+				$params[$k] = $p[1];
1327
+			}
1328
+		}
1329
+
1330
+		return $params;
1331
+	}
1332
+
1333
+	/**
1334
+	 * Returns the token of each parameter out of the given parameter array.
1335
+	 *
1336
+	 * @param array $params parameter array
1337
+	 *
1338
+	 * @return array tokens
1339
+	 */
1340
+	public function getParamTokens(array $params)
1341
+	{
1342
+		foreach ($params as $k => $p) {
1343
+			if (is_array($p)) {
1344
+				$params[$k] = isset($p[2]) ? $p[2] : 0;
1345
+			}
1346
+		}
1347
+
1348
+		return $params;
1349
+	}
1350
+
1351
+	/**
1352
+	 * Entry point of the parser, it redirects calls to other parse* functions.
1353
+	 *
1354
+	 * @param string $in            the string within which we must parse something
1355
+	 * @param int    $from          the starting offset of the parsed area
1356
+	 * @param int    $to            the ending offset of the parsed area
1357
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1358
+	 *                              default
1359
+	 * @param string $curBlock      the current parser-block being processed
1360
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1361
+	 *                              or null by default
1362
+	 *
1363
+	 * @return string parsed values
1364
+	 * @throws CompilationException
1365
+	 */
1366
+	protected function parse($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1367
+	{
1368
+		if ($this->debug) {
1369
+			echo 'Compiler::' . __FUNCTION__ . "\n";
1370
+		}
1371
+
1372
+		if ($to === null) {
1373
+			$to = strlen($in);
1374
+		}
1375
+		$first = substr($in, $from, 1);
1376
+
1377
+		if ($first === false) {
1378
+			throw new CompilationException($this, 'Unexpected EOF, a template tag was not closed');
1379
+		}
1380
+
1381
+		while ($first === ' ' || $first === "\n" || $first === "\t" || $first === "\r") {
1382
+			if ($curBlock === 'root' && substr($in, $from, strlen($this->rd)) === $this->rd) {
1383
+				// end template tag
1384
+				$pointer += strlen($this->rd);
1385
+				if ($this->debug) {
1386
+					echo 'TEMPLATE PARSING ENDED' . "\n";
1387
+				}
1388
+
1389
+				return false;
1390
+			}
1391
+			++ $from;
1392
+			if ($pointer !== null) {
1393
+				++ $pointer;
1394
+			}
1395
+			if ($from >= $to) {
1396
+				if (is_array($parsingParams)) {
1397
+					return $parsingParams;
1398
+				} else {
1399
+					return '';
1400
+				}
1401
+			}
1402
+			$first = $in[$from];
1403
+		}
1404
+
1405
+		$substr = substr($in, $from, $to - $from);
1406
+
1407
+		if ($this->debug) {
1408
+			echo 'PARSE CALL : PARSING "' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . '" @ ' . $from . ':' . $to . ' in ' . $curBlock . ' : pointer=' . $pointer . "\n";
1409
+		}
1410
+		$parsed = '';
1411
+
1412
+		if ($curBlock === 'root' && $first === '*') {
1413
+			$src      = $this->getTemplateSource();
1414
+			$startpos = $this->getPointer() - strlen($this->ld);
1415
+			if (substr($src, $startpos, strlen($this->ld)) === $this->ld) {
1416
+				if ($startpos > 0) {
1417
+					do {
1418
+						$char = substr($src, -- $startpos, 1);
1419
+						if ($char == "\n") {
1420
+							++ $startpos;
1421
+							$whitespaceStart = true;
1422
+							break;
1423
+						}
1424
+					}
1425
+					while ($startpos > 0 && ($char == ' ' || $char == "\t"));
1426
+				}
1427
+
1428
+				if (!isset($whitespaceStart)) {
1429
+					$startpos = $this->getPointer();
1430
+				} else {
1431
+					$pointer -= $this->getPointer() - $startpos;
1432
+				}
1433
+
1434
+				if ($this->allowNestedComments && strpos($src, $this->ld . '*', $this->getPointer()) !== false) {
1435
+					$comOpen  = $this->ld . '*';
1436
+					$comClose = '*' . $this->rd;
1437
+					$level    = 1;
1438
+					$ptr      = $this->getPointer();
1439
+
1440
+					while ($level > 0 && $ptr < strlen($src)) {
1441
+						$open  = strpos($src, $comOpen, $ptr);
1442
+						$close = strpos($src, $comClose, $ptr);
1443
+
1444
+						if ($open !== false && $close !== false) {
1445
+							if ($open < $close) {
1446
+								$ptr = $open + strlen($comOpen);
1447
+								++ $level;
1448
+							} else {
1449
+								$ptr = $close + strlen($comClose);
1450
+								-- $level;
1451
+							}
1452
+						} elseif ($open !== false) {
1453
+							$ptr = $open + strlen($comOpen);
1454
+							++ $level;
1455
+						} elseif ($close !== false) {
1456
+							$ptr = $close + strlen($comClose);
1457
+							-- $level;
1458
+						} else {
1459
+							$ptr = strlen($src);
1460
+						}
1461
+					}
1462
+					$endpos = $ptr - strlen('*' . $this->rd);
1463
+				} else {
1464
+					$endpos = strpos($src, '*' . $this->rd, $startpos);
1465
+					if ($endpos == false) {
1466
+						throw new CompilationException($this, 'Un-ended comment');
1467
+					}
1468
+				}
1469
+				$pointer += $endpos - $startpos + strlen('*' . $this->rd);
1470
+				if (isset($whitespaceStart) && preg_match('#^[\t ]*\r?\n#', substr($src, $endpos + strlen('*' . $this->rd)), $m)) {
1471
+					$pointer += strlen($m[0]);
1472
+					$this->curBlock['buffer'] = substr($this->curBlock['buffer'], 0, strlen($this->curBlock['buffer']) - ($this->getPointer() - $startpos - strlen($this->ld)));
1473
+				}
1474
+
1475
+				return false;
1476
+			}
1477
+		}
1478
+
1479
+		if ($first === '$') {
1480
+			// var
1481
+			$out    = $this->parseVar($in, $from, $to, $parsingParams, $curBlock, $pointer);
1482
+			$parsed = 'var';
1483
+		} elseif ($first === '%' && preg_match('#^%[a-z_\\\\]#i', $substr)) {
1484
+			// Short constant
1485
+			$out = $this->parseConst($in, $from, $to, $parsingParams, $curBlock, $pointer);
1486
+		} elseif (($first === '"' || $first === "'") && !(is_array($parsingParams) && preg_match('#^([\'"])[a-z0-9_]+\1\s*=>?(?:\s+|[^=])#i', $substr))) {
1487
+			// string
1488
+			$out = $this->parseString($in, $from, $to, $parsingParams, $curBlock, $pointer);
1489
+		} elseif (preg_match('/^\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?(' . (is_array($parsingParams) || $curBlock != 'root' ? '' : '\s+[^(]|') . '\s*\(|\s*' . $this->rdr . '|\s*;)/i', $substr)) {
1490
+			// func
1491
+			$out    = $this->parseFunction($in, $from, $to, $parsingParams, $curBlock, $pointer);
1492
+			$parsed = 'func';
1493
+		} elseif ($first === ';') {
1494
+			// instruction end
1495
+			if ($this->debug) {
1496
+				echo 'END OF INSTRUCTION' . "\n";
1497
+			}
1498
+			if ($pointer !== null) {
1499
+				++ $pointer;
1500
+			}
1501
+
1502
+			return $this->parse($in, $from + 1, $to, false, 'root', $pointer);
1503
+		} elseif ($curBlock === 'root' && preg_match('#^/([a-z_][a-z0-9_]*)?#i', $substr, $match)) {
1504
+			// close block
1505
+			if (!empty($match[1]) && $match[1] == 'else') {
1506
+				throw new CompilationException($this, 'Else blocks must not be closed explicitly, they are automatically closed when their parent block is closed');
1507
+			}
1508
+			if (!empty($match[1]) && $match[1] == 'elseif') {
1509
+				throw new CompilationException($this, 'Elseif blocks must not be closed explicitly, they are automatically closed when their parent block is closed or a new else/elseif block is declared after them');
1510
+			}
1511
+			if ($pointer !== null) {
1512
+				$pointer += strlen($match[0]);
1513
+			}
1514
+			if (empty($match[1])) {
1515
+				if ($this->curBlock['type'] == 'else' || $this->curBlock['type'] == 'elseif') {
1516
+					$pointer -= strlen($match[0]);
1517
+				}
1518
+				if ($this->debug) {
1519
+					echo 'TOP BLOCK CLOSED' . "\n";
1520
+				}
1521
+
1522
+				return $this->removeTopBlock();
1523
+			} else {
1524
+				if ($this->debug) {
1525
+					echo 'BLOCK OF TYPE ' . $match[1] . ' CLOSED' . "\n";
1526
+				}
1527
+
1528
+				return $this->removeBlock($match[1]);
1529
+			}
1530
+		} elseif ($curBlock === 'root' && substr($substr, 0, strlen($this->rd)) === $this->rd) {
1531
+			// end template tag
1532
+			if ($this->debug) {
1533
+				echo 'TAG PARSING ENDED' . "\n";
1534
+			}
1535
+			$pointer += strlen($this->rd);
1536
+
1537
+			return false;
1538
+		} elseif (is_array($parsingParams) && preg_match('#^(([\'"]?)[a-z0-9_]+\2\s*=' . ($curBlock === 'array' ? '>?' : '') . ')(?:\s+|[^=]).*#i', $substr, $match)) {
1539
+			// named parameter
1540
+			if ($this->debug) {
1541
+				echo 'NAMED PARAM FOUND' . "\n";
1542
+			}
1543
+			$len = strlen($match[1]);
1544
+			while (substr($in, $from + $len, 1) === ' ') {
1545
+				++ $len;
1546
+			}
1547
+			if ($pointer !== null) {
1548
+				$pointer += $len;
1549
+			}
1550
+
1551
+			$output = array(
1552
+				trim($match[1], " \t\r\n=>'\""),
1553
+				$this->parse($in, $from + $len, $to, false, 'namedparam', $pointer)
1554
+			);
1555
+
1556
+			$parsingParams[] = $output;
1557
+
1558
+			return $parsingParams;
1559
+		} elseif (preg_match('#^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*::\$[a-z0-9_]+)#i', $substr, $match)) {
1560
+			// static member access
1561
+			$parsed = 'var';
1562
+			if (is_array($parsingParams)) {
1563
+				$parsingParams[] = array($match[1], $match[1]);
1564
+				$out             = $parsingParams;
1565
+			} else {
1566
+				$out = $match[1];
1567
+			}
1568
+			$pointer += strlen($match[1]);
1569
+		} elseif ($substr !== '' && (is_array($parsingParams) || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'expression')) {
1570
+			// unquoted string, bool or number
1571
+			$out = $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1572
+		} else {
1573
+			// parse error
1574
+			throw new CompilationException($this, 'Parse error in "' . substr($in, $from, $to - $from) . '"');
1575
+		}
1576
+
1577
+		if (empty($out)) {
1578
+			return '';
1579
+		}
1580
+
1581
+		$substr = substr($in, $pointer, $to - $pointer);
1582
+
1583
+		// var parsed, check if any var-extension applies
1584
+		if ($parsed === 'var') {
1585
+			if (preg_match('#^\s*([/%+*-])\s*([a-z0-9]|\$)#i', $substr, $match)) {
1586
+				if ($this->debug) {
1587
+					echo 'PARSING POST-VAR EXPRESSION ' . $substr . "\n";
1588
+				}
1589
+				// parse expressions
1590
+				$pointer += strlen($match[0]) - 1;
1591
+				if (is_array($parsingParams)) {
1592
+					if ($match[2] == '$') {
1593
+						$expr = $this->parseVar($in, $pointer, $to, array(), $curBlock, $pointer);
1594
+					} else {
1595
+						$expr = $this->parse($in, $pointer, $to, array(), 'expression', $pointer);
1596
+					}
1597
+					$out[count($out) - 1][0] .= $match[1] . $expr[0][0];
1598
+					$out[count($out) - 1][1] .= $match[1] . $expr[0][1];
1599
+				} else {
1600
+					if ($match[2] == '$') {
1601
+						$expr = $this->parseVar($in, $pointer, $to, false, $curBlock, $pointer);
1602
+					} else {
1603
+						$expr = $this->parse($in, $pointer, $to, false, 'expression', $pointer);
1604
+					}
1605
+					if (is_array($out) && is_array($expr)) {
1606
+						$out[0] .= $match[1] . $expr[0];
1607
+						$out[1] .= $match[1] . $expr[1];
1608
+					} elseif (is_array($out)) {
1609
+						$out[0] .= $match[1] . $expr;
1610
+						$out[1] .= $match[1] . $expr;
1611
+					} elseif (is_array($expr)) {
1612
+						$out .= $match[1] . $expr[0];
1613
+					} else {
1614
+						$out .= $match[1] . $expr;
1615
+					}
1616
+				}
1617
+			} elseif ($curBlock === 'root' && preg_match('#^(\s*(?:[+/*%-.]=|=|\+\+|--)\s*)(.*)#s', $substr, $match)) {
1618
+				if ($this->debug) {
1619
+					echo 'PARSING POST-VAR ASSIGNMENT ' . $substr . "\n";
1620
+				}
1621
+				// parse assignment
1622
+				$value    = $match[2];
1623
+				$operator = trim($match[1]);
1624
+				if (substr($value, 0, 1) == '=') {
1625
+					throw new CompilationException($this, 'Unexpected "=" in <em>' . $substr . '</em>');
1626
+				}
1627
+
1628
+				if ($pointer !== null) {
1629
+					$pointer += strlen($match[1]);
1630
+				}
1631
+
1632
+				if ($operator !== '++' && $operator !== '--') {
1633
+					$parts = array();
1634
+					$ptr   = 0;
1635
+					$parts = $this->parse($value, 0, strlen($value), $parts, 'condition', $ptr);
1636
+					$pointer += $ptr;
1637
+
1638
+					// load if plugin
1639
+					try {
1640
+						$this->getPluginType('if');
1641
+					}
1642
+					catch (Exception $e) {
1643
+						throw new CompilationException($this, 'Assignments require the "if" plugin to be accessible');
1644
+					}
1645
+
1646
+					$parts  = $this->mapParams($parts, array(Core::NAMESPACE_PLUGINS_BLOCKS . 'PluginIf', 'init'), 1);
1647
+					$tokens = $this->getParamTokens($parts);
1648
+					$parts  = $this->getCompiledParams($parts);
1649
+
1650
+					$value = PluginIf::replaceKeywords($parts['*'], $tokens['*'], $this);
1651
+					$echo  = '';
1652
+				} else {
1653
+					$value = array();
1654
+					$echo  = 'echo ';
1655
+				}
1656
+
1657
+				if ($this->autoEscape) {
1658
+					$out = preg_replace('#\(is_string\(\$tmp=(.+?)\) \? htmlspecialchars\(\$tmp, ENT_QUOTES, \$this->charset\) : \$tmp\)#', '$1', $out);
1659
+				}
1660
+				$out = self::PHP_OPEN . $echo . $out . $operator . implode(' ', $value) . self::PHP_CLOSE;
1661
+			} elseif ($curBlock === 'array' && is_array($parsingParams) && preg_match('#^(\s*=>?\s*)#', $substr, $match)) {
1662
+				// parse namedparam with var as name (only for array)
1663
+				if ($this->debug) {
1664
+					echo 'VARIABLE NAMED PARAM (FOR ARRAY) FOUND' . "\n";
1665
+				}
1666
+				$len = strlen($match[1]);
1667
+				$var = $out[count($out) - 1];
1668
+				$pointer += $len;
1669
+
1670
+				$output = array($var[0], $this->parse($substr, $len, null, false, 'namedparam', $pointer));
1671
+
1672
+				$parsingParams[] = $output;
1673
+
1674
+				return $parsingParams;
1675
+			}
1676
+		}
1677
+
1678
+		if ($curBlock !== 'modifier' && ($parsed === 'func' || $parsed === 'var') && preg_match('#^(\|@?[a-z0-9_]+(:.*)?)+#i', $substr, $match)) {
1679
+			// parse modifier on funcs or vars
1680
+			$srcPointer = $pointer;
1681
+			if (is_array($parsingParams)) {
1682
+				$tmp                     = $this->replaceModifiers(
1683
+					array(
1684
+					null,
1685
+					null,
1686
+					$out[count($out) - 1][0],
1687
+					$match[0]
1688
+					), $curBlock, $pointer
1689
+				);
1690
+				$out[count($out) - 1][0] = $tmp;
1691
+				$out[count($out) - 1][1] .= substr($substr, $srcPointer, $srcPointer - $pointer);
1692
+			} else {
1693
+				$out = $this->replaceModifiers(array(null, null, $out, $match[0]), $curBlock, $pointer);
1694
+			}
1695
+		}
1696
+
1697
+		// func parsed, check if any func-extension applies
1698
+		if ($parsed === 'func' && preg_match('#^->[a-z0-9_]+(\s*\(.+|->[a-z_].*)?#is', $substr, $match)) {
1699
+			// parse method call or property read
1700
+			$ptr = 0;
1701
+
1702
+			if (is_array($parsingParams)) {
1703
+				$output = $this->parseMethodCall($out[count($out) - 1][1], $match[0], $curBlock, $ptr);
1704
+
1705
+				$out[count($out) - 1][0] = $output;
1706
+				$out[count($out) - 1][1] .= substr($match[0], 0, $ptr);
1707
+			} else {
1708
+				$out = $this->parseMethodCall($out, $match[0], $curBlock, $ptr);
1709
+			}
1710
+
1711
+			$pointer += $ptr;
1712
+		}
1713
+
1714
+		if ($curBlock === 'root' && substr($out, 0, strlen(self::PHP_OPEN)) !== self::PHP_OPEN) {
1715
+			return self::PHP_OPEN . 'echo ' . $out . ';' . self::PHP_CLOSE;
1716
+		}
1717
+
1718
+		return $out;
1719
+	}
1720
+
1721
+	/**
1722
+	 * Parses a function call.
1723
+	 *
1724
+	 * @param string $in            the string within which we must parse something
1725
+	 * @param int    $from          the starting offset of the parsed area
1726
+	 * @param int    $to            the ending offset of the parsed area
1727
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
1728
+	 *                              default
1729
+	 * @param string $curBlock      the current parser-block being processed
1730
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
1731
+	 *                              or null by default
1732
+	 *
1733
+	 * @return string parsed values
1734
+	 * @throws CompilationException
1735
+	 * @throws Exception
1736
+	 * @throws SecurityException
1737
+	 */
1738
+	protected function parseFunction($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
1739
+	{
1740
+		$output = '';
1741
+		$cmdstr = substr($in, $from, $to - $from);
1742
+		preg_match('/^(\\\\?[a-z_](?:\\\\?[a-z0-9_]+)*(?:::[a-z_][a-z0-9_]*)?)(\s*' . $this->rdr . '|\s*;)?/i', $cmdstr, $match);
1743
+
1744
+		if (empty($match[1])) {
1745
+			throw new CompilationException($this, 'Parse error, invalid function name : ' . substr($cmdstr, 0, 15));
1746
+		}
1747
+
1748
+		$func = $match[1];
1749
+
1750
+		if (!empty($match[2])) {
1751
+			$cmdstr = $match[1];
1752
+		}
1753
+
1754
+		if ($this->debug) {
1755
+			echo 'FUNC FOUND (' . $func . ')' . "\n";
1756
+		}
1757
+
1758
+		$paramsep = '';
1759
+
1760
+		if (is_array($parsingParams) || $curBlock != 'root') {
1761
+			$paramspos = strpos($cmdstr, '(');
1762
+			$paramsep  = ')';
1763
+		} elseif (preg_match_all('#^\s*[\\\\:a-z0-9_]+(\s*\(|\s+[^(])#i', $cmdstr, $match, PREG_OFFSET_CAPTURE)) {
1764
+			$paramspos = $match[1][0][1];
1765
+			$paramsep  = substr($match[1][0][0], - 1) === '(' ? ')' : '';
1766
+			if ($paramsep === ')') {
1767
+				$paramspos += strlen($match[1][0][0]) - 1;
1768
+				if (substr($cmdstr, 0, 2) === 'if' || substr($cmdstr, 0, 6) === 'elseif') {
1769
+					$paramsep = '';
1770
+					if (strlen($match[1][0][0]) > 1) {
1771
+						-- $paramspos;
1772
+					}
1773
+				}
1774
+			}
1775
+		} else {
1776
+			$paramspos = false;
1777
+		}
1778
+
1779
+		$state = 0;
1780
+
1781
+		if ($paramspos === false) {
1782
+			$params = array();
1783
+
1784
+			if ($curBlock !== 'root') {
1785
+				return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1786
+			}
1787
+		} else {
1788
+			if ($curBlock === 'condition') {
1789
+				// load if plugin
1790
+				$this->getPluginType('if');
1791
+
1792
+				if (PluginIf::replaceKeywords(array($func), array(self::T_UNQUOTED_STRING), $this) !== array($func)) {
1793
+					return $this->parseOthers($in, $from, $to, $parsingParams, $curBlock, $pointer);
1794
+				}
1795
+			}
1796
+			$whitespace = strlen(substr($cmdstr, strlen($func), $paramspos - strlen($func)));
1797
+			$paramstr   = substr($cmdstr, $paramspos + 1);
1798
+			if (substr($paramstr, - 1, 1) === $paramsep) {
1799
+				$paramstr = substr($paramstr, 0, - 1);
1800
+			}
1801
+
1802
+			if (strlen($paramstr) === 0) {
1803
+				$params   = array();
1804
+				$paramstr = '';
1805
+			} else {
1806
+				$ptr    = 0;
1807
+				$params = array();
1808
+				if ($func === 'empty') {
1809
+					$params = $this->parseVar($paramstr, $ptr, strlen($paramstr), $params, 'root', $ptr);
1810
+				} else {
1811
+					while ($ptr < strlen($paramstr)) {
1812
+						while (true) {
1813
+							if ($ptr >= strlen($paramstr)) {
1814
+								break 2;
1815
+							}
1816
+
1817
+							if ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === ')') {
1818
+								if ($this->debug) {
1819
+									echo 'PARAM PARSING ENDED, ")" FOUND, POINTER AT ' . $ptr . "\n";
1820
+								}
1821
+								break 2;
1822
+							} elseif ($paramstr[$ptr] === ';') {
1823
+								++ $ptr;
1824
+								if ($this->debug) {
1825
+									echo 'PARAM PARSING ENDED, ";" FOUND, POINTER AT ' . $ptr . "\n";
1826
+								}
1827
+								break 2;
1828
+							} elseif ($func !== 'if' && $func !== 'elseif' && $paramstr[$ptr] === '/') {
1829
+								if ($this->debug) {
1830
+									echo 'PARAM PARSING ENDED, "/" FOUND, POINTER AT ' . $ptr . "\n";
1831
+								}
1832
+								break 2;
1833
+							} elseif (substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
1834
+								if ($this->debug) {
1835
+									echo 'PARAM PARSING ENDED, RIGHT DELIMITER FOUND, POINTER AT ' . $ptr . "\n";
1836
+								}
1837
+								break 2;
1838
+							}
1839
+
1840
+							if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === ',' || $paramstr[$ptr] === "\r" || $paramstr[$ptr] === "\n" || $paramstr[$ptr] === "\t") {
1841
+								++ $ptr;
1842
+							} else {
1843
+								break;
1844
+							}
1845
+						}
1846
+
1847
+						if ($this->debug) {
1848
+							echo 'FUNC START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
1849
+						}
1850
+
1851
+						if ($func === 'if' || $func === 'elseif' || $func === 'tif') {
1852
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'condition', $ptr);
1853
+						} elseif ($func === 'array') {
1854
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'array', $ptr);
1855
+						} else {
1856
+							$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'function', $ptr);
1857
+						}
1858
+
1859
+						if ($this->debug) {
1860
+							echo 'PARAM PARSED, POINTER AT ' . $ptr . ' (' . substr($paramstr, $ptr - 1, 3) . ')' . "\n";
1861
+						}
1862
+					}
1863
+				}
1864
+				$paramstr = substr($paramstr, 0, $ptr);
1865
+				$state    = 0;
1866
+				foreach ($params as $k => $p) {
1867
+					if (is_array($p) && is_array($p[1])) {
1868
+						$state |= 2;
1869
+					} else {
1870
+						if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m) && $func !== 'array') {
1871
+							$params[$k] = array($m[2], array('true', 'true'));
1872
+						} else {
1873
+							if ($state & 2 && $func !== 'array') {
1874
+								throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
1875
+							}
1876
+							$state |= 1;
1877
+						}
1878
+					}
1879
+				}
1880
+			}
1881
+		}
1882
+
1883
+		if ($pointer !== null) {
1884
+			$pointer += (isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func) + (isset($whitespace) ? $whitespace : 0);
1885
+			if ($this->debug) {
1886
+				echo 'FUNC ADDS ' . ((isset($paramstr) ? strlen($paramstr) : 0) + (')' === $paramsep ? 2 : ($paramspos === false ? 0 : 1)) + strlen($func)) . ' TO POINTER' . "\n";
1887
+			}
1888
+		}
1889
+
1890
+		if ($curBlock === 'method' || $func === 'do' || strstr($func, '::') !== false) {
1891
+			// handle static method calls with security policy
1892
+			if (strstr($func, '::') !== false && $this->securityPolicy !== null && $this->securityPolicy->isMethodAllowed(explode('::', strtolower($func))) !== true) {
1893
+				throw new SecurityException('Call to a disallowed php function : ' . $func);
1894
+			}
1895
+			$pluginType = Core::NATIVE_PLUGIN;
1896
+		} else {
1897
+			$pluginType = $this->getPluginType($func);
1898
+		}
1899
+
1900
+		// Blocks plugin
1901
+		if ($pluginType & Core::BLOCK_PLUGIN) {
1902
+			if ($curBlock !== 'root' || is_array($parsingParams)) {
1903
+				throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1904
+			}
1905
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1906
+				return $this->addCustomBlock($func, $params, $state);
1907
+			} else {
1908
+				return $this->addBlock($func, $params, $state);
1909
+			}
1910
+		} elseif ($pluginType & Core::SMARTY_BLOCK) {
1911
+			if ($curBlock !== 'root' || is_array($parsingParams)) {
1912
+				throw new CompilationException($this, 'Block plugins can not be used as other plugin\'s arguments');
1913
+			}
1914
+
1915
+			if ($state & 2) {
1916
+				array_unshift($params, array('__functype', array($pluginType, $pluginType)));
1917
+				array_unshift($params, array('__funcname', array($func, $func)));
1918
+			} else {
1919
+				array_unshift($params, array($pluginType, $pluginType));
1920
+				array_unshift($params, array($func, $func));
1921
+			}
1922
+
1923
+			return $this->addBlock('smartyinterface', $params, $state);
1924
+		}
1925
+
1926
+		// Native & Smarty plugins
1927
+		if ($pluginType & Core::NATIVE_PLUGIN || $pluginType & Core::SMARTY_FUNCTION || $pluginType & Core::SMARTY_BLOCK) {
1928
+			$params = $this->mapParams($params, null, $state);
1929
+		} // PHP class plugin
1930
+		elseif ($pluginType & Core::CLASS_PLUGIN) {
1931
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1932
+				$params = $this->mapParams(
1933
+					$params, array(
1934
+					$this->customPlugins[$func]['class'],
1935
+					$this->customPlugins[$func]['function']
1936
+				), $state);
1937
+			} else {
1938
+				if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
1939
+					$params = $this->mapParams($params, array(
1940
+						'Plugin' . Core::toCamelCase($func),
1941
+						($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1942
+					), $state);
1943
+				} elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
1944
+					$params = $this->mapParams($params, array(
1945
+						Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func),
1946
+						($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1947
+					), $state);
1948
+				} else {
1949
+					$params = $this->mapParams($params, array(
1950
+						Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
1951
+						($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process'
1952
+					), $state);
1953
+				}
1954
+			}
1955
+		} // PHP function plugin
1956
+		elseif ($pluginType & Core::FUNC_PLUGIN) {
1957
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
1958
+				$params = $this->mapParams($params, $this->customPlugins[$func]['callback'], $state);
1959
+			} else {
1960
+				// Custom plugin
1961
+				if (function_exists('Plugin' . Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ?
1962
+						'Compile' : '')) !== false) {
1963
+					$params = $this->mapParams($params, 'Plugin' . Core::toCamelCase($func) . (($pluginType &
1964
+							Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1965
+				} // Builtin helper plugin
1966
+				elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . (
1967
+					($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '')) !== false) {
1968
+					$params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase
1969
+						($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1970
+				} // Builtin function plugin
1971
+				else {
1972
+					$params = $this->mapParams($params, Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase
1973
+						($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''), $state);
1974
+				}
1975
+			}
1976
+		} // Smarty modifier
1977
+		elseif ($pluginType & Core::SMARTY_MODIFIER) {
1978
+			$output = 'smarty_modifier_' . $func . '(' . implode(', ', $params) . ')';
1979
+		} // Proxy plugin
1980
+		elseif ($pluginType & Core::PROXY_PLUGIN) {
1981
+			$params = $this->mapParams($params, $this->getCore()->getPluginProxy()->getCallback($func), $state);
1982
+		} // Template plugin
1983
+		elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
1984
+			// transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
1985
+			$map = array();
1986
+			foreach ($this->templatePlugins[$func]['params'] as $param => $defValue) {
1987
+				if ($param == 'rest') {
1988
+					$param = '*';
1989
+				}
1990
+				$hasDefault = $defValue !== null;
1991
+				if ($defValue === 'null') {
1992
+					$defValue = null;
1993
+				} elseif ($defValue === 'false') {
1994
+					$defValue = false;
1995
+				} elseif ($defValue === 'true') {
1996
+					$defValue = true;
1997
+				} elseif (preg_match('#^([\'"]).*?\1$#', $defValue)) {
1998
+					$defValue = substr($defValue, 1, - 1);
1999
+				}
2000
+				$map[] = array($param, $hasDefault, $defValue);
2001
+			}
2002
+
2003
+			$params = $this->mapParams($params, null, $state, $map);
2004
+		}
2005
+
2006
+		// only keep php-syntax-safe values for non-block plugins
2007
+		$tokens = array();
2008
+		foreach ($params as $k => $p) {
2009
+			$tokens[$k] = isset($p[2]) ? $p[2] : 0;
2010
+			$params[$k] = $p[0];
2011
+		}
2012
+
2013
+		// Native plugin
2014
+		if ($pluginType & Core::NATIVE_PLUGIN) {
2015
+			if ($func === 'do') {
2016
+				$output = '';
2017
+				if (isset($params['*'])) {
2018
+					$output = implode(';', $params['*']) . ';';
2019
+				}
2020
+
2021
+				if (is_array($parsingParams) || $curBlock !== 'root') {
2022
+					throw new CompilationException($this, 'Do can not be used inside another function or block');
2023
+				}
2024
+
2025
+				return self::PHP_OPEN . $output . self::PHP_CLOSE;
2026
+			} else {
2027
+				if (isset($params['*'])) {
2028
+					$output = $func . '(' . implode(', ', $params['*']) . ')';
2029
+				} else {
2030
+					$output = $func . '()';
2031
+				}
2032
+			}
2033
+		} // Block class OR Function class
2034
+		elseif ($pluginType & Core::CLASS_PLUGIN || ($pluginType & Core::FUNC_PLUGIN && $pluginType & Core::CLASS_PLUGIN)) {
2035
+			if ($pluginType & Core::COMPILABLE_PLUGIN) {
2036
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2037
+					$callback = $this->customPlugins[$func]['callback'];
2038
+					if (!is_array($callback)) {
2039
+						if (!method_exists($callback, 'compile')) {
2040
+							throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
2041
+						}
2042
+						if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
2043
+							$funcCompiler = array($callback, 'compile');
2044
+						} else {
2045
+							$funcCompiler = array(new $callback(), 'compile');
2046
+						}
2047
+					} else {
2048
+						$funcCompiler = $callback;
2049
+					}
2050
+				} else {
2051
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2052
+						$funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
2053
+					} elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2054
+						$funcCompiler = array(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func), 'compile');
2055
+					} else {
2056
+						$funcCompiler = array(
2057
+							Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func),
2058
+							'compile'
2059
+						);
2060
+					}
2061
+					array_unshift($params, $this);
2062
+				}
2063
+				// @TODO: Is it a real fix ?
2064
+				if ($func === 'tif') {
2065
+					$params[] = $tokens;
2066
+				}
2067
+				$output = call_user_func_array($funcCompiler, $params);
2068
+			} else {
2069
+				$params = self::implode_r($params);
2070
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2071
+					$callback = $this->customPlugins[$func]['callback'];
2072
+					if (!is_array($callback)) {
2073
+						if (!method_exists($callback, 'process')) {
2074
+							throw new Exception('Custom plugin ' . $func . ' must implement the "process" method to be usable, or you should provide a full callback to the method to use');
2075
+						}
2076
+						if (is_object($callback)) {
2077
+							$callback = get_class($callback);
2078
+						}
2079
+						if (($ref = new ReflectionMethod($callback, 'process')) && $ref->isStatic()) {
2080
+							$output = 'call_user_func(array(\'' . $callback . '\', \'process\'), ' . $params . ')';
2081
+						} else {
2082
+							$output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback . '\'), \'process\'), ' . $params . ')';
2083
+						}
2084
+					} elseif (is_object($callback[0])) {
2085
+						$output = 'call_user_func(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), ' . $params . ')';
2086
+					} elseif (($ref = new ReflectionMethod($callback[0], $callback[1])) && $ref->isStatic()) {
2087
+						$output = 'call_user_func(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), ' . $params . ')';
2088
+					} else {
2089
+						$output = 'call_user_func(array($this->getObjectPlugin(\'' . $callback[0] . '\'), \'' . $callback[1] . '\'), ' . $params . ')';
2090
+					}
2091
+					if (empty($params)) {
2092
+						$output = substr($output, 0, - 3) . ')';
2093
+					}
2094
+				} else {
2095
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2096
+						$output = '$this->classCall(\'Plugin' . $func . '\', array(' . $params . '))';
2097
+					} elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
2098
+						$output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\',
2099 2099
                         array(' . $params . '))';
2100
-                    } else {
2101
-                        $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
2102
-                    }
2103
-                }
2104
-            }
2105
-        } // Function plugin only (cannot be a class)
2106
-        elseif ($pluginType & Core::FUNC_PLUGIN) {
2107
-            if ($pluginType & Core::COMPILABLE_PLUGIN) {
2108
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2109
-                    $funcCompiler = $this->customPlugins[$func]['callback'];
2110
-                } else {
2111
-                    // Custom plugin
2112
-                    if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2113
-                        $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
2114
-                    } // Builtin helper plugin
2115
-                    elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2116
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2117
-                            'Compile';
2118
-                    } // Builtin function plugin
2119
-                    else {
2120
-                        $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
2121
-                            'Compile';
2122
-                    }
2123
-                }
2124
-                array_unshift($params, $this);
2125
-                // @TODO: Is it a real fix ?
2126
-                if ($func === 'tif') {
2127
-                    $params[] = $tokens;
2128
-                }
2129
-                $output = call_user_func_array($funcCompiler, $params);
2130
-            } else {
2131
-                array_unshift($params, '$this');
2132
-                $params = self::implode_r($params);
2133
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
2134
-                    $callback = $this->customPlugins[$func]['callback'];
2135
-                    if ($callback instanceof Closure) {
2136
-                        $output = 'call_user_func($this->getCustomPlugin(\'' . $func . '\'), ' . $params . ')';
2137
-                    } else {
2138
-                        $output = 'call_user_func(\'' . $callback . '\', ' . $params . ')';
2139
-                    }
2140
-                } else {
2141
-                    // Custom plugin
2142
-                    if (function_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2143
-                        $output = 'Plugin' . Core::toCamelCase($func) . '(' . $params .
2144
-                            ')';
2145
-                    } // Builtin helper plugin
2146
-                    elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !==
2147
-                        false) {
2148
-                        $output = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . '(' .
2149
-                            $params . ')';
2150
-                    } // Builtin function plugin
2151
-                    else {
2152
-                        $output = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '(' .
2153
-                            $params . ')';
2154
-                    }
2155
-                }
2156
-            }
2157
-        } // Proxy plugin
2158
-        elseif ($pluginType & Core::PROXY_PLUGIN) {
2159
-            $output = call_user_func(array($this->getCore()->getPluginProxy(), 'getCode'), $func, $params);
2160
-        } // Smarty function (@deprecated)
2161
-        elseif ($pluginType & Core::SMARTY_FUNCTION) {
2162
-            $params = '';
2163
-            if (isset($params['*'])) {
2164
-                $params = self::implode_r($params['*'], true);
2165
-            }
2166
-
2167
-            if ($pluginType & Core::CUSTOM_PLUGIN) {
2168
-                $callback = $this->customPlugins[$func]['callback'];
2169
-                if (is_array($callback)) {
2170
-                    if (is_object($callback[0])) {
2171
-                        $output = 'call_user_func_array(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2172
-                    } else {
2173
-                        $output = 'call_user_func_array(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2174
-                    }
2175
-                } else {
2176
-                    $output = $callback . '(array(' . $params . '), $this)';
2177
-                }
2178
-            } else {
2179
-                $output = 'smarty_function_' . $func . '(array(' . $params . '), $this)';
2180
-            }
2181
-        } // Template plugin
2182
-        elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
2183
-            array_unshift($params, '$this');
2184
-            $params                                 = self::implode_r($params);
2185
-            $output                                 = 'Plugin' . Core::toCamelCase($func) .
2186
-                $this->templatePlugins[$func]['uuid'] . '(' . $params . ')';
2187
-            $this->templatePlugins[$func]['called'] = true;
2188
-        }
2189
-
2190
-        if (is_array($parsingParams)) {
2191
-            $parsingParams[] = array($output, $output);
2192
-
2193
-            return $parsingParams;
2194
-        } elseif ($curBlock === 'namedparam') {
2195
-            return array($output, $output);
2196
-        }
2197
-
2198
-        return $output;
2199
-    }
2200
-
2201
-    /**
2202
-     * Parses a string.
2203
-     *
2204
-     * @param string $in            the string within which we must parse something
2205
-     * @param int    $from          the starting offset of the parsed area
2206
-     * @param int    $to            the ending offset of the parsed area
2207
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2208
-     *                              default
2209
-     * @param string $curBlock      the current parser-block being processed
2210
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2211
-     *                              or null by default
2212
-     *
2213
-     * @return string parsed values
2214
-     * @throws CompilationException
2215
-     */
2216
-    protected function parseString($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2217
-    {
2218
-        $substr = substr($in, $from, $to - $from);
2219
-        $first  = $substr[0];
2220
-
2221
-        if ($this->debug) {
2222
-            echo 'STRING FOUND (in ' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . ')' . "\n";
2223
-        }
2224
-        $strend = false;
2225
-        $o      = $from + 1;
2226
-        while ($strend === false) {
2227
-            $strend = strpos($in, $first, $o);
2228
-            if ($strend === false) {
2229
-                throw new CompilationException($this, 'Unfinished string, started with ' . substr($in, $from, $to - $from));
2230
-            }
2231
-            if (substr($in, $strend - 1, 1) === '\\') {
2232
-                $o      = $strend + 1;
2233
-                $strend = false;
2234
-            }
2235
-        }
2236
-        if ($this->debug) {
2237
-            echo 'STRING DELIMITED: ' . substr($in, $from, $strend + 1 - $from) . "\n";
2238
-        }
2239
-
2240
-        $srcOutput = substr($in, $from, $strend + 1 - $from);
2241
-
2242
-        if ($pointer !== null) {
2243
-            $pointer += strlen($srcOutput);
2244
-        }
2245
-
2246
-        $output = $this->replaceStringVars($srcOutput, $first);
2247
-
2248
-        // handle modifiers
2249
-        if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend + 1 - $from), $match)) {
2250
-            $modstr = $match[1];
2251
-
2252
-            if ($curBlock === 'root' && substr($modstr, - 1) === '}') {
2253
-                $modstr = substr($modstr, 0, - 1);
2254
-            }
2255
-            $modstr = str_replace('\\' . $first, $first, $modstr);
2256
-            $ptr    = 0;
2257
-            $output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr);
2258
-
2259
-            $strend += $ptr;
2260
-            if ($pointer !== null) {
2261
-                $pointer += $ptr;
2262
-            }
2263
-            $srcOutput .= substr($substr, $strend + 1 - $from, $ptr);
2264
-        }
2265
-
2266
-        if (is_array($parsingParams)) {
2267
-            $parsingParams[] = array($output, substr($srcOutput, 1, - 1));
2268
-
2269
-            return $parsingParams;
2270
-        } elseif ($curBlock === 'namedparam') {
2271
-            return array($output, substr($srcOutput, 1, - 1));
2272
-        }
2273
-
2274
-        return $output;
2275
-    }
2276
-
2277
-    /**
2278
-     * Parses a constant.
2279
-     *
2280
-     * @param string $in            the string within which we must parse something
2281
-     * @param int    $from          the starting offset of the parsed area
2282
-     * @param int    $to            the ending offset of the parsed area
2283
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2284
-     *                              default
2285
-     * @param string $curBlock      the current parser-block being processed
2286
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2287
-     *                              or null by default
2288
-     *
2289
-     * @return string parsed values
2290
-     * @throws CompilationException
2291
-     */
2292
-    protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2293
-    {
2294
-        $substr = substr($in, $from, $to - $from);
2295
-
2296
-        if ($this->debug) {
2297
-            echo 'CONST FOUND : ' . $substr . "\n";
2298
-        }
2299
-
2300
-        if (!preg_match('#^%([\\\\a-z0-9_:]+)#i', $substr, $m)) {
2301
-            throw new CompilationException($this, 'Invalid constant');
2302
-        }
2303
-
2304
-        if ($pointer !== null) {
2305
-            $pointer += strlen($m[0]);
2306
-        }
2307
-
2308
-        $output = $this->parseConstKey($m[1], $curBlock);
2309
-
2310
-        if (is_array($parsingParams)) {
2311
-            $parsingParams[] = array($output, $m[1]);
2312
-
2313
-            return $parsingParams;
2314
-        } elseif ($curBlock === 'namedparam') {
2315
-            return array($output, $m[1]);
2316
-        }
2317
-
2318
-        return $output;
2319
-    }
2320
-
2321
-    /**
2322
-     * Parses a constant.
2323
-     *
2324
-     * @param string $key      the constant to parse
2325
-     * @param string $curBlock the current parser-block being processed
2326
-     *
2327
-     * @return string parsed constant
2328
-     */
2329
-    protected function parseConstKey($key, $curBlock)
2330
-    {
2331
-        $key = str_replace('\\\\', '\\', $key);
2332
-
2333
-        if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling() === SecurityPolicy::CONST_DISALLOW) {
2334
-            return 'null';
2335
-        }
2336
-
2337
-        if ($curBlock !== 'root') {
2338
-            return '(defined("' . $key . '") ? ' . $key . ' : null)';
2339
-        }
2340
-
2341
-        return $key;
2342
-    }
2343
-
2344
-    /**
2345
-     * Parses a variable.
2346
-     *
2347
-     * @param string $in            the string within which we must parse something
2348
-     * @param int    $from          the starting offset of the parsed area
2349
-     * @param int    $to            the ending offset of the parsed area
2350
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2351
-     *                              default
2352
-     * @param string $curBlock      the current parser-block being processed
2353
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2354
-     *                              or null by default
2355
-     *
2356
-     * @return string parsed values
2357
-     * @throws CompilationException
2358
-     */
2359
-    protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2360
-    {
2361
-        $substr = substr($in, $from, $to - $from);
2362
-
2363
-        // var key
2364
-        $varRegex = '(\\$?\\.?[a-z0-9\\\\_:]*(?:(?:(?:\\.|->)(?:[a-z0-9\\\\_:]+|(?R))|\\[(?:[a-z0-9\\\\_:]+|(?R)|(["\'])[^\\2]*?\\2)\\]))*)';
2365
-        // method call
2366
-        $methodCall = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'expression' || $curBlock === 'delimited_string' ? '(\(.*)?' : '()');
2367
-        // simple math expressions
2368
-        $simpleMathExpressions = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'delimited_string' ? '((?:(?:[+\/*%=-])(?:(?<!=)=?-?[$%][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|(?<!=)=?-?[0-9\.,]*|[+-]))*)' : '()');
2369
-        // modifiers
2370
-        $modifiers = $curBlock !== 'modifier' ? '((?:\|(?:@?[a-z0-9\\\\_]+(?:(?::("|\').*?\5|:[^`]*))*))+)?' : '(())';
2371
-
2372
-        $regex = '#';
2373
-        $regex .= $varRegex;
2374
-        $regex .= $methodCall;
2375
-        $regex .= $simpleMathExpressions;
2376
-        $regex .= $modifiers;
2377
-        $regex .= '#i';
2378
-
2379
-        if (preg_match($regex, $substr, $match)) {
2380
-            $key = substr($match[1], 1);
2381
-
2382
-            $matchedLength = strlen($match[0]);
2383
-            $hasModifiers  = !empty($match[5]);
2384
-            $hasExpression = !empty($match[4]);
2385
-            $hasMethodCall = !empty($match[3]);
2386
-
2387
-            if (substr($key, - 1) == '.') {
2388
-                $key = substr($key, 0, - 1);
2389
-                -- $matchedLength;
2390
-            }
2391
-
2392
-            if ($hasMethodCall) {
2393
-                $matchedLength -= strlen($match[3]) + strlen(substr($match[1], strrpos($match[1], '->')));
2394
-                $key        = substr($match[1], 1, strrpos($match[1], '->') - 1);
2395
-                $methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3];
2396
-            }
2397
-
2398
-            if ($hasModifiers) {
2399
-                $matchedLength -= strlen($match[5]);
2400
-            }
2401
-
2402
-            if ($pointer !== null) {
2403
-                $pointer += $matchedLength;
2404
-            }
2405
-
2406
-            // replace useless brackets by dot accessed vars and strip enclosing quotes if present
2407
-            $key = preg_replace('#\[(["\']?)([^$%\[.>-]+)\1\]#', '.$2', $key);
2408
-
2409
-            if ($this->debug) {
2410
-                if ($hasMethodCall) {
2411
-                    echo 'METHOD CALL FOUND : $' . $key . substr($methodCall, 0, 30) . "\n";
2412
-                } else {
2413
-                    echo 'VAR FOUND : $' . $key . "\n";
2414
-                }
2415
-            }
2416
-
2417
-            $key = str_replace('"', '\\"', $key);
2418
-
2419
-            $cnt = substr_count($key, '$');
2420
-            if ($cnt > 0) {
2421
-                $uid           = 0;
2422
-                $parsed        = array($uid => '');
2423
-                $current       = &$parsed;
2424
-                $curTxt        = &$parsed[$uid ++];
2425
-                $tree          = array();
2426
-                $chars         = str_split($key, 1);
2427
-                $inSplittedVar = false;
2428
-                $bracketCount  = 0;
2429
-
2430
-                while (($char = array_shift($chars)) !== null) {
2431
-                    if ($char === '[') {
2432
-                        if (count($tree) > 0) {
2433
-                            ++ $bracketCount;
2434
-                        } else {
2435
-                            $tree[]        = &$current;
2436
-                            $current[$uid] = array($uid + 1 => '');
2437
-                            $current       = &$current[$uid ++];
2438
-                            $curTxt        = &$current[$uid ++];
2439
-                            continue;
2440
-                        }
2441
-                    } elseif ($char === ']') {
2442
-                        if ($bracketCount > 0) {
2443
-                            -- $bracketCount;
2444
-                        } else {
2445
-                            $current = &$tree[count($tree) - 1];
2446
-                            array_pop($tree);
2447
-                            if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') {
2448
-                                $current[$uid] = '';
2449
-                                $curTxt        = &$current[$uid ++];
2450
-                            }
2451
-                            continue;
2452
-                        }
2453
-                    } elseif ($char === '$') {
2454
-                        if (count($tree) == 0) {
2455
-                            $curTxt        = &$current[$uid ++];
2456
-                            $inSplittedVar = true;
2457
-                        }
2458
-                    } elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) {
2459
-                        $curTxt        = &$current[$uid ++];
2460
-                        $inSplittedVar = false;
2461
-                    }
2462
-
2463
-                    $curTxt .= $char;
2464
-                }
2465
-                unset($uid, $current, $curTxt, $tree, $chars);
2466
-
2467
-                if ($this->debug) {
2468
-                    echo 'RECURSIVE VAR REPLACEMENT : ' . $key . "\n";
2469
-                }
2470
-
2471
-                $key = $this->flattenVarTree($parsed);
2472
-
2473
-                if ($this->debug) {
2474
-                    echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2475
-                }
2476
-
2477
-                $output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("' . $key . '")');
2478
-            } else {
2479
-                $output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock);
2480
-            }
2481
-
2482
-
2483
-            // methods
2484
-            if ($hasMethodCall) {
2485
-                $ptr = 0;
2486
-
2487
-                $output = $this->parseMethodCall($output, $methodCall, $curBlock, $ptr);
2488
-
2489
-                if ($pointer !== null) {
2490
-                    $pointer += $ptr;
2491
-                }
2492
-                $matchedLength += $ptr;
2493
-            }
2494
-
2495
-            if ($hasExpression) {
2496
-                // expressions
2497
-                preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i', $match[4], $expMatch);
2498
-                foreach ($expMatch[1] as $k => $operator) {
2499
-                    if (substr($expMatch[2][$k], 0, 1) === '=') {
2500
-                        $assign = true;
2501
-                        if ($operator === '=') {
2502
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, can not use "==" in expressions');
2503
-                        }
2504
-                        if ($curBlock !== 'root') {
2505
-                            throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2506
-                        }
2507
-                        $operator .= '=';
2508
-                        $expMatch[2][$k] = substr($expMatch[2][$k], 1);
2509
-                    }
2510
-
2511
-                    if (substr($expMatch[2][$k], 0, 1) === '-' && strlen($expMatch[2][$k]) > 1) {
2512
-                        $operator .= '-';
2513
-                        $expMatch[2][$k] = substr($expMatch[2][$k], 1);
2514
-                    }
2515
-                    if (($operator === '+' || $operator === '-') && $expMatch[2][$k] === $operator) {
2516
-                        $output = '(' . $output . $operator . $operator . ')';
2517
-                        break;
2518
-                    } elseif (substr($expMatch[2][$k], 0, 1) === '$') {
2519
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2520
-                    } elseif (substr($expMatch[2][$k], 0, 1) === '%') {
2521
-                        $output = '(' . $output . ' ' . $operator . ' ' . $this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2522
-                    } elseif (!empty($expMatch[2][$k])) {
2523
-                        $output = '(' . $output . ' ' . $operator . ' ' . str_replace(',', '.', $expMatch[2][$k]) . ')';
2524
-                    } else {
2525
-                        throw new CompilationException($this, 'Unfinished expression <em>' . $substr . '</em>, missing var or number after math operator');
2526
-                    }
2527
-                }
2528
-            }
2529
-
2530
-            if ($this->autoEscape === true && $curBlock !== 'condition') {
2531
-                $output = '(is_string($tmp=' . $output . ') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2532
-            }
2533
-
2534
-            // handle modifiers
2535
-            if ($curBlock !== 'modifier' && $hasModifiers) {
2536
-                $ptr    = 0;
2537
-                $output = $this->replaceModifiers(array(null, null, $output, $match[5]), 'var', $ptr);
2538
-                if ($pointer !== null) {
2539
-                    $pointer += $ptr;
2540
-                }
2541
-                $matchedLength += $ptr;
2542
-            }
2543
-
2544
-            if (is_array($parsingParams)) {
2545
-                $parsingParams[] = array($output, $key);
2546
-
2547
-                return $parsingParams;
2548
-            } elseif ($curBlock === 'namedparam') {
2549
-                return array($output, $key);
2550
-            } elseif ($curBlock === 'string' || $curBlock === 'delimited_string') {
2551
-                return array($matchedLength, $output);
2552
-            } elseif ($curBlock === 'expression' || $curBlock === 'variable') {
2553
-                return $output;
2554
-            } elseif (isset($assign)) {
2555
-                return self::PHP_OPEN . $output . ';' . self::PHP_CLOSE;
2556
-            }
2557
-
2558
-            return $output;
2559
-        } else {
2560
-            if ($curBlock === 'string' || $curBlock === 'delimited_string') {
2561
-                return array(0, '');
2562
-            }
2563
-            throw new CompilationException($this, 'Invalid variable name <em>' . $substr . '</em>');
2564
-        }
2565
-    }
2566
-
2567
-    /**
2568
-     * Parses any number of chained method calls/property reads.
2569
-     *
2570
-     * @param string $output     the variable or whatever upon which the method are called
2571
-     * @param string $methodCall method call source, starting at "->"
2572
-     * @param string $curBlock   the current parser-block being processed
2573
-     * @param int    $pointer    a reference to a pointer that will be increased by the amount of characters parsed
2574
-     *
2575
-     * @return string parsed call(s)/read(s)
2576
-     */
2577
-    protected function parseMethodCall($output, $methodCall, $curBlock, &$pointer)
2578
-    {
2579
-        $ptr = 0;
2580
-        $len = strlen($methodCall);
2581
-
2582
-        while ($ptr < $len) {
2583
-            if (strpos($methodCall, '->', $ptr) === $ptr) {
2584
-                $ptr += 2;
2585
-            }
2586
-
2587
-            if (in_array(
2588
-                $methodCall[$ptr], array(
2589
-                    ';',
2590
-                    ',',
2591
-                    '/',
2592
-                    ' ',
2593
-                    "\t",
2594
-                    "\r",
2595
-                    "\n",
2596
-                    ')',
2597
-                    '+',
2598
-                    '*',
2599
-                    '%',
2600
-                    '=',
2601
-                    '-',
2602
-                    '|'
2603
-                )
2604
-            ) || substr($methodCall, $ptr, strlen($this->rd)) === $this->rd
2605
-            ) {
2606
-                // break char found
2607
-                break;
2608
-            }
2609
-
2610
-            if (!preg_match('/^([a-z0-9_]+)(\(.*?\))?/i', substr($methodCall, $ptr), $methMatch)) {
2611
-                break;
2612
-            }
2613
-
2614
-            if (empty($methMatch[2])) {
2615
-                // property
2616
-                if ($curBlock === 'root') {
2617
-                    $output .= '->' . $methMatch[1];
2618
-                } else {
2619
-                    $output = '(($tmp = ' . $output . ') ? $tmp->' . $methMatch[1] . ' : null)';
2620
-                }
2621
-                $ptr += strlen($methMatch[1]);
2622
-            } else {
2623
-                // method
2624
-                if (substr($methMatch[2], 0, 2) === '()') {
2625
-                    $parsedCall = $methMatch[1] . '()';
2626
-                    $ptr += strlen($methMatch[1]) + 2;
2627
-                } else {
2628
-                    $parsedCall = $this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr);
2629
-                }
2630
-                if ($this->securityPolicy !== null) {
2631
-                    $argPos = strpos($parsedCall, '(');
2632
-                    $method = strtolower(substr($parsedCall, 0, $argPos));
2633
-                    $args   = substr($parsedCall, $argPos);
2634
-                    if ($curBlock === 'root') {
2635
-                        $output = '$this->getSecurityPolicy()->callMethod($this, ' . $output . ', ' . var_export($method, true) . ', array' . $args . ')';
2636
-                    } else {
2637
-                        $output = '(($tmp = ' . $output . ') ? $this->getSecurityPolicy()->callMethod($this, $tmp, ' . var_export($method, true) . ', array' . $args . ') : null)';
2638
-                    }
2639
-                } else {
2640
-                    if ($curBlock === 'root') {
2641
-                        $output .= '->' . $parsedCall;
2642
-                    } else {
2643
-                        $output = '(($tmp = ' . $output . ') ? $tmp->' . $parsedCall . ' : null)';
2644
-                    }
2645
-                }
2646
-            }
2647
-        }
2648
-
2649
-        $pointer += $ptr;
2650
-
2651
-        return $output;
2652
-    }
2653
-
2654
-    /**
2655
-     * Parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save
2656
-     * runtime processing time.
2657
-     *
2658
-     * @param string $key      the variable to parse
2659
-     * @param string $curBlock the current parser-block being processed
2660
-     *
2661
-     * @return string parsed variable
2662
-     */
2663
-    protected function parseVarKey($key, $curBlock)
2664
-    {
2665
-        if ($key === '') {
2666
-            return '$this->scope';
2667
-        }
2668
-        if (substr($key, 0, 1) === '.') {
2669
-            $key = 'dwoo' . $key;
2670
-        }
2671
-        if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) {
2672
-            $global = strtoupper($m[1]);
2673
-            if ($global === 'COOKIES') {
2674
-                $global = 'COOKIE';
2675
-            }
2676
-            $key = '$_' . $global;
2677
-            foreach (explode('.', ltrim($m[2], '.')) as $part) {
2678
-                $key .= '[' . var_export($part, true) . ']';
2679
-            }
2680
-            if ($curBlock === 'root') {
2681
-                $output = $key;
2682
-            } else {
2683
-                $output = '(isset(' . $key . ')?' . $key . ':null)';
2684
-            }
2685
-        } elseif (preg_match('#dwoo\\.const\\.([a-z0-9\\\\_:]+)#i', $key, $m)) {
2686
-            return $this->parseConstKey($m[1], $curBlock);
2687
-        } elseif ($this->scope !== null) {
2688
-            if (strstr($key, '.') === false && strstr($key, '[') === false && strstr($key, '->') === false) {
2689
-                if ($key === 'dwoo') {
2690
-                    $output = '$this->globals';
2691
-                } elseif ($key === '_root' || $key === '__') {
2692
-                    $output = '$this->data';
2693
-                } elseif ($key === '_parent' || $key === '_') {
2694
-                    $output = '$this->readParentVar(1)';
2695
-                } elseif ($key === '_key') {
2696
-                    $output = '$tmp_key';
2697
-                } else {
2698
-                    if ($curBlock === 'root') {
2699
-                        $output = '$this->scope["' . $key . '"]';
2700
-                    } else {
2701
-                        $output = '(isset($this->scope["' . $key . '"]) ? $this->scope["' . $key . '"] : null)';
2702
-                    }
2703
-                }
2704
-            } else {
2705
-                preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+|(\\\?[\'"])[^\3]*?\3)\]?#i', $key, $m);
2706
-
2707
-                $i = $m[2][0];
2708
-                if ($i === '_parent' || $i === '_') {
2709
-                    $parentCnt = 0;
2710
-
2711
-                    while (true) {
2712
-                        ++ $parentCnt;
2713
-                        array_shift($m[2]);
2714
-                        array_shift($m[1]);
2715
-                        if (current($m[2]) === '_parent') {
2716
-                            continue;
2717
-                        }
2718
-                        break;
2719
-                    }
2720
-
2721
-                    $output = '$this->readParentVar(' . $parentCnt . ')';
2722
-                } else {
2723
-                    if ($i === 'dwoo') {
2724
-                        $output = '$this->globals';
2725
-                        array_shift($m[2]);
2726
-                        array_shift($m[1]);
2727
-                    } elseif ($i === '_root' || $i === '__') {
2728
-                        // $output = '$this->data';
2729
-                        $output = '$this->getData()';
2730
-                        array_shift($m[2]);
2731
-                        array_shift($m[1]);
2732
-                    } elseif ($i === '_key') {
2733
-                        $output = '$tmp_key';
2734
-                    } else {
2735
-                        $output = '$this->scope';
2736
-                    }
2737
-
2738
-                    while (count($m[1]) && $m[1][0] !== '->') {
2739
-                        $m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]);
2740
-                        if (substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") {
2741
-                            $output .= '[' . $m[2][0] . ']';
2742
-                        } else {
2743
-                            $output .= '["' . $m[2][0] . '"]';
2744
-                        }
2745
-                        array_shift($m[2]);
2746
-                        array_shift($m[1]);
2747
-                    }
2748
-
2749
-                    if ($curBlock !== 'root') {
2750
-                        $output = '(isset(' . $output . ') ? ' . $output . ':null)';
2751
-                    }
2752
-                }
2753
-
2754
-                if (count($m[2])) {
2755
-                    unset($m[0]);
2756
-                    $output = '$this->readVarInto(' . str_replace("\n", '', var_export($m, true)) . ', ' . $output . ', ' . ($curBlock == 'root' ? 'false' : 'true') . ')';
2757
-                }
2758
-            }
2759
-        } else {
2760
-            preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m);
2761
-            unset($m[0]);
2762
-            $output = '$this->readVar(' . str_replace("\n", '', var_export($m, true)) . ')';
2763
-        }
2764
-
2765
-        return $output;
2766
-    }
2767
-
2768
-    /**
2769
-     * Flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz,
2770
-     * it computes the contents of the brackets first and works out from there.
2771
-     *
2772
-     * @param array $tree     the variable tree parsed by he parseVar() method that must be flattened
2773
-     * @param bool  $recursed leave that to false by default, it is only for internal use
2774
-     *
2775
-     * @return string flattened tree
2776
-     */
2777
-    protected function flattenVarTree(array $tree, $recursed = false)
2778
-    {
2779
-        $out = $recursed ? '".$this->readVarInto(' : '';
2780
-        foreach ($tree as $bit) {
2781
-            if (is_array($bit)) {
2782
-                $out .= '.' . $this->flattenVarTree($bit, false);
2783
-            } else {
2784
-                $key = str_replace('"', '\\"', $bit);
2785
-
2786
-                if (substr($key, 0, 1) === '$') {
2787
-                    $out .= '".' . $this->parseVar($key, 0, strlen($key), false, 'variable') . '."';
2788
-                } else {
2789
-                    $cnt = substr_count($key, '$');
2790
-
2791
-                    if ($this->debug) {
2792
-                        echo 'PARSING SUBVARS IN : ' . $key . "\n";
2793
-                    }
2794
-                    if ($cnt > 0) {
2795
-                        while (-- $cnt >= 0) {
2796
-                            if (isset($last)) {
2797
-                                $last = strrpos($key, '$', - (strlen($key) - $last + 1));
2798
-                            } else {
2799
-                                $last = strrpos($key, '$');
2800
-                            }
2801
-                            preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2802
-
2803
-                            $len = strlen($submatch[0]);
2804
-                            $key = substr_replace(
2805
-                                $key, preg_replace_callback(
2806
-                                    '#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2807
-                                        $this,
2808
-                                        'replaceVarKeyHelper'
2809
-                                    ), substr($key, $last, $len)
2810
-                                ), $last, $len
2811
-                            );
2812
-                            if ($this->debug) {
2813
-                                echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2814
-                            }
2815
-                        }
2816
-                        unset($last);
2817
-
2818
-                        $out .= $key;
2819
-                    } else {
2820
-                        $out .= $key;
2821
-                    }
2822
-                }
2823
-            }
2824
-        }
2825
-        $out .= $recursed ? ', true)."' : '';
2826
-
2827
-        return $out;
2828
-    }
2829
-
2830
-    /**
2831
-     * Helper function that parses a variable.
2832
-     *
2833
-     * @param array $match the matched variable, array(1=>"string match")
2834
-     *
2835
-     * @return string parsed variable
2836
-     */
2837
-    protected function replaceVarKeyHelper($match)
2838
-    {
2839
-        return '".' . $this->parseVar($match[0], 0, strlen($match[0]), false, 'variable') . '."';
2840
-    }
2841
-
2842
-    /**
2843
-     * Parses various constants, operators or non-quoted strings.
2844
-     *
2845
-     * @param string $in            the string within which we must parse something
2846
-     * @param int    $from          the starting offset of the parsed area
2847
-     * @param int    $to            the ending offset of the parsed area
2848
-     * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2849
-     *                              default
2850
-     * @param string $curBlock      the current parser-block being processed
2851
-     * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2852
-     *                              or null by default
2853
-     *
2854
-     * @return string parsed values
2855
-     * @throws Exception
2856
-     */
2857
-    protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2858
-    {
2859
-        $substr = substr($in, $from, $to - $from);
2860
-
2861
-        $end = strlen($substr);
2862
-
2863
-        if ($curBlock === 'condition') {
2864
-            $breakChars = array(
2865
-                '(',
2866
-                ')',
2867
-                ' ',
2868
-                '||',
2869
-                '&&',
2870
-                '|',
2871
-                '&',
2872
-                '>=',
2873
-                '<=',
2874
-                '===',
2875
-                '==',
2876
-                '=',
2877
-                '!==',
2878
-                '!=',
2879
-                '<<',
2880
-                '<',
2881
-                '>>',
2882
-                '>',
2883
-                '^',
2884
-                '~',
2885
-                ',',
2886
-                '+',
2887
-                '-',
2888
-                '*',
2889
-                '/',
2890
-                '%',
2891
-                '!',
2892
-                '?',
2893
-                ':',
2894
-                $this->rd,
2895
-                ';'
2896
-            );
2897
-        } elseif ($curBlock === 'modifier') {
2898
-            $breakChars = array(' ', ',', ')', ':', '|', "\r", "\n", "\t", ';', $this->rd);
2899
-        } elseif ($curBlock === 'expression') {
2900
-            $breakChars = array('/', '%', '+', '-', '*', ' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2901
-        } else {
2902
-            $breakChars = array(' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2903
-        }
2904
-
2905
-        $breaker = false;
2906
-        foreach ($breakChars as $k => $char) {
2907
-            $test = strpos($substr, $char);
2908
-            if ($test !== false && $test < $end) {
2909
-                $end     = $test;
2910
-                $breaker = $k;
2911
-            }
2912
-        }
2913
-
2914
-        if ($curBlock === 'condition') {
2915
-            if ($end === 0 && $breaker !== false) {
2916
-                $end = strlen($breakChars[$breaker]);
2917
-            }
2918
-        }
2919
-
2920
-        if ($end !== false) {
2921
-            $substr = substr($substr, 0, $end);
2922
-        }
2923
-
2924
-        if ($pointer !== null) {
2925
-            $pointer += strlen($substr);
2926
-        }
2927
-
2928
-        $src    = $substr;
2929
-        $substr = trim($substr);
2930
-
2931
-        if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') {
2932
-            if ($this->debug) {
2933
-                echo 'BOOLEAN(FALSE) PARSED' . "\n";
2934
-            }
2935
-            $substr = 'false';
2936
-            $type   = self::T_BOOL;
2937
-        } elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') {
2938
-            if ($this->debug) {
2939
-                echo 'BOOLEAN(TRUE) PARSED' . "\n";
2940
-            }
2941
-            $substr = 'true';
2942
-            $type   = self::T_BOOL;
2943
-        } elseif ($substr === 'null' || $substr === 'NULL') {
2944
-            if ($this->debug) {
2945
-                echo 'NULL PARSED' . "\n";
2946
-            }
2947
-            $substr = 'null';
2948
-            $type   = self::T_NULL;
2949
-        } elseif (is_numeric($substr)) {
2950
-            $substr = (float)$substr;
2951
-            if ((int)$substr == $substr) {
2952
-                $substr = (int)$substr;
2953
-            }
2954
-            $type = self::T_NUMERIC;
2955
-            if ($this->debug) {
2956
-                echo 'NUMBER (' . $substr . ') PARSED' . "\n";
2957
-            }
2958
-        } elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) {
2959
-            if ($this->debug) {
2960
-                echo 'SIMPLE MATH PARSED . "\n"';
2961
-            }
2962
-            $type   = self::T_MATH;
2963
-            $substr = '(' . $substr . ')';
2964
-        } elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) {
2965
-            if ($this->debug) {
2966
-                echo 'BREAKCHAR (' . $substr . ') PARSED' . "\n";
2967
-            }
2968
-            $type = self::T_BREAKCHAR;
2969
-            //$substr = '"'.$substr.'"';
2970
-        } else {
2971
-            $substr = $this->replaceStringVars('\'' . str_replace('\'', '\\\'', $substr) . '\'', '\'', $curBlock);
2972
-            $type   = self::T_UNQUOTED_STRING;
2973
-            if ($this->debug) {
2974
-                echo 'BLABBER (' . $substr . ') CASTED AS STRING' . "\n";
2975
-            }
2976
-        }
2977
-
2978
-        if (is_array($parsingParams)) {
2979
-            $parsingParams[] = array($substr, $src, $type);
2980
-
2981
-            return $parsingParams;
2982
-        } elseif ($curBlock === 'namedparam') {
2983
-            return array($substr, $src, $type);
2984
-        } elseif ($curBlock === 'expression') {
2985
-            return $substr;
2986
-        } else {
2987
-            throw new Exception('Something went wrong');
2988
-        }
2989
-    }
2990
-
2991
-    /**
2992
-     * Replaces variables within a parsed string.
2993
-     *
2994
-     * @param string $string   the parsed string
2995
-     * @param string $first    the first character parsed in the string, which is the string delimiter (' or ")
2996
-     * @param string $curBlock the current parser-block being processed
2997
-     *
2998
-     * @return string the original string with variables replaced
2999
-     */
3000
-    protected function replaceStringVars($string, $first, $curBlock = '')
3001
-    {
3002
-        $pos = 0;
3003
-        if ($this->debug) {
3004
-            echo 'STRING VAR REPLACEMENT : ' . $string . "\n";
3005
-        }
3006
-        // replace vars
3007
-        while (($pos = strpos($string, '$', $pos)) !== false) {
3008
-            $prev = substr($string, $pos - 1, 1);
3009
-            if ($prev === '\\') {
3010
-                ++ $pos;
3011
-                continue;
3012
-            }
3013
-
3014
-            $var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3015
-            $len = $var[0];
3016
-            $var = $this->parse(str_replace('\\' . $first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3017
-
3018
-            if ($prev === '`' && substr($string, $pos + $len, 1) === '`') {
3019
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos - 1, $len + 2);
3020
-            } else {
3021
-                $string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos, $len);
3022
-            }
3023
-            $pos += strlen($var[1]) + 2;
3024
-            if ($this->debug) {
3025
-                echo 'STRING VAR REPLACEMENT DONE : ' . $string . "\n";
3026
-            }
3027
-        }
3028
-
3029
-        // handle modifiers
3030
-        // TODO Obsolete?
3031
-        $string = preg_replace_callback(
3032
-            '#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i', array(
3033
-            $this,
3034
-            'replaceModifiers'
3035
-            ), $string
3036
-        );
3037
-
3038
-        // replace escaped dollar operators by unescaped ones if required
3039
-        if ($first === "'") {
3040
-            $string = str_replace('\\$', '$', $string);
3041
-        }
3042
-
3043
-        return $string;
3044
-    }
3045
-
3046
-    /**
3047
-     * Replaces the modifiers applied to a string or a variable.
3048
-     *
3049
-     * @param array  $m        the regex matches that must be array(1=>"double or single quotes enclosing a string,
3050
-     *                         when applicable", 2=>"the string or var", 3=>"the modifiers matched")
3051
-     * @param string $curBlock the current parser-block being processed
3052
-     * @param null   $pointer
3053
-     *
3054
-     * @return string the input enclosed with various function calls according to the modifiers found
3055
-     * @throws CompilationException
3056
-     * @throws Exception
3057
-     */
3058
-    protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null)
3059
-    {
3060
-        if ($this->debug) {
3061
-            echo 'PARSING MODIFIERS : ' . $m[3] . "\n";
3062
-        }
3063
-
3064
-        if ($pointer !== null) {
3065
-            $pointer += strlen($m[3]);
3066
-        }
3067
-        // remove first pipe
3068
-        $cmdstrsrc = substr($m[3], 1);
3069
-        // remove last quote if present
3070
-        if (substr($cmdstrsrc, - 1, 1) === $m[1]) {
3071
-            $cmdstrsrc = substr($cmdstrsrc, 0, - 1);
3072
-            $add       = $m[1];
3073
-        }
3074
-
3075
-        $output = $m[2];
3076
-
3077
-        $continue = true;
3078
-        while (strlen($cmdstrsrc) > 0 && $continue) {
3079
-            if ($cmdstrsrc[0] === '|') {
3080
-                $cmdstrsrc = substr($cmdstrsrc, 1);
3081
-                continue;
3082
-            }
3083
-            if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) {
3084
-                if ($this->debug) {
3085
-                    echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND' . "\n";
3086
-                }
3087
-                $continue = false;
3088
-                if ($pointer !== null) {
3089
-                    $pointer -= strlen($cmdstrsrc);
3090
-                }
3091
-                break;
3092
-            }
3093
-            $cmdstr   = $cmdstrsrc;
3094
-            $paramsep = ':';
3095
-            if (!preg_match('/^(@{0,2}[a-z_][a-z0-9_]*)(:)?/i', $cmdstr, $match)) {
3096
-                throw new CompilationException($this, 'Invalid modifier name, started with : ' . substr($cmdstr, 0, 10));
3097
-            }
3098
-            $paramspos = !empty($match[2]) ? strlen($match[1]) : false;
3099
-            $func      = $match[1];
3100
-
3101
-            $state = 0;
3102
-            if ($paramspos === false) {
3103
-                $cmdstrsrc = substr($cmdstrsrc, strlen($func));
3104
-                $params    = array();
3105
-                if ($this->debug) {
3106
-                    echo 'MODIFIER (' . $func . ') CALLED WITH NO PARAMS' . "\n";
3107
-                }
3108
-            } else {
3109
-                $paramstr = substr($cmdstr, $paramspos + 1);
3110
-                if (substr($paramstr, - 1, 1) === $paramsep) {
3111
-                    $paramstr = substr($paramstr, 0, - 1);
3112
-                }
3113
-
3114
-                $ptr    = 0;
3115
-                $params = array();
3116
-                while ($ptr < strlen($paramstr)) {
3117
-                    if ($this->debug) {
3118
-                        echo 'MODIFIER (' . $func . ') START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
3119
-                    }
3120
-                    if ($this->debug) {
3121
-                        echo $paramstr . '--' . $ptr . '--' . strlen($paramstr) . '--modifier' . "\n";
3122
-                    }
3123
-                    $params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr);
3124
-                    if ($this->debug) {
3125
-                        echo 'PARAM PARSED, POINTER AT ' . $ptr . "\n";
3126
-                    }
3127
-
3128
-                    if ($ptr >= strlen($paramstr)) {
3129
-                        if ($this->debug) {
3130
-                            echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED' . "\n";
3131
-                        }
3132
-                        break;
3133
-                    }
3134
-
3135
-                    if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
3136
-                        if ($this->debug) {
3137
-                            echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT ' . $ptr . "\n";
3138
-                        }
3139
-                        if ($paramstr[$ptr] !== '|') {
3140
-                            $continue = false;
3141
-                            if ($pointer !== null) {
3142
-                                $pointer -= strlen($paramstr) - $ptr;
3143
-                            }
3144
-                        }
3145
-                        ++ $ptr;
3146
-                        break;
3147
-                    }
3148
-                    if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') {
3149
-                        ++ $ptr;
3150
-                    }
3151
-                }
3152
-                $cmdstrsrc = substr($cmdstrsrc, strlen($func) + 1 + $ptr);
3153
-                foreach ($params as $k => $p) {
3154
-                    if (is_array($p) && is_array($p[1])) {
3155
-                        $state |= 2;
3156
-                    } else {
3157
-                        if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) {
3158
-                            $params[$k] = array($m[2], array('true', 'true'));
3159
-                        } else {
3160
-                            if ($state & 2) {
3161
-                                throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
3162
-                            }
3163
-                            $state |= 1;
3164
-                        }
3165
-                    }
3166
-                }
3167
-            }
3168
-
3169
-            // check if we must use array_map with this plugin or not
3170
-            $mapped = false;
3171
-            if (substr($func, 0, 1) === '@') {
3172
-                $func   = substr($func, 1);
3173
-                $mapped = true;
3174
-            }
3175
-
3176
-            $pluginType = $this->getPluginType($func);
3177
-
3178
-            if ($state & 2) {
3179
-                array_unshift($params, array('value', is_array($output) ? $output : array($output, $output)));
3180
-            } else {
3181
-                array_unshift($params, is_array($output) ? $output : array($output, $output));
3182
-            }
3183
-
3184
-            if ($pluginType & Core::NATIVE_PLUGIN) {
3185
-                $params = $this->mapParams($params, null, $state);
3186
-
3187
-                $params = $params['*'][0];
3188
-
3189
-                $params = self::implode_r($params);
3190
-
3191
-                if ($mapped) {
3192
-                    $output = '$this->arrayMap(\'' . $func . '\', array(' . $params . '))';
3193
-                } else {
3194
-                    $output = $func . '(' . $params . ')';
3195
-                }
3196
-            } elseif ($pluginType & Core::PROXY_PLUGIN) {
3197
-                $params = $this->mapParams($params, $this->getCore()->getPluginProxy()->getCallback($func), $state);
3198
-                foreach ($params as &$p) {
3199
-                    $p = $p[0];
3200
-                }
3201
-                $output = call_user_func(array($this->getCore()->getPluginProxy(), 'getCode'), $func, $params);
3202
-            } elseif ($pluginType & Core::SMARTY_MODIFIER) {
3203
-                $params = $this->mapParams($params, null, $state);
3204
-                $params = $params['*'][0];
3205
-
3206
-                $params = self::implode_r($params);
3207
-
3208
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
3209
-                    $callback = $this->customPlugins[$func]['callback'];
3210
-                    if (is_array($callback)) {
3211
-                        if (is_object($callback[0])) {
3212
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(' . $params . '))';
3213
-                        } else {
3214
-                            $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3215
-                        }
3216
-                    } elseif ($mapped) {
3217
-                        $output = '$this->arrayMap(\'' . $callback . '\', array(' . $params . '))';
3218
-                    } else {
3219
-                        $output = $callback . '(' . $params . ')';
3220
-                    }
3221
-                } elseif ($mapped) {
3222
-                    $output = '$this->arrayMap(\'smarty_modifier_' . $func . '\', array(' . $params . '))';
3223
-                } else {
3224
-                    $output = 'smarty_modifier_' . $func . '(' . $params . ')';
3225
-                }
3226
-            } else {
3227
-                if ($pluginType & Core::CUSTOM_PLUGIN) {
3228
-                    $pluginName = $callback = $this->customPlugins[$func]['callback'];
3229
-                    if (($pluginType & Core::CLASS_PLUGIN) && !is_array($callback)) {
3230
-                        $pluginName = $this->customPlugins[$func]['callback'];
3231
-                        $callback   = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3232
-                    }
3233
-                } else {
3234
-                    if (class_exists('Plugin' . Core::toCamelCase($func)) !== false || function_exists('Plugin' .
3235
-                            Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3236
-                        !== false) {
3237
-                        $pluginName = 'Plugin' . Core::toCamelCase($func);
3238
-                    } else {
3239
-                        $pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func);
3240
-                    }
3241
-                    if ($pluginType & Core::CLASS_PLUGIN) {
3242
-                        $callback = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3243
-                    } else {
3244
-                        $callback = $pluginName . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3245
-                    }
3246
-                }
3247
-                $params = $this->mapParams($params, $callback, $state);
3248
-
3249
-                foreach ($params as &$p) {
3250
-                    $p = $p[0];
3251
-                }
3252
-
3253
-                // Only for PHP function, who is not a PHP class
3254
-                if ($pluginType & Core::FUNC_PLUGIN && !($pluginType & Core::CLASS_PLUGIN)) {
3255
-                    if ($pluginType & Core::COMPILABLE_PLUGIN) {
3256
-                        if ($mapped) {
3257
-                            throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3258
-                        }
3259
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3260
-                            $funcCompiler = $this->customPlugins[$func]['callback'];
3261
-                        } else {
3262
-                            if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
3263
-                                $funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
3264
-                            } else {
3265
-                                $funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
3266
-                                    'Compile';
3267
-                            }
3268
-                        }
3269
-                        array_unshift($params, $this);
3270
-                        $output = call_user_func_array($funcCompiler, $params);
3271
-                    } else {
3272
-                        array_unshift($params, '$this');
3273
-
3274
-                        $params = self::implode_r($params);
3275
-                        if ($mapped) {
3276
-                            $output = '$this->arrayMap(\'' . $pluginName . '\', array(' . $params . '))';
3277
-                        } else {
3278
-                            $output = $pluginName . '(' . $params . ')';
3279
-                        }
3280
-                    }
3281
-                } else {
3282
-                    if ($pluginType & Core::COMPILABLE_PLUGIN) {
3283
-                        if ($mapped) {
3284
-                            throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3285
-                        }
3286
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3287
-                            $callback = $this->customPlugins[$func]['callback'];
3288
-                            if (!is_array($callback)) {
3289
-                                if (!method_exists($callback, 'compile')) {
3290
-                                    throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3291
-                                }
3292
-                                if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
3293
-                                    $funcCompiler = array($callback, 'compile');
3294
-                                } else {
3295
-                                    $funcCompiler = array(new $callback(), 'compile');
3296
-                                }
3297
-                            } else {
3298
-                                $funcCompiler = $callback;
3299
-                            }
3300
-                        } else {
3301
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3302
-                                $funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
3303
-                            } else {
3304
-                                $funcCompiler = array(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func), 'compile');
3305
-                            }
3306
-                            array_unshift($params, $this);
3307
-                        }
3308
-                        $output = call_user_func_array($funcCompiler, $params);
3309
-                    } else {
3310
-                        $params = self::implode_r($params);
3311
-
3312
-                        if ($pluginType & Core::CUSTOM_PLUGIN) {
3313
-                            if (is_object($callback[0])) {
3314
-                                if (is_array($this->getCore()->getCustomPlugin($func))) {
3315
-                                    $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3316
-                                } else {
3317
-                                    $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(' . $params . '))';
3318
-                                }
3319
-                            } else {
3320
-                                $output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3321
-                            }
3322
-                        } elseif ($mapped) {
3323
-                            $output = '$this->arrayMap(array($this->getObjectPlugin(\''.
3324
-                                Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '\'),
2100
+					} else {
2101
+						$output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
2102
+					}
2103
+				}
2104
+			}
2105
+		} // Function plugin only (cannot be a class)
2106
+		elseif ($pluginType & Core::FUNC_PLUGIN) {
2107
+			if ($pluginType & Core::COMPILABLE_PLUGIN) {
2108
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2109
+					$funcCompiler = $this->customPlugins[$func]['callback'];
2110
+				} else {
2111
+					// Custom plugin
2112
+					if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2113
+						$funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
2114
+					} // Builtin helper plugin
2115
+					elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
2116
+						$funcCompiler = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) .
2117
+							'Compile';
2118
+					} // Builtin function plugin
2119
+					else {
2120
+						$funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
2121
+							'Compile';
2122
+					}
2123
+				}
2124
+				array_unshift($params, $this);
2125
+				// @TODO: Is it a real fix ?
2126
+				if ($func === 'tif') {
2127
+					$params[] = $tokens;
2128
+				}
2129
+				$output = call_user_func_array($funcCompiler, $params);
2130
+			} else {
2131
+				array_unshift($params, '$this');
2132
+				$params = self::implode_r($params);
2133
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
2134
+					$callback = $this->customPlugins[$func]['callback'];
2135
+					if ($callback instanceof Closure) {
2136
+						$output = 'call_user_func($this->getCustomPlugin(\'' . $func . '\'), ' . $params . ')';
2137
+					} else {
2138
+						$output = 'call_user_func(\'' . $callback . '\', ' . $params . ')';
2139
+					}
2140
+				} else {
2141
+					// Custom plugin
2142
+					if (function_exists('Plugin' . Core::toCamelCase($func)) !== false) {
2143
+						$output = 'Plugin' . Core::toCamelCase($func) . '(' . $params .
2144
+							')';
2145
+					} // Builtin helper plugin
2146
+					elseif(function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func)) !==
2147
+						false) {
2148
+						$output = Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($func) . '(' .
2149
+							$params . ')';
2150
+					} // Builtin function plugin
2151
+					else {
2152
+						$output = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '(' .
2153
+							$params . ')';
2154
+					}
2155
+				}
2156
+			}
2157
+		} // Proxy plugin
2158
+		elseif ($pluginType & Core::PROXY_PLUGIN) {
2159
+			$output = call_user_func(array($this->getCore()->getPluginProxy(), 'getCode'), $func, $params);
2160
+		} // Smarty function (@deprecated)
2161
+		elseif ($pluginType & Core::SMARTY_FUNCTION) {
2162
+			$params = '';
2163
+			if (isset($params['*'])) {
2164
+				$params = self::implode_r($params['*'], true);
2165
+			}
2166
+
2167
+			if ($pluginType & Core::CUSTOM_PLUGIN) {
2168
+				$callback = $this->customPlugins[$func]['callback'];
2169
+				if (is_array($callback)) {
2170
+					if (is_object($callback[0])) {
2171
+						$output = 'call_user_func_array(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2172
+					} else {
2173
+						$output = 'call_user_func_array(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(array(' . $params . '), $this))';
2174
+					}
2175
+				} else {
2176
+					$output = $callback . '(array(' . $params . '), $this)';
2177
+				}
2178
+			} else {
2179
+				$output = 'smarty_function_' . $func . '(array(' . $params . '), $this)';
2180
+			}
2181
+		} // Template plugin
2182
+		elseif ($pluginType & Core::TEMPLATE_PLUGIN) {
2183
+			array_unshift($params, '$this');
2184
+			$params                                 = self::implode_r($params);
2185
+			$output                                 = 'Plugin' . Core::toCamelCase($func) .
2186
+				$this->templatePlugins[$func]['uuid'] . '(' . $params . ')';
2187
+			$this->templatePlugins[$func]['called'] = true;
2188
+		}
2189
+
2190
+		if (is_array($parsingParams)) {
2191
+			$parsingParams[] = array($output, $output);
2192
+
2193
+			return $parsingParams;
2194
+		} elseif ($curBlock === 'namedparam') {
2195
+			return array($output, $output);
2196
+		}
2197
+
2198
+		return $output;
2199
+	}
2200
+
2201
+	/**
2202
+	 * Parses a string.
2203
+	 *
2204
+	 * @param string $in            the string within which we must parse something
2205
+	 * @param int    $from          the starting offset of the parsed area
2206
+	 * @param int    $to            the ending offset of the parsed area
2207
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2208
+	 *                              default
2209
+	 * @param string $curBlock      the current parser-block being processed
2210
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2211
+	 *                              or null by default
2212
+	 *
2213
+	 * @return string parsed values
2214
+	 * @throws CompilationException
2215
+	 */
2216
+	protected function parseString($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2217
+	{
2218
+		$substr = substr($in, $from, $to - $from);
2219
+		$first  = $substr[0];
2220
+
2221
+		if ($this->debug) {
2222
+			echo 'STRING FOUND (in ' . htmlentities(substr($in, $from, min($to - $from, 50))) . (($to - $from) > 50 ? '...' : '') . ')' . "\n";
2223
+		}
2224
+		$strend = false;
2225
+		$o      = $from + 1;
2226
+		while ($strend === false) {
2227
+			$strend = strpos($in, $first, $o);
2228
+			if ($strend === false) {
2229
+				throw new CompilationException($this, 'Unfinished string, started with ' . substr($in, $from, $to - $from));
2230
+			}
2231
+			if (substr($in, $strend - 1, 1) === '\\') {
2232
+				$o      = $strend + 1;
2233
+				$strend = false;
2234
+			}
2235
+		}
2236
+		if ($this->debug) {
2237
+			echo 'STRING DELIMITED: ' . substr($in, $from, $strend + 1 - $from) . "\n";
2238
+		}
2239
+
2240
+		$srcOutput = substr($in, $from, $strend + 1 - $from);
2241
+
2242
+		if ($pointer !== null) {
2243
+			$pointer += strlen($srcOutput);
2244
+		}
2245
+
2246
+		$output = $this->replaceStringVars($srcOutput, $first);
2247
+
2248
+		// handle modifiers
2249
+		if ($curBlock !== 'modifier' && preg_match('#^((?:\|(?:@?[a-z0-9_]+(?::.*)*))+)#i', substr($substr, $strend + 1 - $from), $match)) {
2250
+			$modstr = $match[1];
2251
+
2252
+			if ($curBlock === 'root' && substr($modstr, - 1) === '}') {
2253
+				$modstr = substr($modstr, 0, - 1);
2254
+			}
2255
+			$modstr = str_replace('\\' . $first, $first, $modstr);
2256
+			$ptr    = 0;
2257
+			$output = $this->replaceModifiers(array(null, null, $output, $modstr), 'string', $ptr);
2258
+
2259
+			$strend += $ptr;
2260
+			if ($pointer !== null) {
2261
+				$pointer += $ptr;
2262
+			}
2263
+			$srcOutput .= substr($substr, $strend + 1 - $from, $ptr);
2264
+		}
2265
+
2266
+		if (is_array($parsingParams)) {
2267
+			$parsingParams[] = array($output, substr($srcOutput, 1, - 1));
2268
+
2269
+			return $parsingParams;
2270
+		} elseif ($curBlock === 'namedparam') {
2271
+			return array($output, substr($srcOutput, 1, - 1));
2272
+		}
2273
+
2274
+		return $output;
2275
+	}
2276
+
2277
+	/**
2278
+	 * Parses a constant.
2279
+	 *
2280
+	 * @param string $in            the string within which we must parse something
2281
+	 * @param int    $from          the starting offset of the parsed area
2282
+	 * @param int    $to            the ending offset of the parsed area
2283
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2284
+	 *                              default
2285
+	 * @param string $curBlock      the current parser-block being processed
2286
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2287
+	 *                              or null by default
2288
+	 *
2289
+	 * @return string parsed values
2290
+	 * @throws CompilationException
2291
+	 */
2292
+	protected function parseConst($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2293
+	{
2294
+		$substr = substr($in, $from, $to - $from);
2295
+
2296
+		if ($this->debug) {
2297
+			echo 'CONST FOUND : ' . $substr . "\n";
2298
+		}
2299
+
2300
+		if (!preg_match('#^%([\\\\a-z0-9_:]+)#i', $substr, $m)) {
2301
+			throw new CompilationException($this, 'Invalid constant');
2302
+		}
2303
+
2304
+		if ($pointer !== null) {
2305
+			$pointer += strlen($m[0]);
2306
+		}
2307
+
2308
+		$output = $this->parseConstKey($m[1], $curBlock);
2309
+
2310
+		if (is_array($parsingParams)) {
2311
+			$parsingParams[] = array($output, $m[1]);
2312
+
2313
+			return $parsingParams;
2314
+		} elseif ($curBlock === 'namedparam') {
2315
+			return array($output, $m[1]);
2316
+		}
2317
+
2318
+		return $output;
2319
+	}
2320
+
2321
+	/**
2322
+	 * Parses a constant.
2323
+	 *
2324
+	 * @param string $key      the constant to parse
2325
+	 * @param string $curBlock the current parser-block being processed
2326
+	 *
2327
+	 * @return string parsed constant
2328
+	 */
2329
+	protected function parseConstKey($key, $curBlock)
2330
+	{
2331
+		$key = str_replace('\\\\', '\\', $key);
2332
+
2333
+		if ($this->securityPolicy !== null && $this->securityPolicy->getConstantHandling() === SecurityPolicy::CONST_DISALLOW) {
2334
+			return 'null';
2335
+		}
2336
+
2337
+		if ($curBlock !== 'root') {
2338
+			return '(defined("' . $key . '") ? ' . $key . ' : null)';
2339
+		}
2340
+
2341
+		return $key;
2342
+	}
2343
+
2344
+	/**
2345
+	 * Parses a variable.
2346
+	 *
2347
+	 * @param string $in            the string within which we must parse something
2348
+	 * @param int    $from          the starting offset of the parsed area
2349
+	 * @param int    $to            the ending offset of the parsed area
2350
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2351
+	 *                              default
2352
+	 * @param string $curBlock      the current parser-block being processed
2353
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2354
+	 *                              or null by default
2355
+	 *
2356
+	 * @return string parsed values
2357
+	 * @throws CompilationException
2358
+	 */
2359
+	protected function parseVar($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2360
+	{
2361
+		$substr = substr($in, $from, $to - $from);
2362
+
2363
+		// var key
2364
+		$varRegex = '(\\$?\\.?[a-z0-9\\\\_:]*(?:(?:(?:\\.|->)(?:[a-z0-9\\\\_:]+|(?R))|\\[(?:[a-z0-9\\\\_:]+|(?R)|(["\'])[^\\2]*?\\2)\\]))*)';
2365
+		// method call
2366
+		$methodCall = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'expression' || $curBlock === 'delimited_string' ? '(\(.*)?' : '()');
2367
+		// simple math expressions
2368
+		$simpleMathExpressions = ($curBlock === 'root' || $curBlock === 'function' || $curBlock === 'namedparam' || $curBlock === 'condition' || $curBlock === 'variable' || $curBlock === 'delimited_string' ? '((?:(?:[+\/*%=-])(?:(?<!=)=?-?[$%][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|(?<!=)=?-?[0-9\.,]*|[+-]))*)' : '()');
2369
+		// modifiers
2370
+		$modifiers = $curBlock !== 'modifier' ? '((?:\|(?:@?[a-z0-9\\\\_]+(?:(?::("|\').*?\5|:[^`]*))*))+)?' : '(())';
2371
+
2372
+		$regex = '#';
2373
+		$regex .= $varRegex;
2374
+		$regex .= $methodCall;
2375
+		$regex .= $simpleMathExpressions;
2376
+		$regex .= $modifiers;
2377
+		$regex .= '#i';
2378
+
2379
+		if (preg_match($regex, $substr, $match)) {
2380
+			$key = substr($match[1], 1);
2381
+
2382
+			$matchedLength = strlen($match[0]);
2383
+			$hasModifiers  = !empty($match[5]);
2384
+			$hasExpression = !empty($match[4]);
2385
+			$hasMethodCall = !empty($match[3]);
2386
+
2387
+			if (substr($key, - 1) == '.') {
2388
+				$key = substr($key, 0, - 1);
2389
+				-- $matchedLength;
2390
+			}
2391
+
2392
+			if ($hasMethodCall) {
2393
+				$matchedLength -= strlen($match[3]) + strlen(substr($match[1], strrpos($match[1], '->')));
2394
+				$key        = substr($match[1], 1, strrpos($match[1], '->') - 1);
2395
+				$methodCall = substr($match[1], strrpos($match[1], '->')) . $match[3];
2396
+			}
2397
+
2398
+			if ($hasModifiers) {
2399
+				$matchedLength -= strlen($match[5]);
2400
+			}
2401
+
2402
+			if ($pointer !== null) {
2403
+				$pointer += $matchedLength;
2404
+			}
2405
+
2406
+			// replace useless brackets by dot accessed vars and strip enclosing quotes if present
2407
+			$key = preg_replace('#\[(["\']?)([^$%\[.>-]+)\1\]#', '.$2', $key);
2408
+
2409
+			if ($this->debug) {
2410
+				if ($hasMethodCall) {
2411
+					echo 'METHOD CALL FOUND : $' . $key . substr($methodCall, 0, 30) . "\n";
2412
+				} else {
2413
+					echo 'VAR FOUND : $' . $key . "\n";
2414
+				}
2415
+			}
2416
+
2417
+			$key = str_replace('"', '\\"', $key);
2418
+
2419
+			$cnt = substr_count($key, '$');
2420
+			if ($cnt > 0) {
2421
+				$uid           = 0;
2422
+				$parsed        = array($uid => '');
2423
+				$current       = &$parsed;
2424
+				$curTxt        = &$parsed[$uid ++];
2425
+				$tree          = array();
2426
+				$chars         = str_split($key, 1);
2427
+				$inSplittedVar = false;
2428
+				$bracketCount  = 0;
2429
+
2430
+				while (($char = array_shift($chars)) !== null) {
2431
+					if ($char === '[') {
2432
+						if (count($tree) > 0) {
2433
+							++ $bracketCount;
2434
+						} else {
2435
+							$tree[]        = &$current;
2436
+							$current[$uid] = array($uid + 1 => '');
2437
+							$current       = &$current[$uid ++];
2438
+							$curTxt        = &$current[$uid ++];
2439
+							continue;
2440
+						}
2441
+					} elseif ($char === ']') {
2442
+						if ($bracketCount > 0) {
2443
+							-- $bracketCount;
2444
+						} else {
2445
+							$current = &$tree[count($tree) - 1];
2446
+							array_pop($tree);
2447
+							if (current($chars) !== '[' && current($chars) !== false && current($chars) !== ']') {
2448
+								$current[$uid] = '';
2449
+								$curTxt        = &$current[$uid ++];
2450
+							}
2451
+							continue;
2452
+						}
2453
+					} elseif ($char === '$') {
2454
+						if (count($tree) == 0) {
2455
+							$curTxt        = &$current[$uid ++];
2456
+							$inSplittedVar = true;
2457
+						}
2458
+					} elseif (($char === '.' || $char === '-') && count($tree) == 0 && $inSplittedVar) {
2459
+						$curTxt        = &$current[$uid ++];
2460
+						$inSplittedVar = false;
2461
+					}
2462
+
2463
+					$curTxt .= $char;
2464
+				}
2465
+				unset($uid, $current, $curTxt, $tree, $chars);
2466
+
2467
+				if ($this->debug) {
2468
+					echo 'RECURSIVE VAR REPLACEMENT : ' . $key . "\n";
2469
+				}
2470
+
2471
+				$key = $this->flattenVarTree($parsed);
2472
+
2473
+				if ($this->debug) {
2474
+					echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2475
+				}
2476
+
2477
+				$output = preg_replace('#(^""\.|""\.|\.""$|(\()""\.|\.""(\)))#', '$2$3', '$this->readVar("' . $key . '")');
2478
+			} else {
2479
+				$output = $this->parseVarKey($key, $hasModifiers ? 'modifier' : $curBlock);
2480
+			}
2481
+
2482
+
2483
+			// methods
2484
+			if ($hasMethodCall) {
2485
+				$ptr = 0;
2486
+
2487
+				$output = $this->parseMethodCall($output, $methodCall, $curBlock, $ptr);
2488
+
2489
+				if ($pointer !== null) {
2490
+					$pointer += $ptr;
2491
+				}
2492
+				$matchedLength += $ptr;
2493
+			}
2494
+
2495
+			if ($hasExpression) {
2496
+				// expressions
2497
+				preg_match_all('#(?:([+/*%=-])(=?-?[%$][a-z0-9\\\\.[\]>_:-]+(?:\([^)]*\))?|=?-?[0-9.,]+|\1))#i', $match[4], $expMatch);
2498
+				foreach ($expMatch[1] as $k => $operator) {
2499
+					if (substr($expMatch[2][$k], 0, 1) === '=') {
2500
+						$assign = true;
2501
+						if ($operator === '=') {
2502
+							throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, can not use "==" in expressions');
2503
+						}
2504
+						if ($curBlock !== 'root') {
2505
+							throw new CompilationException($this, 'Invalid expression <em>' . $substr . '</em>, assignments can only be used in top level expressions like {$foo+=3} or {$foo="bar"}');
2506
+						}
2507
+						$operator .= '=';
2508
+						$expMatch[2][$k] = substr($expMatch[2][$k], 1);
2509
+					}
2510
+
2511
+					if (substr($expMatch[2][$k], 0, 1) === '-' && strlen($expMatch[2][$k]) > 1) {
2512
+						$operator .= '-';
2513
+						$expMatch[2][$k] = substr($expMatch[2][$k], 1);
2514
+					}
2515
+					if (($operator === '+' || $operator === '-') && $expMatch[2][$k] === $operator) {
2516
+						$output = '(' . $output . $operator . $operator . ')';
2517
+						break;
2518
+					} elseif (substr($expMatch[2][$k], 0, 1) === '$') {
2519
+						$output = '(' . $output . ' ' . $operator . ' ' . $this->parseVar($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2520
+					} elseif (substr($expMatch[2][$k], 0, 1) === '%') {
2521
+						$output = '(' . $output . ' ' . $operator . ' ' . $this->parseConst($expMatch[2][$k], 0, strlen($expMatch[2][$k]), false, 'expression') . ')';
2522
+					} elseif (!empty($expMatch[2][$k])) {
2523
+						$output = '(' . $output . ' ' . $operator . ' ' . str_replace(',', '.', $expMatch[2][$k]) . ')';
2524
+					} else {
2525
+						throw new CompilationException($this, 'Unfinished expression <em>' . $substr . '</em>, missing var or number after math operator');
2526
+					}
2527
+				}
2528
+			}
2529
+
2530
+			if ($this->autoEscape === true && $curBlock !== 'condition') {
2531
+				$output = '(is_string($tmp=' . $output . ') ? htmlspecialchars($tmp, ENT_QUOTES, $this->charset) : $tmp)';
2532
+			}
2533
+
2534
+			// handle modifiers
2535
+			if ($curBlock !== 'modifier' && $hasModifiers) {
2536
+				$ptr    = 0;
2537
+				$output = $this->replaceModifiers(array(null, null, $output, $match[5]), 'var', $ptr);
2538
+				if ($pointer !== null) {
2539
+					$pointer += $ptr;
2540
+				}
2541
+				$matchedLength += $ptr;
2542
+			}
2543
+
2544
+			if (is_array($parsingParams)) {
2545
+				$parsingParams[] = array($output, $key);
2546
+
2547
+				return $parsingParams;
2548
+			} elseif ($curBlock === 'namedparam') {
2549
+				return array($output, $key);
2550
+			} elseif ($curBlock === 'string' || $curBlock === 'delimited_string') {
2551
+				return array($matchedLength, $output);
2552
+			} elseif ($curBlock === 'expression' || $curBlock === 'variable') {
2553
+				return $output;
2554
+			} elseif (isset($assign)) {
2555
+				return self::PHP_OPEN . $output . ';' . self::PHP_CLOSE;
2556
+			}
2557
+
2558
+			return $output;
2559
+		} else {
2560
+			if ($curBlock === 'string' || $curBlock === 'delimited_string') {
2561
+				return array(0, '');
2562
+			}
2563
+			throw new CompilationException($this, 'Invalid variable name <em>' . $substr . '</em>');
2564
+		}
2565
+	}
2566
+
2567
+	/**
2568
+	 * Parses any number of chained method calls/property reads.
2569
+	 *
2570
+	 * @param string $output     the variable or whatever upon which the method are called
2571
+	 * @param string $methodCall method call source, starting at "->"
2572
+	 * @param string $curBlock   the current parser-block being processed
2573
+	 * @param int    $pointer    a reference to a pointer that will be increased by the amount of characters parsed
2574
+	 *
2575
+	 * @return string parsed call(s)/read(s)
2576
+	 */
2577
+	protected function parseMethodCall($output, $methodCall, $curBlock, &$pointer)
2578
+	{
2579
+		$ptr = 0;
2580
+		$len = strlen($methodCall);
2581
+
2582
+		while ($ptr < $len) {
2583
+			if (strpos($methodCall, '->', $ptr) === $ptr) {
2584
+				$ptr += 2;
2585
+			}
2586
+
2587
+			if (in_array(
2588
+				$methodCall[$ptr], array(
2589
+					';',
2590
+					',',
2591
+					'/',
2592
+					' ',
2593
+					"\t",
2594
+					"\r",
2595
+					"\n",
2596
+					')',
2597
+					'+',
2598
+					'*',
2599
+					'%',
2600
+					'=',
2601
+					'-',
2602
+					'|'
2603
+				)
2604
+			) || substr($methodCall, $ptr, strlen($this->rd)) === $this->rd
2605
+			) {
2606
+				// break char found
2607
+				break;
2608
+			}
2609
+
2610
+			if (!preg_match('/^([a-z0-9_]+)(\(.*?\))?/i', substr($methodCall, $ptr), $methMatch)) {
2611
+				break;
2612
+			}
2613
+
2614
+			if (empty($methMatch[2])) {
2615
+				// property
2616
+				if ($curBlock === 'root') {
2617
+					$output .= '->' . $methMatch[1];
2618
+				} else {
2619
+					$output = '(($tmp = ' . $output . ') ? $tmp->' . $methMatch[1] . ' : null)';
2620
+				}
2621
+				$ptr += strlen($methMatch[1]);
2622
+			} else {
2623
+				// method
2624
+				if (substr($methMatch[2], 0, 2) === '()') {
2625
+					$parsedCall = $methMatch[1] . '()';
2626
+					$ptr += strlen($methMatch[1]) + 2;
2627
+				} else {
2628
+					$parsedCall = $this->parseFunction($methodCall, $ptr, strlen($methodCall), false, 'method', $ptr);
2629
+				}
2630
+				if ($this->securityPolicy !== null) {
2631
+					$argPos = strpos($parsedCall, '(');
2632
+					$method = strtolower(substr($parsedCall, 0, $argPos));
2633
+					$args   = substr($parsedCall, $argPos);
2634
+					if ($curBlock === 'root') {
2635
+						$output = '$this->getSecurityPolicy()->callMethod($this, ' . $output . ', ' . var_export($method, true) . ', array' . $args . ')';
2636
+					} else {
2637
+						$output = '(($tmp = ' . $output . ') ? $this->getSecurityPolicy()->callMethod($this, $tmp, ' . var_export($method, true) . ', array' . $args . ') : null)';
2638
+					}
2639
+				} else {
2640
+					if ($curBlock === 'root') {
2641
+						$output .= '->' . $parsedCall;
2642
+					} else {
2643
+						$output = '(($tmp = ' . $output . ') ? $tmp->' . $parsedCall . ' : null)';
2644
+					}
2645
+				}
2646
+			}
2647
+		}
2648
+
2649
+		$pointer += $ptr;
2650
+
2651
+		return $output;
2652
+	}
2653
+
2654
+	/**
2655
+	 * Parses a constant variable (a variable that doesn't contain another variable) and preprocesses it to save
2656
+	 * runtime processing time.
2657
+	 *
2658
+	 * @param string $key      the variable to parse
2659
+	 * @param string $curBlock the current parser-block being processed
2660
+	 *
2661
+	 * @return string parsed variable
2662
+	 */
2663
+	protected function parseVarKey($key, $curBlock)
2664
+	{
2665
+		if ($key === '') {
2666
+			return '$this->scope';
2667
+		}
2668
+		if (substr($key, 0, 1) === '.') {
2669
+			$key = 'dwoo' . $key;
2670
+		}
2671
+		if (preg_match('#dwoo\.(get|post|server|cookies|session|env|request)((?:\.[a-z0-9_-]+)+)#i', $key, $m)) {
2672
+			$global = strtoupper($m[1]);
2673
+			if ($global === 'COOKIES') {
2674
+				$global = 'COOKIE';
2675
+			}
2676
+			$key = '$_' . $global;
2677
+			foreach (explode('.', ltrim($m[2], '.')) as $part) {
2678
+				$key .= '[' . var_export($part, true) . ']';
2679
+			}
2680
+			if ($curBlock === 'root') {
2681
+				$output = $key;
2682
+			} else {
2683
+				$output = '(isset(' . $key . ')?' . $key . ':null)';
2684
+			}
2685
+		} elseif (preg_match('#dwoo\\.const\\.([a-z0-9\\\\_:]+)#i', $key, $m)) {
2686
+			return $this->parseConstKey($m[1], $curBlock);
2687
+		} elseif ($this->scope !== null) {
2688
+			if (strstr($key, '.') === false && strstr($key, '[') === false && strstr($key, '->') === false) {
2689
+				if ($key === 'dwoo') {
2690
+					$output = '$this->globals';
2691
+				} elseif ($key === '_root' || $key === '__') {
2692
+					$output = '$this->data';
2693
+				} elseif ($key === '_parent' || $key === '_') {
2694
+					$output = '$this->readParentVar(1)';
2695
+				} elseif ($key === '_key') {
2696
+					$output = '$tmp_key';
2697
+				} else {
2698
+					if ($curBlock === 'root') {
2699
+						$output = '$this->scope["' . $key . '"]';
2700
+					} else {
2701
+						$output = '(isset($this->scope["' . $key . '"]) ? $this->scope["' . $key . '"] : null)';
2702
+					}
2703
+				}
2704
+			} else {
2705
+				preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+|(\\\?[\'"])[^\3]*?\3)\]?#i', $key, $m);
2706
+
2707
+				$i = $m[2][0];
2708
+				if ($i === '_parent' || $i === '_') {
2709
+					$parentCnt = 0;
2710
+
2711
+					while (true) {
2712
+						++ $parentCnt;
2713
+						array_shift($m[2]);
2714
+						array_shift($m[1]);
2715
+						if (current($m[2]) === '_parent') {
2716
+							continue;
2717
+						}
2718
+						break;
2719
+					}
2720
+
2721
+					$output = '$this->readParentVar(' . $parentCnt . ')';
2722
+				} else {
2723
+					if ($i === 'dwoo') {
2724
+						$output = '$this->globals';
2725
+						array_shift($m[2]);
2726
+						array_shift($m[1]);
2727
+					} elseif ($i === '_root' || $i === '__') {
2728
+						// $output = '$this->data';
2729
+						$output = '$this->getData()';
2730
+						array_shift($m[2]);
2731
+						array_shift($m[1]);
2732
+					} elseif ($i === '_key') {
2733
+						$output = '$tmp_key';
2734
+					} else {
2735
+						$output = '$this->scope';
2736
+					}
2737
+
2738
+					while (count($m[1]) && $m[1][0] !== '->') {
2739
+						$m[2][0] = preg_replace('/(^\\\([\'"])|\\\([\'"])$)/x', '$2$3', $m[2][0]);
2740
+						if (substr($m[2][0], 0, 1) == '"' || substr($m[2][0], 0, 1) == "'") {
2741
+							$output .= '[' . $m[2][0] . ']';
2742
+						} else {
2743
+							$output .= '["' . $m[2][0] . '"]';
2744
+						}
2745
+						array_shift($m[2]);
2746
+						array_shift($m[1]);
2747
+					}
2748
+
2749
+					if ($curBlock !== 'root') {
2750
+						$output = '(isset(' . $output . ') ? ' . $output . ':null)';
2751
+					}
2752
+				}
2753
+
2754
+				if (count($m[2])) {
2755
+					unset($m[0]);
2756
+					$output = '$this->readVarInto(' . str_replace("\n", '', var_export($m, true)) . ', ' . $output . ', ' . ($curBlock == 'root' ? 'false' : 'true') . ')';
2757
+				}
2758
+			}
2759
+		} else {
2760
+			preg_match_all('#(\[|->|\.)?((?:[a-z0-9_]|-(?!>))+)\]?#i', $key, $m);
2761
+			unset($m[0]);
2762
+			$output = '$this->readVar(' . str_replace("\n", '', var_export($m, true)) . ')';
2763
+		}
2764
+
2765
+		return $output;
2766
+	}
2767
+
2768
+	/**
2769
+	 * Flattens a variable tree, this helps in parsing very complex variables such as $var.foo[$foo.bar->baz].baz,
2770
+	 * it computes the contents of the brackets first and works out from there.
2771
+	 *
2772
+	 * @param array $tree     the variable tree parsed by he parseVar() method that must be flattened
2773
+	 * @param bool  $recursed leave that to false by default, it is only for internal use
2774
+	 *
2775
+	 * @return string flattened tree
2776
+	 */
2777
+	protected function flattenVarTree(array $tree, $recursed = false)
2778
+	{
2779
+		$out = $recursed ? '".$this->readVarInto(' : '';
2780
+		foreach ($tree as $bit) {
2781
+			if (is_array($bit)) {
2782
+				$out .= '.' . $this->flattenVarTree($bit, false);
2783
+			} else {
2784
+				$key = str_replace('"', '\\"', $bit);
2785
+
2786
+				if (substr($key, 0, 1) === '$') {
2787
+					$out .= '".' . $this->parseVar($key, 0, strlen($key), false, 'variable') . '."';
2788
+				} else {
2789
+					$cnt = substr_count($key, '$');
2790
+
2791
+					if ($this->debug) {
2792
+						echo 'PARSING SUBVARS IN : ' . $key . "\n";
2793
+					}
2794
+					if ($cnt > 0) {
2795
+						while (-- $cnt >= 0) {
2796
+							if (isset($last)) {
2797
+								$last = strrpos($key, '$', - (strlen($key) - $last + 1));
2798
+							} else {
2799
+								$last = strrpos($key, '$');
2800
+							}
2801
+							preg_match('#\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', substr($key, $last), $submatch);
2802
+
2803
+							$len = strlen($submatch[0]);
2804
+							$key = substr_replace(
2805
+								$key, preg_replace_callback(
2806
+									'#(\$[a-z0-9_]+((?:(?:\.|->)(?:[a-z0-9_]+|(?R))|\[(?:[a-z0-9_]+|(?R))\]))*)' . '((?:(?:[+/*%-])(?:\$[a-z0-9.[\]>_:-]+(?:\([^)]*\))?|[0-9.,]*))*)#i', array(
2807
+										$this,
2808
+										'replaceVarKeyHelper'
2809
+									), substr($key, $last, $len)
2810
+								), $last, $len
2811
+							);
2812
+							if ($this->debug) {
2813
+								echo 'RECURSIVE VAR REPLACEMENT DONE : ' . $key . "\n";
2814
+							}
2815
+						}
2816
+						unset($last);
2817
+
2818
+						$out .= $key;
2819
+					} else {
2820
+						$out .= $key;
2821
+					}
2822
+				}
2823
+			}
2824
+		}
2825
+		$out .= $recursed ? ', true)."' : '';
2826
+
2827
+		return $out;
2828
+	}
2829
+
2830
+	/**
2831
+	 * Helper function that parses a variable.
2832
+	 *
2833
+	 * @param array $match the matched variable, array(1=>"string match")
2834
+	 *
2835
+	 * @return string parsed variable
2836
+	 */
2837
+	protected function replaceVarKeyHelper($match)
2838
+	{
2839
+		return '".' . $this->parseVar($match[0], 0, strlen($match[0]), false, 'variable') . '."';
2840
+	}
2841
+
2842
+	/**
2843
+	 * Parses various constants, operators or non-quoted strings.
2844
+	 *
2845
+	 * @param string $in            the string within which we must parse something
2846
+	 * @param int    $from          the starting offset of the parsed area
2847
+	 * @param int    $to            the ending offset of the parsed area
2848
+	 * @param mixed  $parsingParams must be an array if we are parsing a function or modifier's parameters, or false by
2849
+	 *                              default
2850
+	 * @param string $curBlock      the current parser-block being processed
2851
+	 * @param mixed  $pointer       a reference to a pointer that will be increased by the amount of characters parsed,
2852
+	 *                              or null by default
2853
+	 *
2854
+	 * @return string parsed values
2855
+	 * @throws Exception
2856
+	 */
2857
+	protected function parseOthers($in, $from, $to, $parsingParams = false, $curBlock = '', &$pointer = null)
2858
+	{
2859
+		$substr = substr($in, $from, $to - $from);
2860
+
2861
+		$end = strlen($substr);
2862
+
2863
+		if ($curBlock === 'condition') {
2864
+			$breakChars = array(
2865
+				'(',
2866
+				')',
2867
+				' ',
2868
+				'||',
2869
+				'&&',
2870
+				'|',
2871
+				'&',
2872
+				'>=',
2873
+				'<=',
2874
+				'===',
2875
+				'==',
2876
+				'=',
2877
+				'!==',
2878
+				'!=',
2879
+				'<<',
2880
+				'<',
2881
+				'>>',
2882
+				'>',
2883
+				'^',
2884
+				'~',
2885
+				',',
2886
+				'+',
2887
+				'-',
2888
+				'*',
2889
+				'/',
2890
+				'%',
2891
+				'!',
2892
+				'?',
2893
+				':',
2894
+				$this->rd,
2895
+				';'
2896
+			);
2897
+		} elseif ($curBlock === 'modifier') {
2898
+			$breakChars = array(' ', ',', ')', ':', '|', "\r", "\n", "\t", ';', $this->rd);
2899
+		} elseif ($curBlock === 'expression') {
2900
+			$breakChars = array('/', '%', '+', '-', '*', ' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2901
+		} else {
2902
+			$breakChars = array(' ', ',', ')', "\r", "\n", "\t", ';', $this->rd);
2903
+		}
2904
+
2905
+		$breaker = false;
2906
+		foreach ($breakChars as $k => $char) {
2907
+			$test = strpos($substr, $char);
2908
+			if ($test !== false && $test < $end) {
2909
+				$end     = $test;
2910
+				$breaker = $k;
2911
+			}
2912
+		}
2913
+
2914
+		if ($curBlock === 'condition') {
2915
+			if ($end === 0 && $breaker !== false) {
2916
+				$end = strlen($breakChars[$breaker]);
2917
+			}
2918
+		}
2919
+
2920
+		if ($end !== false) {
2921
+			$substr = substr($substr, 0, $end);
2922
+		}
2923
+
2924
+		if ($pointer !== null) {
2925
+			$pointer += strlen($substr);
2926
+		}
2927
+
2928
+		$src    = $substr;
2929
+		$substr = trim($substr);
2930
+
2931
+		if (strtolower($substr) === 'false' || strtolower($substr) === 'no' || strtolower($substr) === 'off') {
2932
+			if ($this->debug) {
2933
+				echo 'BOOLEAN(FALSE) PARSED' . "\n";
2934
+			}
2935
+			$substr = 'false';
2936
+			$type   = self::T_BOOL;
2937
+		} elseif (strtolower($substr) === 'true' || strtolower($substr) === 'yes' || strtolower($substr) === 'on') {
2938
+			if ($this->debug) {
2939
+				echo 'BOOLEAN(TRUE) PARSED' . "\n";
2940
+			}
2941
+			$substr = 'true';
2942
+			$type   = self::T_BOOL;
2943
+		} elseif ($substr === 'null' || $substr === 'NULL') {
2944
+			if ($this->debug) {
2945
+				echo 'NULL PARSED' . "\n";
2946
+			}
2947
+			$substr = 'null';
2948
+			$type   = self::T_NULL;
2949
+		} elseif (is_numeric($substr)) {
2950
+			$substr = (float)$substr;
2951
+			if ((int)$substr == $substr) {
2952
+				$substr = (int)$substr;
2953
+			}
2954
+			$type = self::T_NUMERIC;
2955
+			if ($this->debug) {
2956
+				echo 'NUMBER (' . $substr . ') PARSED' . "\n";
2957
+			}
2958
+		} elseif (preg_match('{^-?(\d+|\d*(\.\d+))\s*([/*%+-]\s*-?(\d+|\d*(\.\d+)))+$}', $substr)) {
2959
+			if ($this->debug) {
2960
+				echo 'SIMPLE MATH PARSED . "\n"';
2961
+			}
2962
+			$type   = self::T_MATH;
2963
+			$substr = '(' . $substr . ')';
2964
+		} elseif ($curBlock === 'condition' && array_search($substr, $breakChars, true) !== false) {
2965
+			if ($this->debug) {
2966
+				echo 'BREAKCHAR (' . $substr . ') PARSED' . "\n";
2967
+			}
2968
+			$type = self::T_BREAKCHAR;
2969
+			//$substr = '"'.$substr.'"';
2970
+		} else {
2971
+			$substr = $this->replaceStringVars('\'' . str_replace('\'', '\\\'', $substr) . '\'', '\'', $curBlock);
2972
+			$type   = self::T_UNQUOTED_STRING;
2973
+			if ($this->debug) {
2974
+				echo 'BLABBER (' . $substr . ') CASTED AS STRING' . "\n";
2975
+			}
2976
+		}
2977
+
2978
+		if (is_array($parsingParams)) {
2979
+			$parsingParams[] = array($substr, $src, $type);
2980
+
2981
+			return $parsingParams;
2982
+		} elseif ($curBlock === 'namedparam') {
2983
+			return array($substr, $src, $type);
2984
+		} elseif ($curBlock === 'expression') {
2985
+			return $substr;
2986
+		} else {
2987
+			throw new Exception('Something went wrong');
2988
+		}
2989
+	}
2990
+
2991
+	/**
2992
+	 * Replaces variables within a parsed string.
2993
+	 *
2994
+	 * @param string $string   the parsed string
2995
+	 * @param string $first    the first character parsed in the string, which is the string delimiter (' or ")
2996
+	 * @param string $curBlock the current parser-block being processed
2997
+	 *
2998
+	 * @return string the original string with variables replaced
2999
+	 */
3000
+	protected function replaceStringVars($string, $first, $curBlock = '')
3001
+	{
3002
+		$pos = 0;
3003
+		if ($this->debug) {
3004
+			echo 'STRING VAR REPLACEMENT : ' . $string . "\n";
3005
+		}
3006
+		// replace vars
3007
+		while (($pos = strpos($string, '$', $pos)) !== false) {
3008
+			$prev = substr($string, $pos - 1, 1);
3009
+			if ($prev === '\\') {
3010
+				++ $pos;
3011
+				continue;
3012
+			}
3013
+
3014
+			$var = $this->parse($string, $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3015
+			$len = $var[0];
3016
+			$var = $this->parse(str_replace('\\' . $first, $first, $string), $pos, null, false, ($curBlock === 'modifier' ? 'modifier' : ($prev === '`' ? 'delimited_string' : 'string')));
3017
+
3018
+			if ($prev === '`' && substr($string, $pos + $len, 1) === '`') {
3019
+				$string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos - 1, $len + 2);
3020
+			} else {
3021
+				$string = substr_replace($string, $first . '.' . $var[1] . '.' . $first, $pos, $len);
3022
+			}
3023
+			$pos += strlen($var[1]) + 2;
3024
+			if ($this->debug) {
3025
+				echo 'STRING VAR REPLACEMENT DONE : ' . $string . "\n";
3026
+			}
3027
+		}
3028
+
3029
+		// handle modifiers
3030
+		// TODO Obsolete?
3031
+		$string = preg_replace_callback(
3032
+			'#("|\')\.(.+?)\.\1((?:\|(?:@?[a-z0-9_]+(?:(?::("|\').+?\4|:[^`]*))*))+)#i', array(
3033
+			$this,
3034
+			'replaceModifiers'
3035
+			), $string
3036
+		);
3037
+
3038
+		// replace escaped dollar operators by unescaped ones if required
3039
+		if ($first === "'") {
3040
+			$string = str_replace('\\$', '$', $string);
3041
+		}
3042
+
3043
+		return $string;
3044
+	}
3045
+
3046
+	/**
3047
+	 * Replaces the modifiers applied to a string or a variable.
3048
+	 *
3049
+	 * @param array  $m        the regex matches that must be array(1=>"double or single quotes enclosing a string,
3050
+	 *                         when applicable", 2=>"the string or var", 3=>"the modifiers matched")
3051
+	 * @param string $curBlock the current parser-block being processed
3052
+	 * @param null   $pointer
3053
+	 *
3054
+	 * @return string the input enclosed with various function calls according to the modifiers found
3055
+	 * @throws CompilationException
3056
+	 * @throws Exception
3057
+	 */
3058
+	protected function replaceModifiers(array $m, $curBlock = null, &$pointer = null)
3059
+	{
3060
+		if ($this->debug) {
3061
+			echo 'PARSING MODIFIERS : ' . $m[3] . "\n";
3062
+		}
3063
+
3064
+		if ($pointer !== null) {
3065
+			$pointer += strlen($m[3]);
3066
+		}
3067
+		// remove first pipe
3068
+		$cmdstrsrc = substr($m[3], 1);
3069
+		// remove last quote if present
3070
+		if (substr($cmdstrsrc, - 1, 1) === $m[1]) {
3071
+			$cmdstrsrc = substr($cmdstrsrc, 0, - 1);
3072
+			$add       = $m[1];
3073
+		}
3074
+
3075
+		$output = $m[2];
3076
+
3077
+		$continue = true;
3078
+		while (strlen($cmdstrsrc) > 0 && $continue) {
3079
+			if ($cmdstrsrc[0] === '|') {
3080
+				$cmdstrsrc = substr($cmdstrsrc, 1);
3081
+				continue;
3082
+			}
3083
+			if ($cmdstrsrc[0] === ' ' || $cmdstrsrc[0] === ';' || substr($cmdstrsrc, 0, strlen($this->rd)) === $this->rd) {
3084
+				if ($this->debug) {
3085
+					echo 'MODIFIER PARSING ENDED, RIGHT DELIMITER or ";" FOUND' . "\n";
3086
+				}
3087
+				$continue = false;
3088
+				if ($pointer !== null) {
3089
+					$pointer -= strlen($cmdstrsrc);
3090
+				}
3091
+				break;
3092
+			}
3093
+			$cmdstr   = $cmdstrsrc;
3094
+			$paramsep = ':';
3095
+			if (!preg_match('/^(@{0,2}[a-z_][a-z0-9_]*)(:)?/i', $cmdstr, $match)) {
3096
+				throw new CompilationException($this, 'Invalid modifier name, started with : ' . substr($cmdstr, 0, 10));
3097
+			}
3098
+			$paramspos = !empty($match[2]) ? strlen($match[1]) : false;
3099
+			$func      = $match[1];
3100
+
3101
+			$state = 0;
3102
+			if ($paramspos === false) {
3103
+				$cmdstrsrc = substr($cmdstrsrc, strlen($func));
3104
+				$params    = array();
3105
+				if ($this->debug) {
3106
+					echo 'MODIFIER (' . $func . ') CALLED WITH NO PARAMS' . "\n";
3107
+				}
3108
+			} else {
3109
+				$paramstr = substr($cmdstr, $paramspos + 1);
3110
+				if (substr($paramstr, - 1, 1) === $paramsep) {
3111
+					$paramstr = substr($paramstr, 0, - 1);
3112
+				}
3113
+
3114
+				$ptr    = 0;
3115
+				$params = array();
3116
+				while ($ptr < strlen($paramstr)) {
3117
+					if ($this->debug) {
3118
+						echo 'MODIFIER (' . $func . ') START PARAM PARSING WITH POINTER AT ' . $ptr . "\n";
3119
+					}
3120
+					if ($this->debug) {
3121
+						echo $paramstr . '--' . $ptr . '--' . strlen($paramstr) . '--modifier' . "\n";
3122
+					}
3123
+					$params = $this->parse($paramstr, $ptr, strlen($paramstr), $params, 'modifier', $ptr);
3124
+					if ($this->debug) {
3125
+						echo 'PARAM PARSED, POINTER AT ' . $ptr . "\n";
3126
+					}
3127
+
3128
+					if ($ptr >= strlen($paramstr)) {
3129
+						if ($this->debug) {
3130
+							echo 'PARAM PARSING ENDED, PARAM STRING CONSUMED' . "\n";
3131
+						}
3132
+						break;
3133
+					}
3134
+
3135
+					if ($paramstr[$ptr] === ' ' || $paramstr[$ptr] === '|' || $paramstr[$ptr] === ';' || substr($paramstr, $ptr, strlen($this->rd)) === $this->rd) {
3136
+						if ($this->debug) {
3137
+							echo 'PARAM PARSING ENDED, " ", "|", RIGHT DELIMITER or ";" FOUND, POINTER AT ' . $ptr . "\n";
3138
+						}
3139
+						if ($paramstr[$ptr] !== '|') {
3140
+							$continue = false;
3141
+							if ($pointer !== null) {
3142
+								$pointer -= strlen($paramstr) - $ptr;
3143
+							}
3144
+						}
3145
+						++ $ptr;
3146
+						break;
3147
+					}
3148
+					if ($ptr < strlen($paramstr) && $paramstr[$ptr] === ':') {
3149
+						++ $ptr;
3150
+					}
3151
+				}
3152
+				$cmdstrsrc = substr($cmdstrsrc, strlen($func) + 1 + $ptr);
3153
+				foreach ($params as $k => $p) {
3154
+					if (is_array($p) && is_array($p[1])) {
3155
+						$state |= 2;
3156
+					} else {
3157
+						if (($state & 2) && preg_match('#^(["\'])(.+?)\1$#', $p[0], $m)) {
3158
+							$params[$k] = array($m[2], array('true', 'true'));
3159
+						} else {
3160
+							if ($state & 2) {
3161
+								throw new CompilationException($this, 'You can not use an unnamed parameter after a named one');
3162
+							}
3163
+							$state |= 1;
3164
+						}
3165
+					}
3166
+				}
3167
+			}
3168
+
3169
+			// check if we must use array_map with this plugin or not
3170
+			$mapped = false;
3171
+			if (substr($func, 0, 1) === '@') {
3172
+				$func   = substr($func, 1);
3173
+				$mapped = true;
3174
+			}
3175
+
3176
+			$pluginType = $this->getPluginType($func);
3177
+
3178
+			if ($state & 2) {
3179
+				array_unshift($params, array('value', is_array($output) ? $output : array($output, $output)));
3180
+			} else {
3181
+				array_unshift($params, is_array($output) ? $output : array($output, $output));
3182
+			}
3183
+
3184
+			if ($pluginType & Core::NATIVE_PLUGIN) {
3185
+				$params = $this->mapParams($params, null, $state);
3186
+
3187
+				$params = $params['*'][0];
3188
+
3189
+				$params = self::implode_r($params);
3190
+
3191
+				if ($mapped) {
3192
+					$output = '$this->arrayMap(\'' . $func . '\', array(' . $params . '))';
3193
+				} else {
3194
+					$output = $func . '(' . $params . ')';
3195
+				}
3196
+			} elseif ($pluginType & Core::PROXY_PLUGIN) {
3197
+				$params = $this->mapParams($params, $this->getCore()->getPluginProxy()->getCallback($func), $state);
3198
+				foreach ($params as &$p) {
3199
+					$p = $p[0];
3200
+				}
3201
+				$output = call_user_func(array($this->getCore()->getPluginProxy(), 'getCode'), $func, $params);
3202
+			} elseif ($pluginType & Core::SMARTY_MODIFIER) {
3203
+				$params = $this->mapParams($params, null, $state);
3204
+				$params = $params['*'][0];
3205
+
3206
+				$params = self::implode_r($params);
3207
+
3208
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
3209
+					$callback = $this->customPlugins[$func]['callback'];
3210
+					if (is_array($callback)) {
3211
+						if (is_object($callback[0])) {
3212
+							$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(' . $params . '))';
3213
+						} else {
3214
+							$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3215
+						}
3216
+					} elseif ($mapped) {
3217
+						$output = '$this->arrayMap(\'' . $callback . '\', array(' . $params . '))';
3218
+					} else {
3219
+						$output = $callback . '(' . $params . ')';
3220
+					}
3221
+				} elseif ($mapped) {
3222
+					$output = '$this->arrayMap(\'smarty_modifier_' . $func . '\', array(' . $params . '))';
3223
+				} else {
3224
+					$output = 'smarty_modifier_' . $func . '(' . $params . ')';
3225
+				}
3226
+			} else {
3227
+				if ($pluginType & Core::CUSTOM_PLUGIN) {
3228
+					$pluginName = $callback = $this->customPlugins[$func]['callback'];
3229
+					if (($pluginType & Core::CLASS_PLUGIN) && !is_array($callback)) {
3230
+						$pluginName = $this->customPlugins[$func]['callback'];
3231
+						$callback   = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3232
+					}
3233
+				} else {
3234
+					if (class_exists('Plugin' . Core::toCamelCase($func)) !== false || function_exists('Plugin' .
3235
+							Core::toCamelCase($func) . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : ''))
3236
+						!== false) {
3237
+						$pluginName = 'Plugin' . Core::toCamelCase($func);
3238
+					} else {
3239
+						$pluginName = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func);
3240
+					}
3241
+					if ($pluginType & Core::CLASS_PLUGIN) {
3242
+						$callback = array($pluginName, ($pluginType & Core::COMPILABLE_PLUGIN) ? 'compile' : 'process');
3243
+					} else {
3244
+						$callback = $pluginName . (($pluginType & Core::COMPILABLE_PLUGIN) ? 'Compile' : '');
3245
+					}
3246
+				}
3247
+				$params = $this->mapParams($params, $callback, $state);
3248
+
3249
+				foreach ($params as &$p) {
3250
+					$p = $p[0];
3251
+				}
3252
+
3253
+				// Only for PHP function, who is not a PHP class
3254
+				if ($pluginType & Core::FUNC_PLUGIN && !($pluginType & Core::CLASS_PLUGIN)) {
3255
+					if ($pluginType & Core::COMPILABLE_PLUGIN) {
3256
+						if ($mapped) {
3257
+							throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3258
+						}
3259
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3260
+							$funcCompiler = $this->customPlugins[$func]['callback'];
3261
+						} else {
3262
+							if (function_exists('Plugin' . Core::toCamelCase($func) . 'Compile') !== false) {
3263
+								$funcCompiler = 'Plugin' . Core::toCamelCase($func) . 'Compile';
3264
+							} else {
3265
+								$funcCompiler = Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) .
3266
+									'Compile';
3267
+							}
3268
+						}
3269
+						array_unshift($params, $this);
3270
+						$output = call_user_func_array($funcCompiler, $params);
3271
+					} else {
3272
+						array_unshift($params, '$this');
3273
+
3274
+						$params = self::implode_r($params);
3275
+						if ($mapped) {
3276
+							$output = '$this->arrayMap(\'' . $pluginName . '\', array(' . $params . '))';
3277
+						} else {
3278
+							$output = $pluginName . '(' . $params . ')';
3279
+						}
3280
+					}
3281
+				} else {
3282
+					if ($pluginType & Core::COMPILABLE_PLUGIN) {
3283
+						if ($mapped) {
3284
+							throw new CompilationException($this, 'The @ operator can not be used on compiled plugins.');
3285
+						}
3286
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3287
+							$callback = $this->customPlugins[$func]['callback'];
3288
+							if (!is_array($callback)) {
3289
+								if (!method_exists($callback, 'compile')) {
3290
+									throw new Exception('Custom plugin ' . $func . ' must implement the "compile" method to be compilable, or you should provide a full callback to the method to use');
3291
+								}
3292
+								if (($ref = new ReflectionMethod($callback, 'compile')) && $ref->isStatic()) {
3293
+									$funcCompiler = array($callback, 'compile');
3294
+								} else {
3295
+									$funcCompiler = array(new $callback(), 'compile');
3296
+								}
3297
+							} else {
3298
+								$funcCompiler = $callback;
3299
+							}
3300
+						} else {
3301
+							if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3302
+								$funcCompiler = array('Plugin' . Core::toCamelCase($func), 'compile');
3303
+							} else {
3304
+								$funcCompiler = array(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func), 'compile');
3305
+							}
3306
+							array_unshift($params, $this);
3307
+						}
3308
+						$output = call_user_func_array($funcCompiler, $params);
3309
+					} else {
3310
+						$params = self::implode_r($params);
3311
+
3312
+						if ($pluginType & Core::CUSTOM_PLUGIN) {
3313
+							if (is_object($callback[0])) {
3314
+								if (is_array($this->getCore()->getCustomPlugin($func))) {
3315
+									$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->plugins[\'' . $func . '\'][\'callback\'][0], \'' . $callback[1] . '\'), array(' . $params . '))';
3316
+								} else {
3317
+									$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array($this->getCustomPlugin(\'' . $func . '\'), \'' . $callback[1] . '\'), array(' . $params . '))';
3318
+								}
3319
+							} else {
3320
+								$output = ($mapped ? '$this->arrayMap' : 'call_user_func_array') . '(array(\'' . $callback[0] . '\', \'' . $callback[1] . '\'), array(' . $params . '))';
3321
+							}
3322
+						} elseif ($mapped) {
3323
+							$output = '$this->arrayMap(array($this->getObjectPlugin(\''.
3324
+								Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func) . '\'),
3325 3325
                             \'process\'), array(' . $params . '))';
3326
-                        } else {
3327
-                            if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3328
-                                $output = '$this->classCall(\'Plugin' . Core::toCamelCase($func) . '\', array(' . $params . '))';
3329
-                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3330
-                                $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . $func . '\', array(' . $params . '))';
3331
-                            } elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3332
-                                $output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', array(' . $params . '))';
3333
-                            } else {
3334
-                                $output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
3335
-                            }
3336
-                        }
3337
-                    }
3338
-                }
3339
-            }
3340
-        }
3341
-
3342
-        if ($curBlock === 'namedparam') {
3343
-            return array($output, $output);
3344
-        } elseif ($curBlock === 'var' || $m[1] === null) {
3345
-            return $output;
3346
-        } elseif ($curBlock === 'string' || $curBlock === 'root') {
3347
-            return $m[1] . '.' . $output . '.' . $m[1] . (isset($add) ? $add : null);
3348
-        }
3349
-
3350
-        return '';
3351
-    }
3352
-
3353
-    /**
3354
-     * Recursively implodes an array in a similar manner as var_export() does but with some tweaks
3355
-     * to handle pre-compiled values and the fact that we do not need to enclose everything with
3356
-     * "array" and do not require top-level keys to be displayed.
3357
-     *
3358
-     * @param array $params        the array to implode
3359
-     * @param bool  $recursiveCall if set to true, the function outputs key names for the top level
3360
-     *
3361
-     * @return string the imploded array
3362
-     */
3363
-    public static function implode_r(array $params, $recursiveCall = false)
3364
-    {
3365
-        $out = '';
3366
-        foreach ($params as $k => $p) {
3367
-            if (is_array($p)) {
3368
-                $out2 = 'array(';
3369
-                foreach ($p as $k2 => $v) {
3370
-                    $out2 .= var_export($k2, true) . ' => ' . (is_array($v) ? 'array(' . self::implode_r($v, true) . ')' : $v) . ', ';
3371
-                }
3372
-                $p = rtrim($out2, ', ') . ')';
3373
-            }
3374
-            if ($recursiveCall) {
3375
-                $out .= var_export($k, true) . ' => ' . $p . ', ';
3376
-            } else {
3377
-                $out .= $p . ', ';
3378
-            }
3379
-        }
3380
-
3381
-        return rtrim($out, ', ');
3382
-    }
3383
-
3384
-    /**
3385
-     * Returns the plugin type of a plugin and adds it to the used plugins array if required.
3386
-     *
3387
-     * @param string $name plugin name, as found in the template
3388
-     *
3389
-     * @return int type as a multi bit flag composed of the Dwoo plugin types constants
3390
-     * @throws Exception
3391
-     * @throws SecurityException
3392
-     * @throws Exception
3393
-     */
3394
-    protected function getPluginType($name)
3395
-    {
3396
-        $pluginType = - 1;
3397
-
3398
-        if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || ($this->securityPolicy !== null && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
3399
-            $phpFunc = true;
3400
-        } elseif ($this->securityPolicy !== null && function_exists($name) && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) === false) {
3401
-            throw new SecurityException('Call to a disallowed php function : ' . $name);
3402
-        }
3403
-
3404
-        while ($pluginType <= 0) {
3405
-            // Template plugin compilable
3406
-            if (isset($this->templatePlugins[$name])) {
3407
-                $pluginType = Core::TEMPLATE_PLUGIN | Core::COMPILABLE_PLUGIN;
3408
-            } // Custom plugin
3409
-            elseif (isset($this->customPlugins[$name])) {
3410
-                $pluginType = $this->customPlugins[$name]['type'] | Core::CUSTOM_PLUGIN;
3411
-            } // Class blocks plugin
3412
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3413
-                $pluginType = Core::CLASS_PLUGIN;
3414
-                if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3415
-                    $pluginType += Core::BLOCK_PLUGIN;
3416
-                }
3417
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name));
3418
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3419
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3420
-                }
3421
-            } // Class functions plugin
3422
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3423
-                $pluginType = Core::FUNC_PLUGIN + Core::CLASS_PLUGIN;
3424
-                $interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name));
3425
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3426
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3427
-                }
3428
-            } // Class without namespace
3429
-            elseif (class_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3430
-                $pluginType = Core::CLASS_PLUGIN;
3431
-                if (is_subclass_of('Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3432
-                    $pluginType += Core::BLOCK_PLUGIN;
3433
-                }
3434
-                $interfaces = class_implements('Plugin' . Core::toCamelCase($name));
3435
-                if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3436
-                    $pluginType |= Core::COMPILABLE_PLUGIN;
3437
-                }
3438
-            } // Function plugin (with/without namespaces)
3439
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase ($name)) !==
3440
-                false || function_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3441
-                $pluginType = Core::FUNC_PLUGIN;
3442
-            } // Function plugin compile (with/without namespaces)
3443
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name) .
3444
-                    'Compile') !== false || function_exists('Plugin' . Core::toCamelCase($name) . 'Compile') !==
3445
-                false) {
3446
-                $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3447
-            } // Helper plugin class compile
3448
-            elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3449
-                $pluginType = Core::CLASS_PLUGIN | Core::COMPILABLE_PLUGIN;
3450
-            } // Helper plugin function compile
3451
-            elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name) . 'Compile') !== false) {
3452
-                $pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3453
-            } // Smarty modifier
3454
-            elseif (function_exists('smarty_modifier_' . $name) !== false) {
3455
-                $pluginType = Core::SMARTY_MODIFIER;
3456
-            } // Smarty function
3457
-            elseif (function_exists('smarty_function_' . $name) !== false) {
3458
-                $pluginType = Core::SMARTY_FUNCTION;
3459
-            } // Smarty block
3460
-            elseif (function_exists('smarty_block_' . $name) !== false) {
3461
-                $pluginType = Core::SMARTY_BLOCK;
3462
-            } // Everything else
3463
-            else {
3464
-                if ($pluginType === - 1) {
3465
-                    try {
3466
-                        $this->getCore()->getLoader()->loadPlugin('Plugin' . Core::toCamelCase($name));
3467
-                    }
3468
-                    catch (Exception $e) {
3469
-                        if (isset($phpFunc)) {
3470
-                            $pluginType = Core::NATIVE_PLUGIN;
3471
-                        } elseif (is_object($this->getCore()->getPluginProxy()) && $this->getCore()->getPluginProxy()->handles($name)) {
3472
-                            $pluginType = Core::PROXY_PLUGIN;
3473
-                            break;
3474
-                        } else {
3475
-                            throw $e;
3476
-                        }
3477
-                    }
3478
-                } else {
3479
-                    throw new Exception('Plugin "' . $name . '" could not be found, type:' . $pluginType);
3480
-                }
3481
-                ++ $pluginType;
3482
-            }
3483
-        }
3484
-
3485
-        if (($pluginType & Core::COMPILABLE_PLUGIN) === 0 && ($pluginType & Core::NATIVE_PLUGIN) === 0 && ($pluginType & Core::PROXY_PLUGIN) === 0) {
3486
-            $this->addUsedPlugin(Core::toCamelCase($name), $pluginType);
3487
-        }
3488
-
3489
-        return $pluginType;
3490
-    }
3491
-
3492
-    /**
3493
-     * Allows a plugin to load another one at compile time, this will also mark
3494
-     * it as used by this template so it will be loaded at runtime (which can be
3495
-     * useful for compiled plugins that rely on another plugin when their compiled
3496
-     * code runs).
3497
-     *
3498
-     * @param string $name the plugin name
3499
-     *
3500
-     * @return void
3501
-     */
3502
-    public function loadPlugin($name)
3503
-    {
3504
-        $this->getPluginType($name);
3505
-    }
3506
-
3507
-    /**
3508
-     * Runs htmlentities over the matched <?php ?> blocks when the security policy enforces that.
3509
-     *
3510
-     * @param array $match matched php block
3511
-     *
3512
-     * @return string the htmlentities-converted string
3513
-     */
3514
-    protected function phpTagEncodingHelper($match)
3515
-    {
3516
-        return htmlspecialchars($match[0]);
3517
-    }
3518
-
3519
-    /**
3520
-     * Maps the parameters received from the template onto the parameters required by the given callback.
3521
-     *
3522
-     * @param array    $params   the array of parameters
3523
-     * @param callback $callback the function or method to reflect on to find out the required parameters
3524
-     * @param int      $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named
3525
-     *                           parameters call
3526
-     * @param array    $map      the parameter map to use, if not provided it will be built from the callback
3527
-     *
3528
-     * @return array parameters sorted in the correct order with missing optional parameters filled
3529
-     * @throws CompilationException
3530
-     */
3531
-    protected function mapParams(array $params, $callback, $callType = 2, $map = null)
3532
-    {
3533
-        if (!$map) {
3534
-            $map = $this->getParamMap($callback);
3535
-        }
3536
-
3537
-        $paramlist = array();
3538
-
3539
-        // transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
3540
-        $ps = array();
3541
-        foreach ($params as $p) {
3542
-            if (is_array($p[1])) {
3543
-                $ps[$p[0]] = $p[1];
3544
-            } else {
3545
-                $ps[] = $p;
3546
-            }
3547
-        }
3548
-
3549
-        // loops over the param map and assigns values from the template or default value for unset optional params
3550
-        foreach ($map as $k => $v){
3551
-            if ($v[0] === '*') {
3552
-                // "rest" array parameter, fill every remaining params in it and then break
3553
-                if (count($ps) === 0) {
3554
-                    if ($v[1] === false) {
3555
-                        throw new CompilationException(
3556
-                            $this, 'Rest argument missing for ' . str_replace(
3557
-                                array(
3558
-                                    Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3559
-                                'Compile'
3560
-                                ), '', (is_array($callback) ? $callback[0] : $callback)
3561
-                            )
3562
-                        );
3563
-                    } else {
3564
-                        break;
3565
-                    }
3566
-                }
3567
-                $tmp  = array();
3568
-                $tmp2 = array();
3569
-                $tmp3 = array();
3570
-                foreach ($ps as $i => $p) {
3571
-                    $tmp[$i]  = $p[0];
3572
-                    $tmp2[$i] = $p[1];
3573
-                    $tmp3[$i] = isset($p[2]) ? $p[2] : 0;
3574
-                    unset($ps[$i]);
3575
-                }
3576
-                $paramlist[$v[0]] = array($tmp, $tmp2, $tmp3);
3577
-                unset($tmp, $tmp2, $i, $p);
3578
-                break;
3579
-            } elseif (isset($ps[$v[0]])) {
3580
-                // parameter is defined as named param
3581
-                $paramlist[$v[0]] = $ps[$v[0]];
3582
-                unset($ps[$v[0]]);
3583
-            } elseif (isset($ps[$k])) {
3584
-                // parameter is defined as ordered param
3585
-                $paramlist[$v[0]] = $ps[$k];
3586
-                unset($ps[$k]);
3587
-            } elseif ($v[1] === false) {
3588
-                // parameter is not defined and not optional, throw error
3589
-                if (is_array($callback)) {
3590
-                    if (is_object($callback[0])) {
3591
-                        $name = get_class($callback[0]) . '::' . $callback[1];
3592
-                    } else {
3593
-                        $name = $callback[0];
3594
-                    }
3595
-                } else {
3596
-                    $name = $callback;
3597
-                }
3598
-
3599
-                throw new CompilationException(
3600
-                    $this, 'Argument ' . $k . '/' . $v[0] . ' missing for ' . str_replace(
3601
-                        array(
3602
-                            Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3603
-                        'Compile'
3604
-                        ), '', $name
3605
-                    )
3606
-                );
3607
-            } elseif ($v[2] === null) {
3608
-                // enforce lowercased null if default value is null (php outputs NULL with var export)
3609
-                $paramlist[$v[0]] = array('null', null, self::T_NULL);
3610
-            } else {
3611
-                // outputs default value with var_export
3612
-                $paramlist[$v[0]] = array(var_export($v[2], true), $v[2]);
3613
-            }
3614
-        }
3615
-
3616
-        if (count($ps)) {
3617
-            foreach ($ps as $i => $p) {
3618
-                array_push($paramlist, $p);
3619
-            }
3620
-        }
3621
-
3622
-        return $paramlist;
3623
-    }
3624
-
3625
-    /**
3626
-     * Returns the parameter map of the given callback, it filters out entries typed as Dwoo and Compiler and turns the
3627
-     * rest parameter into a "*".
3628
-     *
3629
-     * @param callback $callback the function/method to reflect on
3630
-     *
3631
-     * @return array processed parameter map
3632
-     */
3633
-    protected function getParamMap($callback)
3634
-    {
3635
-        if (is_null($callback)) {
3636
-            return array(array('*', true));
3637
-        }
3638
-        if (is_array($callback)) {
3639
-            $ref = new ReflectionMethod($callback[0], $callback[1]);
3640
-        } else {
3641
-            $ref = new ReflectionFunction($callback);
3642
-        }
3643
-
3644
-        $out = array();
3645
-        foreach ($ref->getParameters() as $param) {
3646
-            if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Core') {
3647
-                continue;
3648
-            }
3649
-            if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Compiler') {
3650
-                continue;
3651
-            }
3652
-            if ($param->getName() === 'rest' && $param->isArray() === true) {
3653
-                $out[] = array('*', $param->isOptional(), null);
3654
-                continue;
3655
-            }
3656
-            $out[] = array(
3657
-                $param->getName(),
3658
-                $param->isOptional(),
3659
-                $param->isOptional() ? $param->getDefaultValue() : null
3660
-            );
3661
-        }
3662
-
3663
-        return $out;
3664
-    }
3665
-
3666
-    /**
3667
-     * Returns a default instance of this compiler, used by default by all Dwoo templates that do not have a
3668
-     * specific compiler assigned and when you do not override the default compiler factory function.
3669
-     *
3670
-     * @see    Core::setDefaultCompilerFactory()
3671
-     * @return Compiler
3672
-     */
3673
-    public static function compilerFactory()
3674
-    {
3675
-        if (self::$instance === null) {
3676
-            self::$instance = new self();
3677
-        }
3678
-
3679
-        return self::$instance;
3680
-    }
3326
+						} else {
3327
+							if (class_exists('Plugin' . Core::toCamelCase($func)) !== false) {
3328
+								$output = '$this->classCall(\'Plugin' . Core::toCamelCase($func) . '\', array(' . $params . '))';
3329
+							} elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3330
+								$output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . $func . '\', array(' . $params . '))';
3331
+							} elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($func)) !== false) {
3332
+								$output = '$this->classCall(\'' . Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . $func . '\', array(' . $params . '))';
3333
+							} else {
3334
+								$output = '$this->classCall(\'' . $func . '\', array(' . $params . '))';
3335
+							}
3336
+						}
3337
+					}
3338
+				}
3339
+			}
3340
+		}
3341
+
3342
+		if ($curBlock === 'namedparam') {
3343
+			return array($output, $output);
3344
+		} elseif ($curBlock === 'var' || $m[1] === null) {
3345
+			return $output;
3346
+		} elseif ($curBlock === 'string' || $curBlock === 'root') {
3347
+			return $m[1] . '.' . $output . '.' . $m[1] . (isset($add) ? $add : null);
3348
+		}
3349
+
3350
+		return '';
3351
+	}
3352
+
3353
+	/**
3354
+	 * Recursively implodes an array in a similar manner as var_export() does but with some tweaks
3355
+	 * to handle pre-compiled values and the fact that we do not need to enclose everything with
3356
+	 * "array" and do not require top-level keys to be displayed.
3357
+	 *
3358
+	 * @param array $params        the array to implode
3359
+	 * @param bool  $recursiveCall if set to true, the function outputs key names for the top level
3360
+	 *
3361
+	 * @return string the imploded array
3362
+	 */
3363
+	public static function implode_r(array $params, $recursiveCall = false)
3364
+	{
3365
+		$out = '';
3366
+		foreach ($params as $k => $p) {
3367
+			if (is_array($p)) {
3368
+				$out2 = 'array(';
3369
+				foreach ($p as $k2 => $v) {
3370
+					$out2 .= var_export($k2, true) . ' => ' . (is_array($v) ? 'array(' . self::implode_r($v, true) . ')' : $v) . ', ';
3371
+				}
3372
+				$p = rtrim($out2, ', ') . ')';
3373
+			}
3374
+			if ($recursiveCall) {
3375
+				$out .= var_export($k, true) . ' => ' . $p . ', ';
3376
+			} else {
3377
+				$out .= $p . ', ';
3378
+			}
3379
+		}
3380
+
3381
+		return rtrim($out, ', ');
3382
+	}
3383
+
3384
+	/**
3385
+	 * Returns the plugin type of a plugin and adds it to the used plugins array if required.
3386
+	 *
3387
+	 * @param string $name plugin name, as found in the template
3388
+	 *
3389
+	 * @return int type as a multi bit flag composed of the Dwoo plugin types constants
3390
+	 * @throws Exception
3391
+	 * @throws SecurityException
3392
+	 * @throws Exception
3393
+	 */
3394
+	protected function getPluginType($name)
3395
+	{
3396
+		$pluginType = - 1;
3397
+
3398
+		if (($this->securityPolicy === null && (function_exists($name) || strtolower($name) === 'isset' || strtolower($name) === 'empty')) || ($this->securityPolicy !== null && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) !== false)) {
3399
+			$phpFunc = true;
3400
+		} elseif ($this->securityPolicy !== null && function_exists($name) && array_key_exists(strtolower($name), $this->securityPolicy->getAllowedPhpFunctions()) === false) {
3401
+			throw new SecurityException('Call to a disallowed php function : ' . $name);
3402
+		}
3403
+
3404
+		while ($pluginType <= 0) {
3405
+			// Template plugin compilable
3406
+			if (isset($this->templatePlugins[$name])) {
3407
+				$pluginType = Core::TEMPLATE_PLUGIN | Core::COMPILABLE_PLUGIN;
3408
+			} // Custom plugin
3409
+			elseif (isset($this->customPlugins[$name])) {
3410
+				$pluginType = $this->customPlugins[$name]['type'] | Core::CUSTOM_PLUGIN;
3411
+			} // Class blocks plugin
3412
+			elseif (class_exists(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3413
+				$pluginType = Core::CLASS_PLUGIN;
3414
+				if (is_subclass_of(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3415
+					$pluginType += Core::BLOCK_PLUGIN;
3416
+				}
3417
+				$interfaces = class_implements(Core::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . Core::toCamelCase($name));
3418
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3419
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3420
+				}
3421
+			} // Class functions plugin
3422
+			elseif (class_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3423
+				$pluginType = Core::FUNC_PLUGIN + Core::CLASS_PLUGIN;
3424
+				$interfaces = class_implements(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name));
3425
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3426
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3427
+				}
3428
+			} // Class without namespace
3429
+			elseif (class_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3430
+				$pluginType = Core::CLASS_PLUGIN;
3431
+				if (is_subclass_of('Plugin' . Core::toCamelCase($name), 'Dwoo\Block\Plugin')) {
3432
+					$pluginType += Core::BLOCK_PLUGIN;
3433
+				}
3434
+				$interfaces = class_implements('Plugin' . Core::toCamelCase($name));
3435
+				if (in_array('Dwoo\ICompilable', $interfaces) !== false || in_array('Dwoo\ICompilable\Block', $interfaces) !== false) {
3436
+					$pluginType |= Core::COMPILABLE_PLUGIN;
3437
+				}
3438
+			} // Function plugin (with/without namespaces)
3439
+			elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase ($name)) !==
3440
+				false || function_exists('Plugin' . Core::toCamelCase($name)) !== false) {
3441
+				$pluginType = Core::FUNC_PLUGIN;
3442
+			} // Function plugin compile (with/without namespaces)
3443
+			elseif (function_exists(Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin' . Core::toCamelCase($name) .
3444
+					'Compile') !== false || function_exists('Plugin' . Core::toCamelCase($name) . 'Compile') !==
3445
+				false) {
3446
+				$pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3447
+			} // Helper plugin class compile
3448
+			elseif (class_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name)) !== false) {
3449
+				$pluginType = Core::CLASS_PLUGIN | Core::COMPILABLE_PLUGIN;
3450
+			} // Helper plugin function compile
3451
+			elseif (function_exists(Core::NAMESPACE_PLUGINS_HELPERS . 'Plugin' . Core::toCamelCase($name) . 'Compile') !== false) {
3452
+				$pluginType = Core::FUNC_PLUGIN | Core::COMPILABLE_PLUGIN;
3453
+			} // Smarty modifier
3454
+			elseif (function_exists('smarty_modifier_' . $name) !== false) {
3455
+				$pluginType = Core::SMARTY_MODIFIER;
3456
+			} // Smarty function
3457
+			elseif (function_exists('smarty_function_' . $name) !== false) {
3458
+				$pluginType = Core::SMARTY_FUNCTION;
3459
+			} // Smarty block
3460
+			elseif (function_exists('smarty_block_' . $name) !== false) {
3461
+				$pluginType = Core::SMARTY_BLOCK;
3462
+			} // Everything else
3463
+			else {
3464
+				if ($pluginType === - 1) {
3465
+					try {
3466
+						$this->getCore()->getLoader()->loadPlugin('Plugin' . Core::toCamelCase($name));
3467
+					}
3468
+					catch (Exception $e) {
3469
+						if (isset($phpFunc)) {
3470
+							$pluginType = Core::NATIVE_PLUGIN;
3471
+						} elseif (is_object($this->getCore()->getPluginProxy()) && $this->getCore()->getPluginProxy()->handles($name)) {
3472
+							$pluginType = Core::PROXY_PLUGIN;
3473
+							break;
3474
+						} else {
3475
+							throw $e;
3476
+						}
3477
+					}
3478
+				} else {
3479
+					throw new Exception('Plugin "' . $name . '" could not be found, type:' . $pluginType);
3480
+				}
3481
+				++ $pluginType;
3482
+			}
3483
+		}
3484
+
3485
+		if (($pluginType & Core::COMPILABLE_PLUGIN) === 0 && ($pluginType & Core::NATIVE_PLUGIN) === 0 && ($pluginType & Core::PROXY_PLUGIN) === 0) {
3486
+			$this->addUsedPlugin(Core::toCamelCase($name), $pluginType);
3487
+		}
3488
+
3489
+		return $pluginType;
3490
+	}
3491
+
3492
+	/**
3493
+	 * Allows a plugin to load another one at compile time, this will also mark
3494
+	 * it as used by this template so it will be loaded at runtime (which can be
3495
+	 * useful for compiled plugins that rely on another plugin when their compiled
3496
+	 * code runs).
3497
+	 *
3498
+	 * @param string $name the plugin name
3499
+	 *
3500
+	 * @return void
3501
+	 */
3502
+	public function loadPlugin($name)
3503
+	{
3504
+		$this->getPluginType($name);
3505
+	}
3506
+
3507
+	/**
3508
+	 * Runs htmlentities over the matched <?php ?> blocks when the security policy enforces that.
3509
+	 *
3510
+	 * @param array $match matched php block
3511
+	 *
3512
+	 * @return string the htmlentities-converted string
3513
+	 */
3514
+	protected function phpTagEncodingHelper($match)
3515
+	{
3516
+		return htmlspecialchars($match[0]);
3517
+	}
3518
+
3519
+	/**
3520
+	 * Maps the parameters received from the template onto the parameters required by the given callback.
3521
+	 *
3522
+	 * @param array    $params   the array of parameters
3523
+	 * @param callback $callback the function or method to reflect on to find out the required parameters
3524
+	 * @param int      $callType the type of call in the template, 0 = no params, 1 = php-style call, 2 = named
3525
+	 *                           parameters call
3526
+	 * @param array    $map      the parameter map to use, if not provided it will be built from the callback
3527
+	 *
3528
+	 * @return array parameters sorted in the correct order with missing optional parameters filled
3529
+	 * @throws CompilationException
3530
+	 */
3531
+	protected function mapParams(array $params, $callback, $callType = 2, $map = null)
3532
+	{
3533
+		if (!$map) {
3534
+			$map = $this->getParamMap($callback);
3535
+		}
3536
+
3537
+		$paramlist = array();
3538
+
3539
+		// transforms the parameter array from (x=>array('paramname'=>array(values))) to (paramname=>array(values))
3540
+		$ps = array();
3541
+		foreach ($params as $p) {
3542
+			if (is_array($p[1])) {
3543
+				$ps[$p[0]] = $p[1];
3544
+			} else {
3545
+				$ps[] = $p;
3546
+			}
3547
+		}
3548
+
3549
+		// loops over the param map and assigns values from the template or default value for unset optional params
3550
+		foreach ($map as $k => $v){
3551
+			if ($v[0] === '*') {
3552
+				// "rest" array parameter, fill every remaining params in it and then break
3553
+				if (count($ps) === 0) {
3554
+					if ($v[1] === false) {
3555
+						throw new CompilationException(
3556
+							$this, 'Rest argument missing for ' . str_replace(
3557
+								array(
3558
+									Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3559
+								'Compile'
3560
+								), '', (is_array($callback) ? $callback[0] : $callback)
3561
+							)
3562
+						);
3563
+					} else {
3564
+						break;
3565
+					}
3566
+				}
3567
+				$tmp  = array();
3568
+				$tmp2 = array();
3569
+				$tmp3 = array();
3570
+				foreach ($ps as $i => $p) {
3571
+					$tmp[$i]  = $p[0];
3572
+					$tmp2[$i] = $p[1];
3573
+					$tmp3[$i] = isset($p[2]) ? $p[2] : 0;
3574
+					unset($ps[$i]);
3575
+				}
3576
+				$paramlist[$v[0]] = array($tmp, $tmp2, $tmp3);
3577
+				unset($tmp, $tmp2, $i, $p);
3578
+				break;
3579
+			} elseif (isset($ps[$v[0]])) {
3580
+				// parameter is defined as named param
3581
+				$paramlist[$v[0]] = $ps[$v[0]];
3582
+				unset($ps[$v[0]]);
3583
+			} elseif (isset($ps[$k])) {
3584
+				// parameter is defined as ordered param
3585
+				$paramlist[$v[0]] = $ps[$k];
3586
+				unset($ps[$k]);
3587
+			} elseif ($v[1] === false) {
3588
+				// parameter is not defined and not optional, throw error
3589
+				if (is_array($callback)) {
3590
+					if (is_object($callback[0])) {
3591
+						$name = get_class($callback[0]) . '::' . $callback[1];
3592
+					} else {
3593
+						$name = $callback[0];
3594
+					}
3595
+				} else {
3596
+					$name = $callback;
3597
+				}
3598
+
3599
+				throw new CompilationException(
3600
+					$this, 'Argument ' . $k . '/' . $v[0] . ' missing for ' . str_replace(
3601
+						array(
3602
+							Core::NAMESPACE_PLUGINS_FUNCTIONS . 'Plugin',
3603
+						'Compile'
3604
+						), '', $name
3605
+					)
3606
+				);
3607
+			} elseif ($v[2] === null) {
3608
+				// enforce lowercased null if default value is null (php outputs NULL with var export)
3609
+				$paramlist[$v[0]] = array('null', null, self::T_NULL);
3610
+			} else {
3611
+				// outputs default value with var_export
3612
+				$paramlist[$v[0]] = array(var_export($v[2], true), $v[2]);
3613
+			}
3614
+		}
3615
+
3616
+		if (count($ps)) {
3617
+			foreach ($ps as $i => $p) {
3618
+				array_push($paramlist, $p);
3619
+			}
3620
+		}
3621
+
3622
+		return $paramlist;
3623
+	}
3624
+
3625
+	/**
3626
+	 * Returns the parameter map of the given callback, it filters out entries typed as Dwoo and Compiler and turns the
3627
+	 * rest parameter into a "*".
3628
+	 *
3629
+	 * @param callback $callback the function/method to reflect on
3630
+	 *
3631
+	 * @return array processed parameter map
3632
+	 */
3633
+	protected function getParamMap($callback)
3634
+	{
3635
+		if (is_null($callback)) {
3636
+			return array(array('*', true));
3637
+		}
3638
+		if (is_array($callback)) {
3639
+			$ref = new ReflectionMethod($callback[0], $callback[1]);
3640
+		} else {
3641
+			$ref = new ReflectionFunction($callback);
3642
+		}
3643
+
3644
+		$out = array();
3645
+		foreach ($ref->getParameters() as $param) {
3646
+			if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Core') {
3647
+				continue;
3648
+			}
3649
+			if (($class = $param->getClass()) !== null && $class->name === 'Dwoo\Compiler') {
3650
+				continue;
3651
+			}
3652
+			if ($param->getName() === 'rest' && $param->isArray() === true) {
3653
+				$out[] = array('*', $param->isOptional(), null);
3654
+				continue;
3655
+			}
3656
+			$out[] = array(
3657
+				$param->getName(),
3658
+				$param->isOptional(),
3659
+				$param->isOptional() ? $param->getDefaultValue() : null
3660
+			);
3661
+		}
3662
+
3663
+		return $out;
3664
+	}
3665
+
3666
+	/**
3667
+	 * Returns a default instance of this compiler, used by default by all Dwoo templates that do not have a
3668
+	 * specific compiler assigned and when you do not override the default compiler factory function.
3669
+	 *
3670
+	 * @see    Core::setDefaultCompilerFactory()
3671
+	 * @return Compiler
3672
+	 */
3673
+	public static function compilerFactory()
3674
+	{
3675
+		if (self::$instance === null) {
3676
+			self::$instance = new self();
3677
+		}
3678
+
3679
+		return self::$instance;
3680
+	}
3681 3681
 }
Please login to merge, or discard this patch.
lib/Dwoo/Core.php 2 patches
Indentation   +1748 added lines, -1748 removed lines patch added patch discarded remove patch
@@ -44,1752 +44,1752 @@
 block discarded – undo
44 44
  */
45 45
 class Core
46 46
 {
47
-    /**
48
-     * Current version number.
49
-     *
50
-     * @var string
51
-     */
52
-    const VERSION = '1.3.6';
53
-
54
-    /**
55
-     * Unique number of this dwoo release, based on version number.
56
-     * this can be used by templates classes to check whether the compiled template
57
-     * has been compiled before this release or not, so that old templates are
58
-     * recompiled automatically when Dwoo is updated
59
-     */
60
-    const RELEASE_TAG = 136;
61
-
62
-    /**
63
-     * Constants that represents all plugin types
64
-     * these are bitwise-operation-safe values to allow multiple types
65
-     * on a single plugin
66
-     *
67
-     * @var int
68
-     */
69
-    const CLASS_PLUGIN      = 1;
70
-    const FUNC_PLUGIN       = 2;
71
-    const NATIVE_PLUGIN     = 4;
72
-    const BLOCK_PLUGIN      = 8;
73
-    const COMPILABLE_PLUGIN = 16;
74
-    const CUSTOM_PLUGIN     = 32;
75
-    const SMARTY_MODIFIER   = 64;
76
-    const SMARTY_BLOCK      = 128;
77
-    const SMARTY_FUNCTION   = 256;
78
-    const PROXY_PLUGIN      = 512;
79
-    const TEMPLATE_PLUGIN   = 1024;
80
-
81
-    /**
82
-     * Constant to default namespaces of builtin plugins
83
-     *
84
-     * @var string
85
-     */
86
-    const NAMESPACE_PLUGINS_BLOCKS     = 'Dwoo\Plugins\Blocks\\';
87
-    const NAMESPACE_PLUGINS_FILTERS    = 'Dwoo\Plugins\Filters\\';
88
-    const NAMESPACE_PLUGINS_FUNCTIONS  = 'Dwoo\Plugins\Functions\\';
89
-    const NAMESPACE_PLUGINS_HELPERS    = 'Dwoo\Plugins\Helpers\\';
90
-    const NAMESPACE_PLUGINS_PROCESSORS = 'Dwoo\Plugins\Processors\\';
91
-
92
-    /**
93
-     * Character set of the template, used by string manipulation plugins.
94
-     * it must be lowercase, but setCharset() will take care of that
95
-     *
96
-     * @see setCharset
97
-     * @see getCharset
98
-     * @var string
99
-     */
100
-    protected $charset = 'UTF-8';
101
-
102
-    /**
103
-     * Global variables that are accessible through $dwoo.* in the templates.
104
-     * default values include:
105
-     * $dwoo.version - current version number
106
-     * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
107
-     * $dwoo.now - the current time
108
-     * $dwoo.template - the current template filename
109
-     * $dwoo.charset - the character set used by the template
110
-     * on top of that, foreach and other plugins can store special values in there,
111
-     * see their documentation for more details.
112
-     *
113
-     * @var array
114
-     */
115
-    protected $globals = array();
116
-
117
-    /**
118
-     * Directory where the compiled templates are stored.
119
-     * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default)
120
-     *
121
-     * @var string
122
-     */
123
-    protected $compileDir;
124
-
125
-    /**
126
-     * Directory where the cached templates are stored.
127
-     * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default)
128
-     *
129
-     * @var string
130
-     */
131
-    protected $cacheDir;
132
-
133
-    /**
134
-     * Directory where the template files are stored
135
-     *
136
-     * @var array
137
-     */
138
-    protected $templateDir = array();
139
-
140
-    /**
141
-     * Defines how long (in seconds) the cached files must remain valid.
142
-     * can be overridden on a per-template basis
143
-     * -1 = never delete
144
-     * 0 = disabled
145
-     * >0 = duration in seconds
146
-     *
147
-     * @var int
148
-     */
149
-    protected $cacheTime = 0;
150
-
151
-    /**
152
-     * Security policy object.
153
-     *
154
-     * @var SecurityPolicy
155
-     */
156
-    protected $securityPolicy = null;
157
-
158
-    /**
159
-     * Stores the custom plugins callbacks.
160
-     *
161
-     * @see addPlugin
162
-     * @see removePlugin
163
-     * @var array
164
-     */
165
-    protected $plugins = array();
166
-
167
-    /**
168
-     * Stores the filter callbacks.
169
-     *
170
-     * @see addFilter
171
-     * @see removeFilter
172
-     * @var array
173
-     */
174
-    protected $filters = array();
175
-
176
-    /**
177
-     * Stores the resource types and associated
178
-     * classes / compiler classes.
179
-     *
180
-     * @var array
181
-     */
182
-    protected $resources = array(
183
-        'file'   => array(
184
-            'class'    => 'Dwoo\Template\File',
185
-            'compiler' => null,
186
-        ),
187
-        'string' => array(
188
-            'class'    => 'Dwoo\Template\Str',
189
-            'compiler' => null,
190
-        ),
191
-    );
192
-
193
-    /**
194
-     * The dwoo loader object used to load plugins by this dwoo instance.
195
-     *
196
-     * @var ILoader
197
-     */
198
-    protected $loader = null;
199
-
200
-    /**
201
-     * Currently rendered template, set to null when not-rendering.
202
-     *
203
-     * @var ITemplate
204
-     */
205
-    protected $template = null;
206
-
207
-    /**
208
-     * Stores the instances of the class plugins during template runtime.
209
-     *
210
-     * @var array
211
-     */
212
-    protected $runtimePlugins = array();
213
-
214
-    /**
215
-     * Stores the returned values during template runtime.
216
-     *
217
-     * @var array
218
-     */
219
-    protected $returnData = array();
220
-
221
-    /**
222
-     * Stores the data during template runtime.
223
-     *
224
-     * @var array
225
-     */
226
-    protected $data = array();
227
-
228
-    /**
229
-     * Stores the current scope during template runtime.
230
-     * this should ideally not be accessed directly from outside template code
231
-     *
232
-     * @var mixed
233
-     */
234
-    public $scope;
235
-
236
-    /**
237
-     * Stores the scope tree during template runtime.
238
-     *
239
-     * @var array
240
-     */
241
-    protected $scopeTree = array();
242
-
243
-    /**
244
-     * Stores the block plugins stack during template runtime.
245
-     *
246
-     * @var array
247
-     */
248
-    protected $stack = array();
249
-
250
-    /**
251
-     * Stores the current block plugin at the top of the stack during template runtime.
252
-     *
253
-     * @var BlockPlugin
254
-     */
255
-    protected $curBlock;
256
-
257
-    /**
258
-     * Stores the output buffer during template runtime.
259
-     *
260
-     * @var string
261
-     */
262
-    protected $buffer;
263
-
264
-    /**
265
-     * Stores plugin proxy.
266
-     *
267
-     * @var IPluginProxy
268
-     */
269
-    protected $pluginProxy;
270
-
271
-    /**
272
-     * Constructor, sets the cache and compile dir to the default values if not provided.
273
-     *
274
-     * @param string $compileDir path to the compiled directory, defaults to lib/compiled
275
-     * @param string $cacheDir   path to the cache directory, defaults to lib/cache
276
-     */
277
-    public function __construct($compileDir = null, $cacheDir = null)
278
-    {
279
-        if ($compileDir !== null) {
280
-            $this->setCompileDir($compileDir);
281
-        }
282
-        if ($cacheDir !== null) {
283
-            $this->setCacheDir($cacheDir);
284
-        }
285
-        $this->initGlobals();
286
-    }
287
-
288
-    /**
289
-     * Resets some runtime variables to allow a cloned object to be used to render sub-templates.
290
-     *
291
-     * @return void
292
-     */
293
-    public function __clone()
294
-    {
295
-        $this->template = null;
296
-        unset($this->data);
297
-        unset($this->returnData);
298
-    }
299
-
300
-    /**
301
-     * Returns the given template rendered using the provided data and optional compiler.
302
-     *
303
-     * @param mixed     $_tpl      template, can either be a ITemplate object (i.e. TemplateFile), a
304
-     *                             valid path to a template, or a template as a string it is recommended to
305
-     *                             provide a ITemplate as it will probably make things faster, especially if
306
-     *                             you render a template multiple times
307
-     * @param mixed     $data      the data to use, can either be a IDataProvider object (i.e. Data) or
308
-     *                             an associative array. if you're rendering the template from cache, it can be
309
-     *                             left null
310
-     * @param ICompiler $_compiler the compiler that must be used to compile the template, if left empty a default
311
-     *                             Compiler will be used
312
-     *
313
-     * @return string|void or the template output if $output is false
314
-     * @throws Exception
315
-     */
316
-    public function get($_tpl, $data = array(), $_compiler = null)
317
-    {
318
-        // a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
319
-        if ($this->template instanceof ITemplate) {
320
-            $clone = clone $this;
321
-
322
-            return $clone->get($_tpl, $data, $_compiler);
323
-        }
324
-
325
-        // auto-create template if required
326
-        if ($_tpl instanceof ITemplate) {
327
-            // valid, skip
328
-        } elseif (is_string($_tpl)) {
329
-            $_tpl = new TemplateFile($_tpl);
330
-            $_tpl->setIncludePath($this->getTemplateDir());
331
-        } else {
332
-            throw new Exception('Dwoo->get\'s first argument must be a ITemplate (i.e. TemplateFile) or a valid path to a template file', E_USER_NOTICE);
333
-        }
334
-
335
-        // save the current template, enters render mode at the same time
336
-        // if another rendering is requested it will be proxied to a new Core(instance
337
-        $this->template = $_tpl;
338
-
339
-        // load data
340
-        if ($data instanceof IDataProvider) {
341
-            $this->data = $data->getData();
342
-        } elseif (is_array($data)) {
343
-            $this->data = $data;
344
-        } elseif ($data instanceof ArrayAccess) {
345
-            $this->data = $data;
346
-        } else {
347
-            throw new Exception('Dwoo->get/Dwoo->output\'s data argument must be a IDataProvider object (i.e. Data) or an associative array', E_USER_NOTICE);
348
-        }
349
-
350
-        $this->addGlobal('template', $_tpl->getName());
351
-        $this->initRuntimeVars($_tpl);
352
-
353
-        // try to get cached template
354
-        $file        = $_tpl->getCachedTemplate($this);
355
-        $doCache     = $file === true;
356
-        $cacheLoaded = is_string($file);
357
-
358
-        if ($cacheLoaded === true) {
359
-            // cache is present, run it
360
-            ob_start();
361
-            include $file;
362
-            $this->template = null;
363
-
364
-            return ob_get_clean();
365
-        } else {
366
-            $dynamicId = uniqid();
367
-
368
-            // render template
369
-            $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
370
-            $out              = include $compiledTemplate;
371
-
372
-            // template returned false so it needs to be recompiled
373
-            if ($out === false) {
374
-                $_tpl->forceCompilation();
375
-                $compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
376
-                $out              = include $compiledTemplate;
377
-            }
378
-
379
-            if ($doCache === true) {
380
-                $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
381
-                if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
382
-                    $this->getLoader()->loadPlugin('PluginDynamic');
383
-                }
384
-                $out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
385
-            }
386
-
387
-            // process filters
388
-            foreach ($this->filters as $filter) {
389
-                if (is_array($filter) && $filter[0] instanceof Filter) {
390
-                    $out = call_user_func($filter, $out);
391
-                } else {
392
-                    $out = call_user_func($filter, $this, $out);
393
-                }
394
-            }
395
-
396
-            if ($doCache === true) {
397
-                // building cache
398
-                $file = $_tpl->cache($this, $out);
399
-
400
-                // run it from the cache to be sure dynamics are rendered
401
-                ob_start();
402
-                include $file;
403
-                // exit render mode
404
-                $this->template = null;
405
-
406
-                return ob_get_clean();
407
-            } else {
408
-                // no need to build cache
409
-                // exit render mode
410
-                $this->template = null;
411
-
412
-                return $out;
413
-            }
414
-        }
415
-    }
416
-
417
-    /**
418
-     * Registers a Global.
419
-     * New globals can be added before compiling or rendering a template
420
-     * but after, you can only update existing globals.
421
-     *
422
-     * @param string $name
423
-     * @param mixed  $value
424
-     *
425
-     * @return $this
426
-     * @throws Exception
427
-     */
428
-    public function addGlobal($name, $value)
429
-    {
430
-        if (null === $this->globals) {
431
-            $this->initGlobals();
432
-        }
433
-
434
-        $this->globals[$name] = $value;
435
-
436
-        return $this;
437
-    }
438
-
439
-    /**
440
-     * Gets the registered Globals.
441
-     *
442
-     * @return array
443
-     */
444
-    public function getGlobals()
445
-    {
446
-        return $this->globals;
447
-    }
448
-
449
-    /**
450
-     * Re-initializes the globals array before each template run.
451
-     * this method is only callede once when the Dwoo object is created
452
-     *
453
-     * @return void
454
-     */
455
-    protected function initGlobals()
456
-    {
457
-        $this->globals = array(
458
-            'version' => self::VERSION,
459
-            'ad'      => '<a href="http://dwoo.org/">Powered by Dwoo</a>',
460
-            'now'     => $_SERVER['REQUEST_TIME'],
461
-            'charset' => $this->getCharset(),
462
-        );
463
-    }
464
-
465
-    /**
466
-     * Re-initializes the runtime variables before each template run.
467
-     * override this method to inject data in the globals array if needed, this
468
-     * method is called before each template execution
469
-     *
470
-     * @param ITemplate $tpl the template that is going to be rendered
471
-     *
472
-     * @return void
473
-     */
474
-    protected function initRuntimeVars(ITemplate $tpl)
475
-    {
476
-        $this->runtimePlugins = array();
477
-        $this->scope          = &$this->data;
478
-        $this->scopeTree      = array();
479
-        $this->stack          = array();
480
-        $this->curBlock       = null;
481
-        $this->buffer         = '';
482
-        $this->returnData     = array();
483
-    }
484
-
485
-    /**
486
-     * Adds a custom plugin that is not in one of the plugin directories.
487
-     *
488
-     * @param string   $name       the plugin name to be used in the templates
489
-     * @param callback $callback   the plugin callback, either a function name,
490
-     *                             a class name or an array containing an object
491
-     *                             or class name and a method name
492
-     * @param bool     $compilable if set to true, the plugin is assumed to be compilable
493
-     *
494
-     * @return void
495
-     * @throws Exception
496
-     */
497
-    public function addPlugin($name, $callback, $compilable = false)
498
-    {
499
-        $compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
500
-        if (is_array($callback)) {
501
-            if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo\Block\Plugin')) {
502
-                $this->plugins[$name] = array(
503
-                    'type'     => self::BLOCK_PLUGIN | $compilable,
504
-                    'callback' => $callback,
505
-                    'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0])
506
-                );
507
-            } else {
508
-                $this->plugins[$name] = array(
509
-                    'type'     => self::CLASS_PLUGIN | $compilable,
510
-                    'callback' => $callback,
511
-                    'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0]),
512
-                    'function' => $callback[1]
513
-                );
514
-            }
515
-        } elseif (is_string($callback)) {
516
-            if (class_exists($callback)) {
517
-                if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
518
-                    $this->plugins[$name] = array(
519
-                        'type'     => self::BLOCK_PLUGIN | $compilable,
520
-                        'callback' => $callback,
521
-                        'class'    => $callback
522
-                    );
523
-                } else {
524
-                    $this->plugins[$name] = array(
525
-                        'type'     => self::CLASS_PLUGIN | $compilable,
526
-                        'callback' => $callback,
527
-                        'class'    => $callback,
528
-                        'function' => ($compilable ? 'compile' : 'process')
529
-                    );
530
-                }
531
-            } elseif (function_exists($callback)) {
532
-                $this->plugins[$name] = array(
533
-                    'type'     => self::FUNC_PLUGIN | $compilable,
534
-                    'callback' => $callback
535
-                );
536
-            } else {
537
-                throw new Exception('Callback could not be processed correctly, please check that the function/class you used exists');
538
-            }
539
-        } elseif ($callback instanceof Closure) {
540
-            $this->plugins[$name] = array(
541
-                'type'     => self::FUNC_PLUGIN | $compilable,
542
-                'callback' => $callback
543
-            );
544
-        } elseif (is_object($callback)) {
545
-            if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
546
-                $this->plugins[$name] = array(
547
-                    'type'     => self::BLOCK_PLUGIN | $compilable,
548
-                    'callback' => get_class($callback),
549
-                    'class'    => $callback
550
-                );
551
-            } else {
552
-                $this->plugins[$name] = array(
553
-                    'type'     => self::CLASS_PLUGIN | $compilable,
554
-                    'callback' => $callback,
555
-                    'class'    => $callback,
556
-                    'function' => ($compilable ? 'compile' : 'process')
557
-                );
558
-            }
559
-        } else {
560
-            throw new Exception('Callback could not be processed correctly, please check that the function/class you used exists');
561
-        }
562
-    }
563
-
564
-    /**
565
-     * Removes a custom plugin.
566
-     *
567
-     * @param string $name the plugin name
568
-     *
569
-     * @return void
570
-     */
571
-    public function removePlugin($name)
572
-    {
573
-        if (isset($this->plugins[$name])) {
574
-            unset($this->plugins[$name]);
575
-        }
576
-    }
577
-
578
-    /**
579
-     * Adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this
580
-     * instance.
581
-     *
582
-     * @param mixed $callback a callback or a filter name if it is autoloaded from a plugin directory
583
-     * @param bool  $autoload if true, the first parameter must be a filter name from one of the plugin directories
584
-     *
585
-     * @return void
586
-     * @throws Exception
587
-     */
588
-    public function addFilter($callback, $autoload = false)
589
-    {
590
-        if ($autoload) {
591
-            $class = self::NAMESPACE_PLUGINS_FILTERS . self::toCamelCase($callback);
592
-            if (!class_exists($class) && !function_exists($class)) {
593
-                try {
594
-                    $this->getLoader()->loadPlugin($callback);
595
-                }
596
-                catch (Exception $e) {
597
-                    if (strstr($callback, self::NAMESPACE_PLUGINS_FILTERS)) {
598
-                        throw new Exception('Wrong filter name : ' . $callback . ', the "Filter" prefix should not be used, please only use "' . str_replace('Filter', '', $callback) . '"');
599
-                    } else {
600
-                        throw new Exception('Wrong filter name : ' . $callback . ', when using autoload the filter must be in one of your plugin dir as "name.php" containig a class or function named "Filter<name>"');
601
-                    }
602
-                }
603
-            }
604
-
605
-            if (class_exists($class)) {
606
-                $callback = array(new $class($this), 'process');
607
-            } elseif (function_exists($class)) {
608
-                $callback = $class;
609
-            } else {
610
-                throw new Exception('Wrong filter name : ' . $callback . ', when using autoload the filter must be in one of your plugin dir as "name.php" containig a class or function named "Filter<name>"');
611
-            }
612
-
613
-            $this->filters[] = $callback;
614
-        } else {
615
-            $this->filters[] = $callback;
616
-        }
617
-    }
618
-
619
-    /**
620
-     * Removes a filter.
621
-     *
622
-     * @param mixed $callback callback or filter name if it was autoloaded
623
-     *
624
-     * @return void
625
-     */
626
-    public function removeFilter($callback)
627
-    {
628
-        if (($index = array_search(self::NAMESPACE_PLUGINS_FILTERS. 'Filter' . self::toCamelCase($callback), $this->filters,
629
-                true)) !==
630
-            false) {
631
-            unset($this->filters[$index]);
632
-        } elseif (($index = array_search($callback, $this->filters, true)) !== false) {
633
-            unset($this->filters[$index]);
634
-        } else {
635
-            $class = self::NAMESPACE_PLUGINS_FILTERS . 'Filter' . $callback;
636
-            foreach ($this->filters as $index => $filter) {
637
-                if (is_array($filter) && $filter[0] instanceof $class) {
638
-                    unset($this->filters[$index]);
639
-                    break;
640
-                }
641
-            }
642
-        }
643
-    }
644
-
645
-    /**
646
-     * Adds a resource or overrides a default one.
647
-     *
648
-     * @param string   $name            the resource name
649
-     * @param string   $class           the resource class (which must implement ITemplate)
650
-     * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance
651
-     *                                  used to compile this resource, if none is provided. by default it will produce
652
-     *                                  a Compiler object
653
-     *
654
-     * @return void
655
-     * @throws Exception
656
-     */
657
-    public function addResource($name, $class, $compilerFactory = null)
658
-    {
659
-        if (strlen($name) < 2) {
660
-            throw new Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
661
-        }
662
-
663
-        if (!class_exists($class)) {
664
-            throw new Exception(sprintf('Resource class %s does not exist', $class));
665
-        }
666
-
667
-        $interfaces = class_implements($class);
668
-        if (in_array('Dwoo\ITemplate', $interfaces) === false) {
669
-            throw new Exception('Resource class must implement ITemplate');
670
-        }
671
-
672
-        $this->resources[$name] = array(
673
-            'class'    => $class,
674
-            'compiler' => $compilerFactory
675
-        );
676
-    }
677
-
678
-    /**
679
-     * Removes a custom resource.
680
-     *
681
-     * @param string $name the resource name
682
-     *
683
-     * @return void
684
-     */
685
-    public function removeResource($name)
686
-    {
687
-        unset($this->resources[$name]);
688
-        if ($name === 'file') {
689
-            $this->resources['file'] = array(
690
-                'class'    => 'Dwoo\Template\File',
691
-                'compiler' => null
692
-            );
693
-        }
694
-    }
695
-
696
-    /**
697
-     * Sets the loader object to use to load plugins.
698
-     *
699
-     * @param ILoader $loader loader
700
-     *
701
-     * @return void
702
-     */
703
-    public function setLoader(ILoader $loader)
704
-    {
705
-        $this->loader = $loader;
706
-    }
707
-
708
-    /**
709
-     * Returns the current loader object or a default one if none is currently found.
710
-     *
711
-     * @return ILoader|Loader
712
-     */
713
-    public function getLoader()
714
-    {
715
-        if ($this->loader === null) {
716
-            $this->loader = new Loader($this->getCompileDir());
717
-        }
718
-
719
-        return $this->loader;
720
-    }
721
-
722
-    /**
723
-     * Returns the custom plugins loaded.
724
-     * Used by the ITemplate classes to pass the custom plugins to their ICompiler instance.
725
-     *
726
-     * @return array
727
-     */
728
-    public function getCustomPlugins()
729
-    {
730
-        return $this->plugins;
731
-    }
732
-
733
-    /**
734
-     * Return a specified custom plugin loaded by his name.
735
-     * Used by the compiler, for executing a Closure.
736
-     *
737
-     * @param string $name
738
-     *
739
-     * @return mixed|null
740
-     */
741
-    public function getCustomPlugin($name)
742
-    {
743
-        if (isset($this->plugins[$name])) {
744
-            return $this->plugins[$name]['callback'];
745
-        }
746
-
747
-        return null;
748
-    }
749
-
750
-    /**
751
-     * Returns the cache directory with a trailing DIRECTORY_SEPARATOR.
752
-     *
753
-     * @return string
754
-     */
755
-    public function getCacheDir()
756
-    {
757
-        if ($this->cacheDir === null) {
758
-            $this->setCacheDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR);
759
-        }
760
-
761
-        return $this->cacheDir;
762
-    }
763
-
764
-    /**
765
-     * Sets the cache directory and automatically appends a DIRECTORY_SEPARATOR.
766
-     *
767
-     * @param string $dir the cache directory
768
-     *
769
-     * @return void
770
-     * @throws Exception
771
-     */
772
-    public function setCacheDir($dir)
773
-    {
774
-        $this->cacheDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
775
-        if (!file_exists($this->cacheDir)) {
776
-            mkdir($this->cacheDir, 0777, true);
777
-        }
778
-        if (is_writable($this->cacheDir) === false) {
779
-            throw new Exception('The cache directory must be writable, chmod "' . $this->cacheDir . '" to make it writable');
780
-        }
781
-    }
782
-
783
-    /**
784
-     * Returns the compile directory with a trailing DIRECTORY_SEPARATOR.
785
-     *
786
-     * @return string
787
-     */
788
-    public function getCompileDir()
789
-    {
790
-        if ($this->compileDir === null) {
791
-            $this->setCompileDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'compiled' . DIRECTORY_SEPARATOR);
792
-        }
793
-
794
-        return $this->compileDir;
795
-    }
796
-
797
-    /**
798
-     * Sets the compile directory and automatically appends a DIRECTORY_SEPARATOR.
799
-     *
800
-     * @param string $dir the compile directory
801
-     *
802
-     * @return void
803
-     * @throws Exception
804
-     */
805
-    public function setCompileDir($dir)
806
-    {
807
-        $this->compileDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
808
-        if (!file_exists($this->compileDir)) {
809
-            mkdir($this->compileDir, 0777, true);
810
-        }
811
-        if (is_writable($this->compileDir) === false) {
812
-            throw new Exception('The compile directory must be writable, chmod "' . $this->compileDir . '" to make it writable');
813
-        }
814
-    }
815
-
816
-    /**
817
-     * Returns an array of the template directory with a trailing DIRECTORY_SEPARATOR
818
-     *
819
-     * @return array
820
-     */
821
-    public function getTemplateDir()
822
-    {
823
-        return $this->templateDir;
824
-    }
825
-
826
-    /**
827
-     * sets the template directory and automatically appends a DIRECTORY_SEPARATOR
828
-     * template directory is stored in an array
829
-     *
830
-     * @param string $dir
831
-     *
832
-     * @throws Exception
833
-     */
834
-    public function setTemplateDir($dir)
835
-    {
836
-        $tmpDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
837
-        if (is_dir($tmpDir) === false) {
838
-            throw new Exception('The template directory: "' . $tmpDir . '" does not exists, create the directory or specify an other location !');
839
-        }
840
-        $this->templateDir[] = $tmpDir;
841
-    }
842
-
843
-    /**
844
-     * Returns the default cache time that is used with templates that do not have a cache time set.
845
-     *
846
-     * @return int the duration in seconds
847
-     */
848
-    public function getCacheTime()
849
-    {
850
-        return $this->cacheTime;
851
-    }
852
-
853
-    /**
854
-     * Sets the default cache time to use with templates that do not have a cache time set.
855
-     *
856
-     * @param int $seconds the duration in seconds
857
-     *
858
-     * @return void
859
-     */
860
-    public function setCacheTime($seconds)
861
-    {
862
-        $this->cacheTime = (int)$seconds;
863
-    }
864
-
865
-    /**
866
-     * Returns the character set used by the string manipulation plugins.
867
-     * the charset is automatically lowercased
868
-     *
869
-     * @return string
870
-     */
871
-    public function getCharset()
872
-    {
873
-        return $this->charset;
874
-    }
875
-
876
-    /**
877
-     * Sets the character set used by the string manipulation plugins.
878
-     * the charset will be automatically lowercased
879
-     *
880
-     * @param string $charset the character set
881
-     *
882
-     * @return void
883
-     */
884
-    public function setCharset($charset)
885
-    {
886
-        $this->charset = strtolower((string)$charset);
887
-    }
888
-
889
-    /**
890
-     * Returns the current template being rendered, when applicable, or null.
891
-     *
892
-     * @return ITemplate|null
893
-     */
894
-    public function getTemplate()
895
-    {
896
-        return $this->template;
897
-    }
898
-
899
-    /**
900
-     * Sets the current template being rendered.
901
-     *
902
-     * @param ITemplate $tpl template object
903
-     *
904
-     * @return void
905
-     */
906
-    public function setTemplate(ITemplate $tpl)
907
-    {
908
-        $this->template = $tpl;
909
-    }
910
-
911
-    /**
912
-     * Sets the default compiler factory function for the given resource name.
913
-     * a compiler factory must return a ICompiler object pre-configured to fit your needs
914
-     *
915
-     * @param string   $resourceName    the resource name (i.e. file, string)
916
-     * @param callback $compilerFactory the compiler factory callback
917
-     *
918
-     * @return void
919
-     */
920
-    public function setDefaultCompilerFactory($resourceName, $compilerFactory)
921
-    {
922
-        $this->resources[$resourceName]['compiler'] = $compilerFactory;
923
-    }
924
-
925
-    /**
926
-     * Returns the default compiler factory function for the given resource name.
927
-     *
928
-     * @param string $resourceName the resource name
929
-     *
930
-     * @return callback the compiler factory callback
931
-     */
932
-    public function getDefaultCompilerFactory($resourceName)
933
-    {
934
-        return $this->resources[$resourceName]['compiler'];
935
-    }
936
-
937
-    /**
938
-     * Sets the security policy object to enforce some php security settings.
939
-     * use this if untrusted persons can modify templates
940
-     *
941
-     * @param SecurityPolicy $policy the security policy object
942
-     *
943
-     * @return void
944
-     */
945
-    public function setSecurityPolicy(SecurityPolicy $policy = null)
946
-    {
947
-        $this->securityPolicy = $policy;
948
-    }
949
-
950
-    /**
951
-     * Returns the current security policy object or null by default.
952
-     *
953
-     * @return SecurityPolicy|null the security policy object if any
954
-     */
955
-    public function getSecurityPolicy()
956
-    {
957
-        return $this->securityPolicy;
958
-    }
959
-
960
-    /**
961
-     * Sets the object that must be used as a plugin proxy when plugin can't be found
962
-     * by dwoo's loader.
963
-     *
964
-     * @param IPluginProxy $pluginProxy the proxy object
965
-     *
966
-     * @return void
967
-     */
968
-    public function setPluginProxy(IPluginProxy $pluginProxy)
969
-    {
970
-        $this->pluginProxy = $pluginProxy;
971
-    }
972
-
973
-    /**
974
-     * Returns the current plugin proxy object or null by default.
975
-     *
976
-     * @return IPluginProxy
977
-     */
978
-    public function getPluginProxy()
979
-    {
980
-        return $this->pluginProxy;
981
-    }
982
-
983
-    /**
984
-     * Checks whether the given template is cached or not.
985
-     *
986
-     * @param ITemplate $tpl the template object
987
-     *
988
-     * @return bool
989
-     */
990
-    public function isCached(ITemplate $tpl)
991
-    {
992
-        return is_string($tpl->getCachedTemplate($this));
993
-    }
994
-
995
-    /**
996
-     * Clear templates inside the compiled directory.
997
-     *
998
-     * @return int
999
-     */
1000
-    public function clearCompiled()
1001
-    {
1002
-        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCompileDir()), \RecursiveIteratorIterator::SELF_FIRST);
1003
-        $count    = 0;
1004
-        foreach ($iterator as $file) {
1005
-            if ($file->isFile()) {
1006
-                $count += unlink($file->__toString()) ? 1 : 0;
1007
-            }
1008
-        }
1009
-
1010
-        return $count;
1011
-    }
1012
-
1013
-    /**
1014
-     * Clears the cached templates if they are older than the given time.
1015
-     *
1016
-     * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
1017
-     *
1018
-     * @return int the amount of templates cleared
1019
-     */
1020
-    public function clearCache($olderThan = - 1)
1021
-    {
1022
-        $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCacheDir()), \RecursiveIteratorIterator::SELF_FIRST);
1023
-        $expired  = time() - $olderThan;
1024
-        $count    = 0;
1025
-        foreach ($iterator as $file) {
1026
-            if ($file->isFile() && $file->getCTime() < $expired) {
1027
-                $count += unlink((string)$file) ? 1 : 0;
1028
-            }
1029
-        }
1030
-
1031
-        return $count;
1032
-    }
1033
-
1034
-    /**
1035
-     * Fetches a template object of the given resource.
1036
-     *
1037
-     * @param string    $resourceName   the resource name (i.e. file, string)
1038
-     * @param string    $resourceId     the resource identifier (i.e. file path)
1039
-     * @param int       $cacheTime      the cache time setting for this resource
1040
-     * @param string    $cacheId        the unique cache identifier
1041
-     * @param string    $compileId      the unique compiler identifier
1042
-     * @param ITemplate $parentTemplate the parent template
1043
-     *
1044
-     * @return ITemplate
1045
-     * @throws Exception
1046
-     */
1047
-    public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, ITemplate $parentTemplate = null)
1048
-    {
1049
-        if (isset($this->resources[$resourceName])) {
1050
-            /**
1051
-             * Interface ITemplate
1052
-             *
1053
-             * @var ITemplate $class
1054
-             */
1055
-            $class = $this->resources[$resourceName]['class'];
1056
-
1057
-            return $class::templateFactory($this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
1058
-        }
1059
-
1060
-        throw new Exception('Unknown resource type : ' . $resourceName);
1061
-    }
1062
-
1063
-    /**
1064
-     * Checks if the input is an array or arrayaccess object, optionally it can also check if it's
1065
-     * empty.
1066
-     *
1067
-     * @param mixed $value        the variable to check
1068
-     * @param bool  $checkIsEmpty if true, the function will also check if the array|arrayaccess is empty,
1069
-     *                            and return true only if it's not empty
1070
-     *
1071
-     * @return int|bool true if it's an array|arrayaccess (or the item count if $checkIsEmpty is true) or false if it's
1072
-     *                  not an array|arrayaccess (or 0 if $checkIsEmpty is true)
1073
-     */
1074
-    public function isArray($value, $checkIsEmpty = false)
1075
-    {
1076
-        if (is_array($value) === true || $value instanceof ArrayAccess) {
1077
-            if ($checkIsEmpty === false) {
1078
-                return true;
1079
-            }
1080
-
1081
-            return $this->count($value);
1082
-        }
1083
-
1084
-        return false;
1085
-    }
1086
-
1087
-    /**
1088
-     * Checks if the input is an array or a traversable object, optionally it can also check if it's
1089
-     * empty.
1090
-     *
1091
-     * @param mixed $value        the variable to check
1092
-     * @param bool  $checkIsEmpty if true, the function will also check if the array|traversable is empty,
1093
-     *                            and return true only if it's not empty
1094
-     *
1095
-     * @return int|bool true if it's an array|traversable (or the item count if $checkIsEmpty is true) or false if it's
1096
-     *                  not an array|traversable (or 0 if $checkIsEmpty is true)
1097
-     */
1098
-    public function isTraversable($value, $checkIsEmpty = false)
1099
-    {
1100
-        if (is_array($value) === true) {
1101
-            if ($checkIsEmpty === false) {
1102
-                return true;
1103
-            } else {
1104
-                return count($value) > 0;
1105
-            }
1106
-        } elseif ($value instanceof Traversable) {
1107
-            if ($checkIsEmpty === false) {
1108
-                return true;
1109
-            } else {
1110
-                return $this->count($value);
1111
-            }
1112
-        }
1113
-
1114
-        return false;
1115
-    }
1116
-
1117
-    /**
1118
-     * Counts an array or arrayaccess/traversable object.
1119
-     *
1120
-     * @param mixed $value the value to count
1121
-     *
1122
-     * @return int|bool the count for arrays and objects that implement countable, true for other objects that don't,
1123
-     *                  and 0 for empty elements
1124
-     */
1125
-    public function count($value)
1126
-    {
1127
-        if (is_array($value) === true || $value instanceof Countable) {
1128
-            return count($value);
1129
-        } elseif ($value instanceof ArrayAccess) {
1130
-            if ($value->offsetExists(0)) {
1131
-                return true;
1132
-            }
1133
-        } elseif ($value instanceof Iterator) {
1134
-            $value->rewind();
1135
-            if ($value->valid()) {
1136
-                return true;
1137
-            }
1138
-        } elseif ($value instanceof Traversable) {
1139
-            foreach ($value as $dummy) {
1140
-                return true;
1141
-            }
1142
-        }
1143
-
1144
-        return 0;
1145
-    }
1146
-
1147
-    /**
1148
-     * Triggers a dwoo error.
1149
-     *
1150
-     * @param string $message the error message
1151
-     * @param int    $level   the error level, one of the PHP's E_* constants
1152
-     *
1153
-     * @return void
1154
-     */
1155
-    public function triggerError($message, $level = E_USER_NOTICE)
1156
-    {
1157
-        if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
1158
-            $tplIdentifier = $this->template->getResourceName();
1159
-        }
1160
-        trigger_error('Dwoo error (in ' . $tplIdentifier . ') : ' . $message, $level);
1161
-    }
1162
-
1163
-    /**
1164
-     * Adds a block to the block stack.
1165
-     *
1166
-     * @param string $blockName the block name (without `Plugin` prefix)
1167
-     * @param array  $args      the arguments to be passed to the block's init() function
1168
-     *
1169
-     * @return BlockPlugin the newly created block
1170
-     */
1171
-    public function addStack($blockName, array $args = array())
1172
-    {
1173
-        if (isset($this->plugins[$blockName])) {
1174
-            $class = $this->plugins[$blockName]['class'];
1175
-        } else {
1176
-            $class = current(array_filter([
1177
-                'Plugin' . self::toCamelCase($blockName),
1178
-                self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . self::toCamelCase($blockName)
1179
-            ], 'class_exists'));
1180
-        }
1181
-
1182
-        if ($this->curBlock !== null) {
1183
-            $this->curBlock->buffer(ob_get_contents());
1184
-            ob_clean();
1185
-        } else {
1186
-            $this->buffer .= ob_get_contents();
1187
-            ob_clean();
1188
-        }
1189
-
1190
-        $block = new $class($this);
1191
-
1192
-        call_user_func_array(array($block, 'init'), $args);
1193
-
1194
-        $this->stack[] = $this->curBlock = $block;
1195
-
1196
-        return $block;
1197
-    }
1198
-
1199
-    /**
1200
-     * Removes the plugin at the top of the block stack.
1201
-     * Calls the block buffer() function, followed by a call to end() and finally a call to process()
1202
-     *
1203
-     * @return void
1204
-     */
1205
-    public function delStack()
1206
-    {
1207
-        $args = func_get_args();
1208
-
1209
-        $this->curBlock->buffer(ob_get_contents());
1210
-        ob_clean();
1211
-
1212
-        call_user_func_array(array($this->curBlock, 'end'), $args);
1213
-
1214
-        $tmp = array_pop($this->stack);
1215
-
1216
-        if (count($this->stack) > 0) {
1217
-            $this->curBlock = end($this->stack);
1218
-            $this->curBlock->buffer($tmp->process());
1219
-        } else {
1220
-            if ($this->buffer !== '') {
1221
-                echo $this->buffer;
1222
-                $this->buffer = '';
1223
-            }
1224
-            $this->curBlock = null;
1225
-            echo $tmp->process();
1226
-        }
1227
-
1228
-        unset($tmp);
1229
-    }
1230
-
1231
-    /**
1232
-     * Returns the parent block of the given block.
1233
-     *
1234
-     * @param BlockPlugin $block the block class plugin
1235
-     *
1236
-     * @return BlockPlugin|false if the given block isn't in the stack
1237
-     */
1238
-    public function getParentBlock(BlockPlugin $block)
1239
-    {
1240
-        $index = array_search($block, $this->stack, true);
1241
-        if ($index !== false && $index > 0) {
1242
-            return $this->stack[$index - 1];
1243
-        }
1244
-
1245
-        return false;
1246
-    }
1247
-
1248
-    /**
1249
-     * Finds the closest block of the given type, starting at the top of the stack.
1250
-     *
1251
-     * @param string $type the type of plugin you want to find
1252
-     *
1253
-     * @return BlockPlugin|false if no plugin of such type is in the stack
1254
-     */
1255
-    public function findBlock($type)
1256
-    {
1257
-        if (isset($this->plugins[$type])) {
1258
-            $type = $this->plugins[$type]['class'];
1259
-        } else {
1260
-            $type = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin_' . str_replace(self::NAMESPACE_PLUGINS_BLOCKS.'Plugin',
1261
-                    '', $type);
1262
-        }
1263
-
1264
-        $keys = array_keys($this->stack);
1265
-        while (($key = array_pop($keys)) !== false) {
1266
-            if ($this->stack[$key] instanceof $type) {
1267
-                return $this->stack[$key];
1268
-            }
1269
-        }
1270
-
1271
-        return false;
1272
-    }
1273
-
1274
-    /**
1275
-     * Returns a Plugin of the given class.
1276
-     * this is so a single instance of every class plugin is created at each template run,
1277
-     * allowing class plugins to have "per-template-run" static variables
1278
-     *
1279
-     * @param string $class the class name
1280
-     *
1281
-     * @return mixed an object of the given class
1282
-     */
1283
-    public function getObjectPlugin($class)
1284
-    {
1285
-        if (isset($this->runtimePlugins[$class])) {
1286
-            return $this->runtimePlugins[$class];
1287
-        }
1288
-
1289
-        return $this->runtimePlugins[$class] = new $class($this);
1290
-    }
1291
-
1292
-    /**
1293
-     * Calls the process() method of the given class-plugin name.
1294
-     *
1295
-     * @param string $plugName the class plugin name (without `Plugin` prefix)
1296
-     * @param array  $params   an array of parameters to send to the process() method
1297
-     *
1298
-     * @return string the process() return value
1299
-     */
1300
-    public function classCall($plugName, array $params = array())
1301
-    {
1302
-        $class  = self::toCamelCase($plugName);
1303
-        $plugin = $this->getObjectPlugin($class);
1304
-
1305
-        return call_user_func_array(array($plugin, 'process'), $params);
1306
-    }
1307
-
1308
-    /**
1309
-     * Calls a php function.
1310
-     *
1311
-     * @param string $callback the function to call
1312
-     * @param array  $params   an array of parameters to send to the function
1313
-     *
1314
-     * @return mixed the return value of the called function
1315
-     */
1316
-    public function arrayMap($callback, array $params)
1317
-    {
1318
-        if ($params[0] === $this) {
1319
-            $addThis = true;
1320
-            array_shift($params);
1321
-        }
1322
-        if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) {
1323
-            if (empty($params[0])) {
1324
-                return $params[0];
1325
-            }
1326
-
1327
-            // array map
1328
-            $out = array();
1329
-            $cnt = count($params);
1330
-
1331
-            if (isset($addThis)) {
1332
-                array_unshift($params, $this);
1333
-                $items = $params[1];
1334
-                $keys  = array_keys($items);
1335
-
1336
-                if (is_string($callback) === false) {
1337
-                    while (($i = array_shift($keys)) !== null) {
1338
-                        $out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1339
-                    }
1340
-                } elseif ($cnt === 1) {
1341
-                    while (($i = array_shift($keys)) !== null) {
1342
-                        $out[] = $callback($this, $items[$i]);
1343
-                    }
1344
-                } elseif ($cnt === 2) {
1345
-                    while (($i = array_shift($keys)) !== null) {
1346
-                        $out[] = $callback($this, $items[$i], $params[2]);
1347
-                    }
1348
-                } elseif ($cnt === 3) {
1349
-                    while (($i = array_shift($keys)) !== null) {
1350
-                        $out[] = $callback($this, $items[$i], $params[2], $params[3]);
1351
-                    }
1352
-                } else {
1353
-                    while (($i = array_shift($keys)) !== null) {
1354
-                        $out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1355
-                    }
1356
-                }
1357
-            } else {
1358
-                $items = $params[0];
1359
-                $keys  = array_keys($items);
1360
-
1361
-                if (is_string($callback) === false) {
1362
-                    while (($i = array_shift($keys)) !== null) {
1363
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1364
-                    }
1365
-                } elseif ($cnt === 1) {
1366
-                    while (($i = array_shift($keys)) !== null) {
1367
-                        $out[] = $callback($items[$i]);
1368
-                    }
1369
-                } elseif ($cnt === 2) {
1370
-                    while (($i = array_shift($keys)) !== null) {
1371
-                        $out[] = $callback($items[$i], $params[1]);
1372
-                    }
1373
-                } elseif ($cnt === 3) {
1374
-                    while (($i = array_shift($keys)) !== null) {
1375
-                        $out[] = $callback($items[$i], $params[1], $params[2]);
1376
-                    }
1377
-                } elseif ($cnt === 4) {
1378
-                    while (($i = array_shift($keys)) !== null) {
1379
-                        $out[] = $callback($items[$i], $params[1], $params[2], $params[3]);
1380
-                    }
1381
-                } else {
1382
-                    while (($i = array_shift($keys)) !== null) {
1383
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1384
-                    }
1385
-                }
1386
-            }
1387
-
1388
-            return $out;
1389
-        } else {
1390
-            return $params[0];
1391
-        }
1392
-    }
1393
-
1394
-    /**
1395
-     * Reads a variable into the given data array.
1396
-     *
1397
-     * @param string $varstr   the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1398
-     * @param mixed  $data     the data array or object to read from
1399
-     * @param bool   $safeRead if true, the function will check whether the index exists to prevent any notices from
1400
-     *                         being output
1401
-     *
1402
-     * @return mixed
1403
-     */
1404
-    public function readVarInto($varstr, $data, $safeRead = false)
1405
-    {
1406
-        if ($data === null) {
1407
-            return null;
1408
-        }
1409
-
1410
-        if (is_array($varstr) === false) {
1411
-            preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1412
-        } else {
1413
-            $m = $varstr;
1414
-        }
1415
-        unset($varstr);
1416
-
1417
-        foreach ($m[1] as $k => $sep) {
1418
-            if ($sep === '.' || $sep === '[' || $sep === '') {
1419
-                // strip enclosing quotes if present
1420
-                $m[2][$k] = preg_replace('#^(["\']?)(.*?)\1$#', '$2', $m[2][$k]);
1421
-
1422
-                if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) {
1423
-                    $data = $data[$m[2][$k]];
1424
-                } else {
1425
-                    return null;
1426
-                }
1427
-            } else {
1428
-                if (is_object($data) && ($safeRead === false || isset($data->{$m[2][$k]}))) {
1429
-                    $data = $data->{$m[2][$k]};
1430
-                } else {
1431
-                    return null;
1432
-                }
1433
-            }
1434
-        }
1435
-
1436
-        return $data;
1437
-    }
1438
-
1439
-    /**
1440
-     * Reads a variable into the parent scope.
1441
-     *
1442
-     * @param int    $parentLevels the amount of parent levels to go from the current scope
1443
-     * @param string $varstr       the variable string, using dwoo variable syntax (i.e.
1444
-     *                             "var.subvar[subsubvar]->property")
1445
-     *
1446
-     * @return mixed
1447
-     */
1448
-    public function readParentVar($parentLevels, $varstr = null)
1449
-    {
1450
-        $tree = $this->scopeTree;
1451
-        $cur  = $this->data;
1452
-
1453
-        while ($parentLevels -- !== 0) {
1454
-            array_pop($tree);
1455
-        }
1456
-
1457
-        while (($i = array_shift($tree)) !== null) {
1458
-            if (is_object($cur)) {
1459
-                $cur = $cur->{$i};
1460
-            } else {
1461
-                $cur = $cur[$i];
1462
-            }
1463
-        }
1464
-
1465
-        if ($varstr !== null) {
1466
-            return $this->readVarInto($varstr, $cur);
1467
-        } else {
1468
-            return $cur;
1469
-        }
1470
-    }
1471
-
1472
-    /**
1473
-     * Reads a variable into the current scope.
1474
-     *
1475
-     * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1476
-     *
1477
-     * @return mixed
1478
-     */
1479
-    public function readVar($varstr)
1480
-    {
1481
-        if (is_array($varstr) === true) {
1482
-            $m = $varstr;
1483
-            unset($varstr);
1484
-        } else {
1485
-            if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) {
1486
-                if ($varstr === 'dwoo') {
1487
-                    return $this->getGlobals();
1488
-                } elseif ($varstr === '__' || $varstr === '_root') {
1489
-                    return $this->data;
1490
-                } elseif ($varstr === '_' || $varstr === '_parent') {
1491
-                    $varstr = '.' . $varstr;
1492
-                    $tree   = $this->scopeTree;
1493
-                    $cur    = $this->data;
1494
-                    array_pop($tree);
1495
-
1496
-                    while (($i = array_shift($tree)) !== null) {
1497
-                        if (is_object($cur)) {
1498
-                            $cur = $cur->{$i};
1499
-                        } else {
1500
-                            $cur = $cur[$i];
1501
-                        }
1502
-                    }
1503
-
1504
-                    return $cur;
1505
-                }
1506
-
1507
-                $cur = $this->scope;
1508
-
1509
-                if (isset($cur[$varstr])) {
1510
-                    return $cur[$varstr];
1511
-                } else {
1512
-                    return null;
1513
-                }
1514
-            }
1515
-
1516
-            if (substr($varstr, 0, 1) === '.') {
1517
-                $varstr = 'dwoo' . $varstr;
1518
-            }
1519
-
1520
-            preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1521
-        }
1522
-
1523
-        $i = $m[2][0];
1524
-        if ($i === 'dwoo') {
1525
-            $cur = $this->getGlobals();
1526
-            array_shift($m[2]);
1527
-            array_shift($m[1]);
1528
-            switch ($m[2][0]) {
1529
-            case 'get':
1530
-                $cur = $_GET;
1531
-                break;
1532
-            case 'post':
1533
-                $cur = $_POST;
1534
-                break;
1535
-            case 'session':
1536
-                $cur = $_SESSION;
1537
-                break;
1538
-            case 'cookies':
1539
-            case 'cookie':
1540
-                $cur = $_COOKIE;
1541
-                break;
1542
-            case 'server':
1543
-                $cur = $_SERVER;
1544
-                break;
1545
-            case 'env':
1546
-                $cur = $_ENV;
1547
-                break;
1548
-            case 'request':
1549
-                $cur = $_REQUEST;
1550
-                break;
1551
-            case 'const':
1552
-                array_shift($m[2]);
1553
-                if (defined($m[2][0])) {
1554
-                    return constant($m[2][0]);
1555
-                } else {
1556
-                    return null;
1557
-                }
1558
-            }
1559
-            if ($cur !== $this->getGlobals()) {
1560
-                array_shift($m[2]);
1561
-                array_shift($m[1]);
1562
-            }
1563
-        } elseif ($i === '__' || $i === '_root') {
1564
-            $cur = $this->data;
1565
-            array_shift($m[2]);
1566
-            array_shift($m[1]);
1567
-        } elseif ($i === '_' || $i === '_parent') {
1568
-            $tree = $this->scopeTree;
1569
-            $cur  = $this->data;
1570
-
1571
-            while (true) {
1572
-                array_pop($tree);
1573
-                array_shift($m[2]);
1574
-                array_shift($m[1]);
1575
-                if (current($m[2]) === '_' || current($m[2]) === '_parent') {
1576
-                    continue;
1577
-                }
1578
-
1579
-                while (($i = array_shift($tree)) !== null) {
1580
-                    if (is_object($cur)) {
1581
-                        $cur = $cur->{$i};
1582
-                    } else {
1583
-                        $cur = $cur[$i];
1584
-                    }
1585
-                }
1586
-                break;
1587
-            }
1588
-        } else {
1589
-            $cur = $this->scope;
1590
-        }
1591
-
1592
-        foreach ($m[1] as $k => $sep) {
1593
-            if ($sep === '.' || $sep === '[' || $sep === '') {
1594
-                if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) {
1595
-                    $cur = $cur[$m[2][$k]];
1596
-                } else {
1597
-                    return null;
1598
-                }
1599
-            } elseif ($sep === '->') {
1600
-                if (is_object($cur)) {
1601
-                    $cur = $cur->{$m[2][$k]};
1602
-                } else {
1603
-                    return null;
1604
-                }
1605
-            } else {
1606
-                return null;
1607
-            }
1608
-        }
1609
-
1610
-        return $cur;
1611
-    }
1612
-
1613
-    /**
1614
-     * Assign the value to the given variable.
1615
-     *
1616
-     * @param mixed  $value the value to assign
1617
-     * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1618
-     *
1619
-     * @return bool true if assigned correctly or false if a problem occured while parsing the var string
1620
-     */
1621
-    public function assignInScope($value, $scope)
1622
-    {
1623
-        if (!is_string($scope)) {
1624
-            $this->triggerError('Assignments must be done into strings, (' . gettype($scope) . ') ' . var_export($scope, true) . ' given', E_USER_ERROR);
1625
-        }
1626
-        if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1627
-            $this->scope[$scope] = $value;
1628
-        } else {
1629
-            // TODO handle _root/_parent scopes ?
1630
-            preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m);
1631
-
1632
-            $cur  = &$this->scope;
1633
-            $last = array(
1634
-                array_pop($m[1]),
1635
-                array_pop($m[2])
1636
-            );
1637
-
1638
-            foreach ($m[1] as $k => $sep) {
1639
-                if ($sep === '.' || $sep === '[' || $sep === '') {
1640
-                    if (is_array($cur) === false) {
1641
-                        $cur = array();
1642
-                    }
1643
-                    $cur = &$cur[$m[2][$k]];
1644
-                } elseif ($sep === '->') {
1645
-                    if (is_object($cur) === false) {
1646
-                        $cur = new stdClass();
1647
-                    }
1648
-                    $cur = &$cur->{$m[2][$k]};
1649
-                } else {
1650
-                    return false;
1651
-                }
1652
-            }
1653
-
1654
-            if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') {
1655
-                if (is_array($cur) === false) {
1656
-                    $cur = array();
1657
-                }
1658
-                $cur[$last[1]] = $value;
1659
-            } elseif ($last[0] === '->') {
1660
-                if (is_object($cur) === false) {
1661
-                    $cur = new stdClass();
1662
-                }
1663
-                $cur->{$last[1]} = $value;
1664
-            } else {
1665
-                return false;
1666
-            }
1667
-        }
1668
-    }
1669
-
1670
-    /**
1671
-     * Sets the scope to the given scope string or array.
1672
-     *
1673
-     * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1674
-     * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1675
-     *
1676
-     * @return array the current scope tree
1677
-     */
1678
-    public function setScope($scope, $absolute = false)
1679
-    {
1680
-        $old = $this->scopeTree;
1681
-
1682
-        if (is_string($scope) === true) {
1683
-            $scope = explode('.', $scope);
1684
-        }
1685
-
1686
-        if ($absolute === true) {
1687
-            $this->scope     = &$this->data;
1688
-            $this->scopeTree = array();
1689
-        }
1690
-
1691
-        while (($bit = array_shift($scope)) !== null) {
1692
-            if ($bit === '_' || $bit === '_parent') {
1693
-                array_pop($this->scopeTree);
1694
-                $this->scope = &$this->data;
1695
-                $cnt         = count($this->scopeTree);
1696
-                for ($i = 0; $i < $cnt; ++ $i) {
1697
-                    $this->scope = &$this->scope[$this->scopeTree[$i]];
1698
-                }
1699
-            } elseif ($bit === '__' || $bit === '_root') {
1700
-                $this->scope     = &$this->data;
1701
-                $this->scopeTree = array();
1702
-            } elseif (isset($this->scope[$bit])) {
1703
-                if ($this->scope instanceof ArrayAccess) {
1704
-                    $tmp         = $this->scope[$bit];
1705
-                    $this->scope = &$tmp;
1706
-                } else {
1707
-                    $this->scope = &$this->scope[$bit];
1708
-                }
1709
-                $this->scopeTree[] = $bit;
1710
-            } else {
1711
-                unset($this->scope);
1712
-                $this->scope = null;
1713
-            }
1714
-        }
1715
-
1716
-        return $old;
1717
-    }
1718
-
1719
-    /**
1720
-     * Returns the entire data array.
1721
-     *
1722
-     * @return array
1723
-     */
1724
-    public function getData()
1725
-    {
1726
-        return $this->data;
1727
-    }
1728
-
1729
-    /**
1730
-     * Sets a return value for the currently running template.
1731
-     *
1732
-     * @param string $name  var name
1733
-     * @param mixed  $value var value
1734
-     *
1735
-     * @return void
1736
-     */
1737
-    public function setReturnValue($name, $value)
1738
-    {
1739
-        $this->returnData[$name] = $value;
1740
-    }
1741
-
1742
-    /**
1743
-     * Retrieves the return values set by the template.
1744
-     *
1745
-     * @return array
1746
-     */
1747
-    public function getReturnValues()
1748
-    {
1749
-        return $this->returnData;
1750
-    }
1751
-
1752
-    /**
1753
-     * Returns a reference to the current scope.
1754
-     *
1755
-     * @return mixed
1756
-     */
1757
-    public function &getScope()
1758
-    {
1759
-        return $this->scope;
1760
-    }
1761
-
1762
-    /**
1763
-     * Redirects all calls to unexisting to plugin proxy.
1764
-     *
1765
-     * @param string $method the method name
1766
-     * @param array  $args   array of arguments
1767
-     *
1768
-     * @return mixed
1769
-     * @throws Exception
1770
-     */
1771
-    public function __call($method, $args)
1772
-    {
1773
-        $proxy = $this->getPluginProxy();
1774
-        if (!$proxy) {
1775
-            throw new Exception('Call to undefined method ' . __CLASS__ . '::' . $method . '()');
1776
-        }
1777
-
1778
-        return call_user_func_array($proxy->getCallback($method), $args);
1779
-    }
1780
-
1781
-    /**
1782
-     * Convert plugin name from `auto_escape` to `AutoEscape`.
1783
-     * @param string $input
1784
-     * @param string $separator
1785
-     *
1786
-     * @return mixed
1787
-     */
1788
-    public static function toCamelCase($input, $separator = '_')
1789
-    {
1790
-        return join(array_map('ucfirst', explode($separator, $input)));
1791
-
1792
-        // TODO >= PHP5.4.32
1793
-        //return str_replace($separator, '', ucwords($input, $separator));
1794
-    }
47
+	/**
48
+	 * Current version number.
49
+	 *
50
+	 * @var string
51
+	 */
52
+	const VERSION = '1.3.6';
53
+
54
+	/**
55
+	 * Unique number of this dwoo release, based on version number.
56
+	 * this can be used by templates classes to check whether the compiled template
57
+	 * has been compiled before this release or not, so that old templates are
58
+	 * recompiled automatically when Dwoo is updated
59
+	 */
60
+	const RELEASE_TAG = 136;
61
+
62
+	/**
63
+	 * Constants that represents all plugin types
64
+	 * these are bitwise-operation-safe values to allow multiple types
65
+	 * on a single plugin
66
+	 *
67
+	 * @var int
68
+	 */
69
+	const CLASS_PLUGIN      = 1;
70
+	const FUNC_PLUGIN       = 2;
71
+	const NATIVE_PLUGIN     = 4;
72
+	const BLOCK_PLUGIN      = 8;
73
+	const COMPILABLE_PLUGIN = 16;
74
+	const CUSTOM_PLUGIN     = 32;
75
+	const SMARTY_MODIFIER   = 64;
76
+	const SMARTY_BLOCK      = 128;
77
+	const SMARTY_FUNCTION   = 256;
78
+	const PROXY_PLUGIN      = 512;
79
+	const TEMPLATE_PLUGIN   = 1024;
80
+
81
+	/**
82
+	 * Constant to default namespaces of builtin plugins
83
+	 *
84
+	 * @var string
85
+	 */
86
+	const NAMESPACE_PLUGINS_BLOCKS     = 'Dwoo\Plugins\Blocks\\';
87
+	const NAMESPACE_PLUGINS_FILTERS    = 'Dwoo\Plugins\Filters\\';
88
+	const NAMESPACE_PLUGINS_FUNCTIONS  = 'Dwoo\Plugins\Functions\\';
89
+	const NAMESPACE_PLUGINS_HELPERS    = 'Dwoo\Plugins\Helpers\\';
90
+	const NAMESPACE_PLUGINS_PROCESSORS = 'Dwoo\Plugins\Processors\\';
91
+
92
+	/**
93
+	 * Character set of the template, used by string manipulation plugins.
94
+	 * it must be lowercase, but setCharset() will take care of that
95
+	 *
96
+	 * @see setCharset
97
+	 * @see getCharset
98
+	 * @var string
99
+	 */
100
+	protected $charset = 'UTF-8';
101
+
102
+	/**
103
+	 * Global variables that are accessible through $dwoo.* in the templates.
104
+	 * default values include:
105
+	 * $dwoo.version - current version number
106
+	 * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
107
+	 * $dwoo.now - the current time
108
+	 * $dwoo.template - the current template filename
109
+	 * $dwoo.charset - the character set used by the template
110
+	 * on top of that, foreach and other plugins can store special values in there,
111
+	 * see their documentation for more details.
112
+	 *
113
+	 * @var array
114
+	 */
115
+	protected $globals = array();
116
+
117
+	/**
118
+	 * Directory where the compiled templates are stored.
119
+	 * defaults to DWOO_COMPILEDIR (= dwoo_dir/compiled by default)
120
+	 *
121
+	 * @var string
122
+	 */
123
+	protected $compileDir;
124
+
125
+	/**
126
+	 * Directory where the cached templates are stored.
127
+	 * defaults to DWOO_CACHEDIR (= dwoo_dir/cache by default)
128
+	 *
129
+	 * @var string
130
+	 */
131
+	protected $cacheDir;
132
+
133
+	/**
134
+	 * Directory where the template files are stored
135
+	 *
136
+	 * @var array
137
+	 */
138
+	protected $templateDir = array();
139
+
140
+	/**
141
+	 * Defines how long (in seconds) the cached files must remain valid.
142
+	 * can be overridden on a per-template basis
143
+	 * -1 = never delete
144
+	 * 0 = disabled
145
+	 * >0 = duration in seconds
146
+	 *
147
+	 * @var int
148
+	 */
149
+	protected $cacheTime = 0;
150
+
151
+	/**
152
+	 * Security policy object.
153
+	 *
154
+	 * @var SecurityPolicy
155
+	 */
156
+	protected $securityPolicy = null;
157
+
158
+	/**
159
+	 * Stores the custom plugins callbacks.
160
+	 *
161
+	 * @see addPlugin
162
+	 * @see removePlugin
163
+	 * @var array
164
+	 */
165
+	protected $plugins = array();
166
+
167
+	/**
168
+	 * Stores the filter callbacks.
169
+	 *
170
+	 * @see addFilter
171
+	 * @see removeFilter
172
+	 * @var array
173
+	 */
174
+	protected $filters = array();
175
+
176
+	/**
177
+	 * Stores the resource types and associated
178
+	 * classes / compiler classes.
179
+	 *
180
+	 * @var array
181
+	 */
182
+	protected $resources = array(
183
+		'file'   => array(
184
+			'class'    => 'Dwoo\Template\File',
185
+			'compiler' => null,
186
+		),
187
+		'string' => array(
188
+			'class'    => 'Dwoo\Template\Str',
189
+			'compiler' => null,
190
+		),
191
+	);
192
+
193
+	/**
194
+	 * The dwoo loader object used to load plugins by this dwoo instance.
195
+	 *
196
+	 * @var ILoader
197
+	 */
198
+	protected $loader = null;
199
+
200
+	/**
201
+	 * Currently rendered template, set to null when not-rendering.
202
+	 *
203
+	 * @var ITemplate
204
+	 */
205
+	protected $template = null;
206
+
207
+	/**
208
+	 * Stores the instances of the class plugins during template runtime.
209
+	 *
210
+	 * @var array
211
+	 */
212
+	protected $runtimePlugins = array();
213
+
214
+	/**
215
+	 * Stores the returned values during template runtime.
216
+	 *
217
+	 * @var array
218
+	 */
219
+	protected $returnData = array();
220
+
221
+	/**
222
+	 * Stores the data during template runtime.
223
+	 *
224
+	 * @var array
225
+	 */
226
+	protected $data = array();
227
+
228
+	/**
229
+	 * Stores the current scope during template runtime.
230
+	 * this should ideally not be accessed directly from outside template code
231
+	 *
232
+	 * @var mixed
233
+	 */
234
+	public $scope;
235
+
236
+	/**
237
+	 * Stores the scope tree during template runtime.
238
+	 *
239
+	 * @var array
240
+	 */
241
+	protected $scopeTree = array();
242
+
243
+	/**
244
+	 * Stores the block plugins stack during template runtime.
245
+	 *
246
+	 * @var array
247
+	 */
248
+	protected $stack = array();
249
+
250
+	/**
251
+	 * Stores the current block plugin at the top of the stack during template runtime.
252
+	 *
253
+	 * @var BlockPlugin
254
+	 */
255
+	protected $curBlock;
256
+
257
+	/**
258
+	 * Stores the output buffer during template runtime.
259
+	 *
260
+	 * @var string
261
+	 */
262
+	protected $buffer;
263
+
264
+	/**
265
+	 * Stores plugin proxy.
266
+	 *
267
+	 * @var IPluginProxy
268
+	 */
269
+	protected $pluginProxy;
270
+
271
+	/**
272
+	 * Constructor, sets the cache and compile dir to the default values if not provided.
273
+	 *
274
+	 * @param string $compileDir path to the compiled directory, defaults to lib/compiled
275
+	 * @param string $cacheDir   path to the cache directory, defaults to lib/cache
276
+	 */
277
+	public function __construct($compileDir = null, $cacheDir = null)
278
+	{
279
+		if ($compileDir !== null) {
280
+			$this->setCompileDir($compileDir);
281
+		}
282
+		if ($cacheDir !== null) {
283
+			$this->setCacheDir($cacheDir);
284
+		}
285
+		$this->initGlobals();
286
+	}
287
+
288
+	/**
289
+	 * Resets some runtime variables to allow a cloned object to be used to render sub-templates.
290
+	 *
291
+	 * @return void
292
+	 */
293
+	public function __clone()
294
+	{
295
+		$this->template = null;
296
+		unset($this->data);
297
+		unset($this->returnData);
298
+	}
299
+
300
+	/**
301
+	 * Returns the given template rendered using the provided data and optional compiler.
302
+	 *
303
+	 * @param mixed     $_tpl      template, can either be a ITemplate object (i.e. TemplateFile), a
304
+	 *                             valid path to a template, or a template as a string it is recommended to
305
+	 *                             provide a ITemplate as it will probably make things faster, especially if
306
+	 *                             you render a template multiple times
307
+	 * @param mixed     $data      the data to use, can either be a IDataProvider object (i.e. Data) or
308
+	 *                             an associative array. if you're rendering the template from cache, it can be
309
+	 *                             left null
310
+	 * @param ICompiler $_compiler the compiler that must be used to compile the template, if left empty a default
311
+	 *                             Compiler will be used
312
+	 *
313
+	 * @return string|void or the template output if $output is false
314
+	 * @throws Exception
315
+	 */
316
+	public function get($_tpl, $data = array(), $_compiler = null)
317
+	{
318
+		// a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
319
+		if ($this->template instanceof ITemplate) {
320
+			$clone = clone $this;
321
+
322
+			return $clone->get($_tpl, $data, $_compiler);
323
+		}
324
+
325
+		// auto-create template if required
326
+		if ($_tpl instanceof ITemplate) {
327
+			// valid, skip
328
+		} elseif (is_string($_tpl)) {
329
+			$_tpl = new TemplateFile($_tpl);
330
+			$_tpl->setIncludePath($this->getTemplateDir());
331
+		} else {
332
+			throw new Exception('Dwoo->get\'s first argument must be a ITemplate (i.e. TemplateFile) or a valid path to a template file', E_USER_NOTICE);
333
+		}
334
+
335
+		// save the current template, enters render mode at the same time
336
+		// if another rendering is requested it will be proxied to a new Core(instance
337
+		$this->template = $_tpl;
338
+
339
+		// load data
340
+		if ($data instanceof IDataProvider) {
341
+			$this->data = $data->getData();
342
+		} elseif (is_array($data)) {
343
+			$this->data = $data;
344
+		} elseif ($data instanceof ArrayAccess) {
345
+			$this->data = $data;
346
+		} else {
347
+			throw new Exception('Dwoo->get/Dwoo->output\'s data argument must be a IDataProvider object (i.e. Data) or an associative array', E_USER_NOTICE);
348
+		}
349
+
350
+		$this->addGlobal('template', $_tpl->getName());
351
+		$this->initRuntimeVars($_tpl);
352
+
353
+		// try to get cached template
354
+		$file        = $_tpl->getCachedTemplate($this);
355
+		$doCache     = $file === true;
356
+		$cacheLoaded = is_string($file);
357
+
358
+		if ($cacheLoaded === true) {
359
+			// cache is present, run it
360
+			ob_start();
361
+			include $file;
362
+			$this->template = null;
363
+
364
+			return ob_get_clean();
365
+		} else {
366
+			$dynamicId = uniqid();
367
+
368
+			// render template
369
+			$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
370
+			$out              = include $compiledTemplate;
371
+
372
+			// template returned false so it needs to be recompiled
373
+			if ($out === false) {
374
+				$_tpl->forceCompilation();
375
+				$compiledTemplate = $_tpl->getCompiledTemplate($this, $_compiler);
376
+				$out              = include $compiledTemplate;
377
+			}
378
+
379
+			if ($doCache === true) {
380
+				$out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
381
+				if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
382
+					$this->getLoader()->loadPlugin('PluginDynamic');
383
+				}
384
+				$out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
385
+			}
386
+
387
+			// process filters
388
+			foreach ($this->filters as $filter) {
389
+				if (is_array($filter) && $filter[0] instanceof Filter) {
390
+					$out = call_user_func($filter, $out);
391
+				} else {
392
+					$out = call_user_func($filter, $this, $out);
393
+				}
394
+			}
395
+
396
+			if ($doCache === true) {
397
+				// building cache
398
+				$file = $_tpl->cache($this, $out);
399
+
400
+				// run it from the cache to be sure dynamics are rendered
401
+				ob_start();
402
+				include $file;
403
+				// exit render mode
404
+				$this->template = null;
405
+
406
+				return ob_get_clean();
407
+			} else {
408
+				// no need to build cache
409
+				// exit render mode
410
+				$this->template = null;
411
+
412
+				return $out;
413
+			}
414
+		}
415
+	}
416
+
417
+	/**
418
+	 * Registers a Global.
419
+	 * New globals can be added before compiling or rendering a template
420
+	 * but after, you can only update existing globals.
421
+	 *
422
+	 * @param string $name
423
+	 * @param mixed  $value
424
+	 *
425
+	 * @return $this
426
+	 * @throws Exception
427
+	 */
428
+	public function addGlobal($name, $value)
429
+	{
430
+		if (null === $this->globals) {
431
+			$this->initGlobals();
432
+		}
433
+
434
+		$this->globals[$name] = $value;
435
+
436
+		return $this;
437
+	}
438
+
439
+	/**
440
+	 * Gets the registered Globals.
441
+	 *
442
+	 * @return array
443
+	 */
444
+	public function getGlobals()
445
+	{
446
+		return $this->globals;
447
+	}
448
+
449
+	/**
450
+	 * Re-initializes the globals array before each template run.
451
+	 * this method is only callede once when the Dwoo object is created
452
+	 *
453
+	 * @return void
454
+	 */
455
+	protected function initGlobals()
456
+	{
457
+		$this->globals = array(
458
+			'version' => self::VERSION,
459
+			'ad'      => '<a href="http://dwoo.org/">Powered by Dwoo</a>',
460
+			'now'     => $_SERVER['REQUEST_TIME'],
461
+			'charset' => $this->getCharset(),
462
+		);
463
+	}
464
+
465
+	/**
466
+	 * Re-initializes the runtime variables before each template run.
467
+	 * override this method to inject data in the globals array if needed, this
468
+	 * method is called before each template execution
469
+	 *
470
+	 * @param ITemplate $tpl the template that is going to be rendered
471
+	 *
472
+	 * @return void
473
+	 */
474
+	protected function initRuntimeVars(ITemplate $tpl)
475
+	{
476
+		$this->runtimePlugins = array();
477
+		$this->scope          = &$this->data;
478
+		$this->scopeTree      = array();
479
+		$this->stack          = array();
480
+		$this->curBlock       = null;
481
+		$this->buffer         = '';
482
+		$this->returnData     = array();
483
+	}
484
+
485
+	/**
486
+	 * Adds a custom plugin that is not in one of the plugin directories.
487
+	 *
488
+	 * @param string   $name       the plugin name to be used in the templates
489
+	 * @param callback $callback   the plugin callback, either a function name,
490
+	 *                             a class name or an array containing an object
491
+	 *                             or class name and a method name
492
+	 * @param bool     $compilable if set to true, the plugin is assumed to be compilable
493
+	 *
494
+	 * @return void
495
+	 * @throws Exception
496
+	 */
497
+	public function addPlugin($name, $callback, $compilable = false)
498
+	{
499
+		$compilable = $compilable ? self::COMPILABLE_PLUGIN : 0;
500
+		if (is_array($callback)) {
501
+			if (is_subclass_of(is_object($callback[0]) ? get_class($callback[0]) : $callback[0], 'Dwoo\Block\Plugin')) {
502
+				$this->plugins[$name] = array(
503
+					'type'     => self::BLOCK_PLUGIN | $compilable,
504
+					'callback' => $callback,
505
+					'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0])
506
+				);
507
+			} else {
508
+				$this->plugins[$name] = array(
509
+					'type'     => self::CLASS_PLUGIN | $compilable,
510
+					'callback' => $callback,
511
+					'class'    => (is_object($callback[0]) ? get_class($callback[0]) : $callback[0]),
512
+					'function' => $callback[1]
513
+				);
514
+			}
515
+		} elseif (is_string($callback)) {
516
+			if (class_exists($callback)) {
517
+				if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
518
+					$this->plugins[$name] = array(
519
+						'type'     => self::BLOCK_PLUGIN | $compilable,
520
+						'callback' => $callback,
521
+						'class'    => $callback
522
+					);
523
+				} else {
524
+					$this->plugins[$name] = array(
525
+						'type'     => self::CLASS_PLUGIN | $compilable,
526
+						'callback' => $callback,
527
+						'class'    => $callback,
528
+						'function' => ($compilable ? 'compile' : 'process')
529
+					);
530
+				}
531
+			} elseif (function_exists($callback)) {
532
+				$this->plugins[$name] = array(
533
+					'type'     => self::FUNC_PLUGIN | $compilable,
534
+					'callback' => $callback
535
+				);
536
+			} else {
537
+				throw new Exception('Callback could not be processed correctly, please check that the function/class you used exists');
538
+			}
539
+		} elseif ($callback instanceof Closure) {
540
+			$this->plugins[$name] = array(
541
+				'type'     => self::FUNC_PLUGIN | $compilable,
542
+				'callback' => $callback
543
+			);
544
+		} elseif (is_object($callback)) {
545
+			if (is_subclass_of($callback, 'Dwoo\Block\Plugin')) {
546
+				$this->plugins[$name] = array(
547
+					'type'     => self::BLOCK_PLUGIN | $compilable,
548
+					'callback' => get_class($callback),
549
+					'class'    => $callback
550
+				);
551
+			} else {
552
+				$this->plugins[$name] = array(
553
+					'type'     => self::CLASS_PLUGIN | $compilable,
554
+					'callback' => $callback,
555
+					'class'    => $callback,
556
+					'function' => ($compilable ? 'compile' : 'process')
557
+				);
558
+			}
559
+		} else {
560
+			throw new Exception('Callback could not be processed correctly, please check that the function/class you used exists');
561
+		}
562
+	}
563
+
564
+	/**
565
+	 * Removes a custom plugin.
566
+	 *
567
+	 * @param string $name the plugin name
568
+	 *
569
+	 * @return void
570
+	 */
571
+	public function removePlugin($name)
572
+	{
573
+		if (isset($this->plugins[$name])) {
574
+			unset($this->plugins[$name]);
575
+		}
576
+	}
577
+
578
+	/**
579
+	 * Adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this
580
+	 * instance.
581
+	 *
582
+	 * @param mixed $callback a callback or a filter name if it is autoloaded from a plugin directory
583
+	 * @param bool  $autoload if true, the first parameter must be a filter name from one of the plugin directories
584
+	 *
585
+	 * @return void
586
+	 * @throws Exception
587
+	 */
588
+	public function addFilter($callback, $autoload = false)
589
+	{
590
+		if ($autoload) {
591
+			$class = self::NAMESPACE_PLUGINS_FILTERS . self::toCamelCase($callback);
592
+			if (!class_exists($class) && !function_exists($class)) {
593
+				try {
594
+					$this->getLoader()->loadPlugin($callback);
595
+				}
596
+				catch (Exception $e) {
597
+					if (strstr($callback, self::NAMESPACE_PLUGINS_FILTERS)) {
598
+						throw new Exception('Wrong filter name : ' . $callback . ', the "Filter" prefix should not be used, please only use "' . str_replace('Filter', '', $callback) . '"');
599
+					} else {
600
+						throw new Exception('Wrong filter name : ' . $callback . ', when using autoload the filter must be in one of your plugin dir as "name.php" containig a class or function named "Filter<name>"');
601
+					}
602
+				}
603
+			}
604
+
605
+			if (class_exists($class)) {
606
+				$callback = array(new $class($this), 'process');
607
+			} elseif (function_exists($class)) {
608
+				$callback = $class;
609
+			} else {
610
+				throw new Exception('Wrong filter name : ' . $callback . ', when using autoload the filter must be in one of your plugin dir as "name.php" containig a class or function named "Filter<name>"');
611
+			}
612
+
613
+			$this->filters[] = $callback;
614
+		} else {
615
+			$this->filters[] = $callback;
616
+		}
617
+	}
618
+
619
+	/**
620
+	 * Removes a filter.
621
+	 *
622
+	 * @param mixed $callback callback or filter name if it was autoloaded
623
+	 *
624
+	 * @return void
625
+	 */
626
+	public function removeFilter($callback)
627
+	{
628
+		if (($index = array_search(self::NAMESPACE_PLUGINS_FILTERS. 'Filter' . self::toCamelCase($callback), $this->filters,
629
+				true)) !==
630
+			false) {
631
+			unset($this->filters[$index]);
632
+		} elseif (($index = array_search($callback, $this->filters, true)) !== false) {
633
+			unset($this->filters[$index]);
634
+		} else {
635
+			$class = self::NAMESPACE_PLUGINS_FILTERS . 'Filter' . $callback;
636
+			foreach ($this->filters as $index => $filter) {
637
+				if (is_array($filter) && $filter[0] instanceof $class) {
638
+					unset($this->filters[$index]);
639
+					break;
640
+				}
641
+			}
642
+		}
643
+	}
644
+
645
+	/**
646
+	 * Adds a resource or overrides a default one.
647
+	 *
648
+	 * @param string   $name            the resource name
649
+	 * @param string   $class           the resource class (which must implement ITemplate)
650
+	 * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance
651
+	 *                                  used to compile this resource, if none is provided. by default it will produce
652
+	 *                                  a Compiler object
653
+	 *
654
+	 * @return void
655
+	 * @throws Exception
656
+	 */
657
+	public function addResource($name, $class, $compilerFactory = null)
658
+	{
659
+		if (strlen($name) < 2) {
660
+			throw new Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
661
+		}
662
+
663
+		if (!class_exists($class)) {
664
+			throw new Exception(sprintf('Resource class %s does not exist', $class));
665
+		}
666
+
667
+		$interfaces = class_implements($class);
668
+		if (in_array('Dwoo\ITemplate', $interfaces) === false) {
669
+			throw new Exception('Resource class must implement ITemplate');
670
+		}
671
+
672
+		$this->resources[$name] = array(
673
+			'class'    => $class,
674
+			'compiler' => $compilerFactory
675
+		);
676
+	}
677
+
678
+	/**
679
+	 * Removes a custom resource.
680
+	 *
681
+	 * @param string $name the resource name
682
+	 *
683
+	 * @return void
684
+	 */
685
+	public function removeResource($name)
686
+	{
687
+		unset($this->resources[$name]);
688
+		if ($name === 'file') {
689
+			$this->resources['file'] = array(
690
+				'class'    => 'Dwoo\Template\File',
691
+				'compiler' => null
692
+			);
693
+		}
694
+	}
695
+
696
+	/**
697
+	 * Sets the loader object to use to load plugins.
698
+	 *
699
+	 * @param ILoader $loader loader
700
+	 *
701
+	 * @return void
702
+	 */
703
+	public function setLoader(ILoader $loader)
704
+	{
705
+		$this->loader = $loader;
706
+	}
707
+
708
+	/**
709
+	 * Returns the current loader object or a default one if none is currently found.
710
+	 *
711
+	 * @return ILoader|Loader
712
+	 */
713
+	public function getLoader()
714
+	{
715
+		if ($this->loader === null) {
716
+			$this->loader = new Loader($this->getCompileDir());
717
+		}
718
+
719
+		return $this->loader;
720
+	}
721
+
722
+	/**
723
+	 * Returns the custom plugins loaded.
724
+	 * Used by the ITemplate classes to pass the custom plugins to their ICompiler instance.
725
+	 *
726
+	 * @return array
727
+	 */
728
+	public function getCustomPlugins()
729
+	{
730
+		return $this->plugins;
731
+	}
732
+
733
+	/**
734
+	 * Return a specified custom plugin loaded by his name.
735
+	 * Used by the compiler, for executing a Closure.
736
+	 *
737
+	 * @param string $name
738
+	 *
739
+	 * @return mixed|null
740
+	 */
741
+	public function getCustomPlugin($name)
742
+	{
743
+		if (isset($this->plugins[$name])) {
744
+			return $this->plugins[$name]['callback'];
745
+		}
746
+
747
+		return null;
748
+	}
749
+
750
+	/**
751
+	 * Returns the cache directory with a trailing DIRECTORY_SEPARATOR.
752
+	 *
753
+	 * @return string
754
+	 */
755
+	public function getCacheDir()
756
+	{
757
+		if ($this->cacheDir === null) {
758
+			$this->setCacheDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR);
759
+		}
760
+
761
+		return $this->cacheDir;
762
+	}
763
+
764
+	/**
765
+	 * Sets the cache directory and automatically appends a DIRECTORY_SEPARATOR.
766
+	 *
767
+	 * @param string $dir the cache directory
768
+	 *
769
+	 * @return void
770
+	 * @throws Exception
771
+	 */
772
+	public function setCacheDir($dir)
773
+	{
774
+		$this->cacheDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
775
+		if (!file_exists($this->cacheDir)) {
776
+			mkdir($this->cacheDir, 0777, true);
777
+		}
778
+		if (is_writable($this->cacheDir) === false) {
779
+			throw new Exception('The cache directory must be writable, chmod "' . $this->cacheDir . '" to make it writable');
780
+		}
781
+	}
782
+
783
+	/**
784
+	 * Returns the compile directory with a trailing DIRECTORY_SEPARATOR.
785
+	 *
786
+	 * @return string
787
+	 */
788
+	public function getCompileDir()
789
+	{
790
+		if ($this->compileDir === null) {
791
+			$this->setCompileDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'compiled' . DIRECTORY_SEPARATOR);
792
+		}
793
+
794
+		return $this->compileDir;
795
+	}
796
+
797
+	/**
798
+	 * Sets the compile directory and automatically appends a DIRECTORY_SEPARATOR.
799
+	 *
800
+	 * @param string $dir the compile directory
801
+	 *
802
+	 * @return void
803
+	 * @throws Exception
804
+	 */
805
+	public function setCompileDir($dir)
806
+	{
807
+		$this->compileDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
808
+		if (!file_exists($this->compileDir)) {
809
+			mkdir($this->compileDir, 0777, true);
810
+		}
811
+		if (is_writable($this->compileDir) === false) {
812
+			throw new Exception('The compile directory must be writable, chmod "' . $this->compileDir . '" to make it writable');
813
+		}
814
+	}
815
+
816
+	/**
817
+	 * Returns an array of the template directory with a trailing DIRECTORY_SEPARATOR
818
+	 *
819
+	 * @return array
820
+	 */
821
+	public function getTemplateDir()
822
+	{
823
+		return $this->templateDir;
824
+	}
825
+
826
+	/**
827
+	 * sets the template directory and automatically appends a DIRECTORY_SEPARATOR
828
+	 * template directory is stored in an array
829
+	 *
830
+	 * @param string $dir
831
+	 *
832
+	 * @throws Exception
833
+	 */
834
+	public function setTemplateDir($dir)
835
+	{
836
+		$tmpDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
837
+		if (is_dir($tmpDir) === false) {
838
+			throw new Exception('The template directory: "' . $tmpDir . '" does not exists, create the directory or specify an other location !');
839
+		}
840
+		$this->templateDir[] = $tmpDir;
841
+	}
842
+
843
+	/**
844
+	 * Returns the default cache time that is used with templates that do not have a cache time set.
845
+	 *
846
+	 * @return int the duration in seconds
847
+	 */
848
+	public function getCacheTime()
849
+	{
850
+		return $this->cacheTime;
851
+	}
852
+
853
+	/**
854
+	 * Sets the default cache time to use with templates that do not have a cache time set.
855
+	 *
856
+	 * @param int $seconds the duration in seconds
857
+	 *
858
+	 * @return void
859
+	 */
860
+	public function setCacheTime($seconds)
861
+	{
862
+		$this->cacheTime = (int)$seconds;
863
+	}
864
+
865
+	/**
866
+	 * Returns the character set used by the string manipulation plugins.
867
+	 * the charset is automatically lowercased
868
+	 *
869
+	 * @return string
870
+	 */
871
+	public function getCharset()
872
+	{
873
+		return $this->charset;
874
+	}
875
+
876
+	/**
877
+	 * Sets the character set used by the string manipulation plugins.
878
+	 * the charset will be automatically lowercased
879
+	 *
880
+	 * @param string $charset the character set
881
+	 *
882
+	 * @return void
883
+	 */
884
+	public function setCharset($charset)
885
+	{
886
+		$this->charset = strtolower((string)$charset);
887
+	}
888
+
889
+	/**
890
+	 * Returns the current template being rendered, when applicable, or null.
891
+	 *
892
+	 * @return ITemplate|null
893
+	 */
894
+	public function getTemplate()
895
+	{
896
+		return $this->template;
897
+	}
898
+
899
+	/**
900
+	 * Sets the current template being rendered.
901
+	 *
902
+	 * @param ITemplate $tpl template object
903
+	 *
904
+	 * @return void
905
+	 */
906
+	public function setTemplate(ITemplate $tpl)
907
+	{
908
+		$this->template = $tpl;
909
+	}
910
+
911
+	/**
912
+	 * Sets the default compiler factory function for the given resource name.
913
+	 * a compiler factory must return a ICompiler object pre-configured to fit your needs
914
+	 *
915
+	 * @param string   $resourceName    the resource name (i.e. file, string)
916
+	 * @param callback $compilerFactory the compiler factory callback
917
+	 *
918
+	 * @return void
919
+	 */
920
+	public function setDefaultCompilerFactory($resourceName, $compilerFactory)
921
+	{
922
+		$this->resources[$resourceName]['compiler'] = $compilerFactory;
923
+	}
924
+
925
+	/**
926
+	 * Returns the default compiler factory function for the given resource name.
927
+	 *
928
+	 * @param string $resourceName the resource name
929
+	 *
930
+	 * @return callback the compiler factory callback
931
+	 */
932
+	public function getDefaultCompilerFactory($resourceName)
933
+	{
934
+		return $this->resources[$resourceName]['compiler'];
935
+	}
936
+
937
+	/**
938
+	 * Sets the security policy object to enforce some php security settings.
939
+	 * use this if untrusted persons can modify templates
940
+	 *
941
+	 * @param SecurityPolicy $policy the security policy object
942
+	 *
943
+	 * @return void
944
+	 */
945
+	public function setSecurityPolicy(SecurityPolicy $policy = null)
946
+	{
947
+		$this->securityPolicy = $policy;
948
+	}
949
+
950
+	/**
951
+	 * Returns the current security policy object or null by default.
952
+	 *
953
+	 * @return SecurityPolicy|null the security policy object if any
954
+	 */
955
+	public function getSecurityPolicy()
956
+	{
957
+		return $this->securityPolicy;
958
+	}
959
+
960
+	/**
961
+	 * Sets the object that must be used as a plugin proxy when plugin can't be found
962
+	 * by dwoo's loader.
963
+	 *
964
+	 * @param IPluginProxy $pluginProxy the proxy object
965
+	 *
966
+	 * @return void
967
+	 */
968
+	public function setPluginProxy(IPluginProxy $pluginProxy)
969
+	{
970
+		$this->pluginProxy = $pluginProxy;
971
+	}
972
+
973
+	/**
974
+	 * Returns the current plugin proxy object or null by default.
975
+	 *
976
+	 * @return IPluginProxy
977
+	 */
978
+	public function getPluginProxy()
979
+	{
980
+		return $this->pluginProxy;
981
+	}
982
+
983
+	/**
984
+	 * Checks whether the given template is cached or not.
985
+	 *
986
+	 * @param ITemplate $tpl the template object
987
+	 *
988
+	 * @return bool
989
+	 */
990
+	public function isCached(ITemplate $tpl)
991
+	{
992
+		return is_string($tpl->getCachedTemplate($this));
993
+	}
994
+
995
+	/**
996
+	 * Clear templates inside the compiled directory.
997
+	 *
998
+	 * @return int
999
+	 */
1000
+	public function clearCompiled()
1001
+	{
1002
+		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCompileDir()), \RecursiveIteratorIterator::SELF_FIRST);
1003
+		$count    = 0;
1004
+		foreach ($iterator as $file) {
1005
+			if ($file->isFile()) {
1006
+				$count += unlink($file->__toString()) ? 1 : 0;
1007
+			}
1008
+		}
1009
+
1010
+		return $count;
1011
+	}
1012
+
1013
+	/**
1014
+	 * Clears the cached templates if they are older than the given time.
1015
+	 *
1016
+	 * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
1017
+	 *
1018
+	 * @return int the amount of templates cleared
1019
+	 */
1020
+	public function clearCache($olderThan = - 1)
1021
+	{
1022
+		$iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCacheDir()), \RecursiveIteratorIterator::SELF_FIRST);
1023
+		$expired  = time() - $olderThan;
1024
+		$count    = 0;
1025
+		foreach ($iterator as $file) {
1026
+			if ($file->isFile() && $file->getCTime() < $expired) {
1027
+				$count += unlink((string)$file) ? 1 : 0;
1028
+			}
1029
+		}
1030
+
1031
+		return $count;
1032
+	}
1033
+
1034
+	/**
1035
+	 * Fetches a template object of the given resource.
1036
+	 *
1037
+	 * @param string    $resourceName   the resource name (i.e. file, string)
1038
+	 * @param string    $resourceId     the resource identifier (i.e. file path)
1039
+	 * @param int       $cacheTime      the cache time setting for this resource
1040
+	 * @param string    $cacheId        the unique cache identifier
1041
+	 * @param string    $compileId      the unique compiler identifier
1042
+	 * @param ITemplate $parentTemplate the parent template
1043
+	 *
1044
+	 * @return ITemplate
1045
+	 * @throws Exception
1046
+	 */
1047
+	public function templateFactory($resourceName, $resourceId, $cacheTime = null, $cacheId = null, $compileId = null, ITemplate $parentTemplate = null)
1048
+	{
1049
+		if (isset($this->resources[$resourceName])) {
1050
+			/**
1051
+			 * Interface ITemplate
1052
+			 *
1053
+			 * @var ITemplate $class
1054
+			 */
1055
+			$class = $this->resources[$resourceName]['class'];
1056
+
1057
+			return $class::templateFactory($this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
1058
+		}
1059
+
1060
+		throw new Exception('Unknown resource type : ' . $resourceName);
1061
+	}
1062
+
1063
+	/**
1064
+	 * Checks if the input is an array or arrayaccess object, optionally it can also check if it's
1065
+	 * empty.
1066
+	 *
1067
+	 * @param mixed $value        the variable to check
1068
+	 * @param bool  $checkIsEmpty if true, the function will also check if the array|arrayaccess is empty,
1069
+	 *                            and return true only if it's not empty
1070
+	 *
1071
+	 * @return int|bool true if it's an array|arrayaccess (or the item count if $checkIsEmpty is true) or false if it's
1072
+	 *                  not an array|arrayaccess (or 0 if $checkIsEmpty is true)
1073
+	 */
1074
+	public function isArray($value, $checkIsEmpty = false)
1075
+	{
1076
+		if (is_array($value) === true || $value instanceof ArrayAccess) {
1077
+			if ($checkIsEmpty === false) {
1078
+				return true;
1079
+			}
1080
+
1081
+			return $this->count($value);
1082
+		}
1083
+
1084
+		return false;
1085
+	}
1086
+
1087
+	/**
1088
+	 * Checks if the input is an array or a traversable object, optionally it can also check if it's
1089
+	 * empty.
1090
+	 *
1091
+	 * @param mixed $value        the variable to check
1092
+	 * @param bool  $checkIsEmpty if true, the function will also check if the array|traversable is empty,
1093
+	 *                            and return true only if it's not empty
1094
+	 *
1095
+	 * @return int|bool true if it's an array|traversable (or the item count if $checkIsEmpty is true) or false if it's
1096
+	 *                  not an array|traversable (or 0 if $checkIsEmpty is true)
1097
+	 */
1098
+	public function isTraversable($value, $checkIsEmpty = false)
1099
+	{
1100
+		if (is_array($value) === true) {
1101
+			if ($checkIsEmpty === false) {
1102
+				return true;
1103
+			} else {
1104
+				return count($value) > 0;
1105
+			}
1106
+		} elseif ($value instanceof Traversable) {
1107
+			if ($checkIsEmpty === false) {
1108
+				return true;
1109
+			} else {
1110
+				return $this->count($value);
1111
+			}
1112
+		}
1113
+
1114
+		return false;
1115
+	}
1116
+
1117
+	/**
1118
+	 * Counts an array or arrayaccess/traversable object.
1119
+	 *
1120
+	 * @param mixed $value the value to count
1121
+	 *
1122
+	 * @return int|bool the count for arrays and objects that implement countable, true for other objects that don't,
1123
+	 *                  and 0 for empty elements
1124
+	 */
1125
+	public function count($value)
1126
+	{
1127
+		if (is_array($value) === true || $value instanceof Countable) {
1128
+			return count($value);
1129
+		} elseif ($value instanceof ArrayAccess) {
1130
+			if ($value->offsetExists(0)) {
1131
+				return true;
1132
+			}
1133
+		} elseif ($value instanceof Iterator) {
1134
+			$value->rewind();
1135
+			if ($value->valid()) {
1136
+				return true;
1137
+			}
1138
+		} elseif ($value instanceof Traversable) {
1139
+			foreach ($value as $dummy) {
1140
+				return true;
1141
+			}
1142
+		}
1143
+
1144
+		return 0;
1145
+	}
1146
+
1147
+	/**
1148
+	 * Triggers a dwoo error.
1149
+	 *
1150
+	 * @param string $message the error message
1151
+	 * @param int    $level   the error level, one of the PHP's E_* constants
1152
+	 *
1153
+	 * @return void
1154
+	 */
1155
+	public function triggerError($message, $level = E_USER_NOTICE)
1156
+	{
1157
+		if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
1158
+			$tplIdentifier = $this->template->getResourceName();
1159
+		}
1160
+		trigger_error('Dwoo error (in ' . $tplIdentifier . ') : ' . $message, $level);
1161
+	}
1162
+
1163
+	/**
1164
+	 * Adds a block to the block stack.
1165
+	 *
1166
+	 * @param string $blockName the block name (without `Plugin` prefix)
1167
+	 * @param array  $args      the arguments to be passed to the block's init() function
1168
+	 *
1169
+	 * @return BlockPlugin the newly created block
1170
+	 */
1171
+	public function addStack($blockName, array $args = array())
1172
+	{
1173
+		if (isset($this->plugins[$blockName])) {
1174
+			$class = $this->plugins[$blockName]['class'];
1175
+		} else {
1176
+			$class = current(array_filter([
1177
+				'Plugin' . self::toCamelCase($blockName),
1178
+				self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . self::toCamelCase($blockName)
1179
+			], 'class_exists'));
1180
+		}
1181
+
1182
+		if ($this->curBlock !== null) {
1183
+			$this->curBlock->buffer(ob_get_contents());
1184
+			ob_clean();
1185
+		} else {
1186
+			$this->buffer .= ob_get_contents();
1187
+			ob_clean();
1188
+		}
1189
+
1190
+		$block = new $class($this);
1191
+
1192
+		call_user_func_array(array($block, 'init'), $args);
1193
+
1194
+		$this->stack[] = $this->curBlock = $block;
1195
+
1196
+		return $block;
1197
+	}
1198
+
1199
+	/**
1200
+	 * Removes the plugin at the top of the block stack.
1201
+	 * Calls the block buffer() function, followed by a call to end() and finally a call to process()
1202
+	 *
1203
+	 * @return void
1204
+	 */
1205
+	public function delStack()
1206
+	{
1207
+		$args = func_get_args();
1208
+
1209
+		$this->curBlock->buffer(ob_get_contents());
1210
+		ob_clean();
1211
+
1212
+		call_user_func_array(array($this->curBlock, 'end'), $args);
1213
+
1214
+		$tmp = array_pop($this->stack);
1215
+
1216
+		if (count($this->stack) > 0) {
1217
+			$this->curBlock = end($this->stack);
1218
+			$this->curBlock->buffer($tmp->process());
1219
+		} else {
1220
+			if ($this->buffer !== '') {
1221
+				echo $this->buffer;
1222
+				$this->buffer = '';
1223
+			}
1224
+			$this->curBlock = null;
1225
+			echo $tmp->process();
1226
+		}
1227
+
1228
+		unset($tmp);
1229
+	}
1230
+
1231
+	/**
1232
+	 * Returns the parent block of the given block.
1233
+	 *
1234
+	 * @param BlockPlugin $block the block class plugin
1235
+	 *
1236
+	 * @return BlockPlugin|false if the given block isn't in the stack
1237
+	 */
1238
+	public function getParentBlock(BlockPlugin $block)
1239
+	{
1240
+		$index = array_search($block, $this->stack, true);
1241
+		if ($index !== false && $index > 0) {
1242
+			return $this->stack[$index - 1];
1243
+		}
1244
+
1245
+		return false;
1246
+	}
1247
+
1248
+	/**
1249
+	 * Finds the closest block of the given type, starting at the top of the stack.
1250
+	 *
1251
+	 * @param string $type the type of plugin you want to find
1252
+	 *
1253
+	 * @return BlockPlugin|false if no plugin of such type is in the stack
1254
+	 */
1255
+	public function findBlock($type)
1256
+	{
1257
+		if (isset($this->plugins[$type])) {
1258
+			$type = $this->plugins[$type]['class'];
1259
+		} else {
1260
+			$type = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin_' . str_replace(self::NAMESPACE_PLUGINS_BLOCKS.'Plugin',
1261
+					'', $type);
1262
+		}
1263
+
1264
+		$keys = array_keys($this->stack);
1265
+		while (($key = array_pop($keys)) !== false) {
1266
+			if ($this->stack[$key] instanceof $type) {
1267
+				return $this->stack[$key];
1268
+			}
1269
+		}
1270
+
1271
+		return false;
1272
+	}
1273
+
1274
+	/**
1275
+	 * Returns a Plugin of the given class.
1276
+	 * this is so a single instance of every class plugin is created at each template run,
1277
+	 * allowing class plugins to have "per-template-run" static variables
1278
+	 *
1279
+	 * @param string $class the class name
1280
+	 *
1281
+	 * @return mixed an object of the given class
1282
+	 */
1283
+	public function getObjectPlugin($class)
1284
+	{
1285
+		if (isset($this->runtimePlugins[$class])) {
1286
+			return $this->runtimePlugins[$class];
1287
+		}
1288
+
1289
+		return $this->runtimePlugins[$class] = new $class($this);
1290
+	}
1291
+
1292
+	/**
1293
+	 * Calls the process() method of the given class-plugin name.
1294
+	 *
1295
+	 * @param string $plugName the class plugin name (without `Plugin` prefix)
1296
+	 * @param array  $params   an array of parameters to send to the process() method
1297
+	 *
1298
+	 * @return string the process() return value
1299
+	 */
1300
+	public function classCall($plugName, array $params = array())
1301
+	{
1302
+		$class  = self::toCamelCase($plugName);
1303
+		$plugin = $this->getObjectPlugin($class);
1304
+
1305
+		return call_user_func_array(array($plugin, 'process'), $params);
1306
+	}
1307
+
1308
+	/**
1309
+	 * Calls a php function.
1310
+	 *
1311
+	 * @param string $callback the function to call
1312
+	 * @param array  $params   an array of parameters to send to the function
1313
+	 *
1314
+	 * @return mixed the return value of the called function
1315
+	 */
1316
+	public function arrayMap($callback, array $params)
1317
+	{
1318
+		if ($params[0] === $this) {
1319
+			$addThis = true;
1320
+			array_shift($params);
1321
+		}
1322
+		if ((is_array($params[0]) || ($params[0] instanceof Iterator && $params[0] instanceof ArrayAccess))) {
1323
+			if (empty($params[0])) {
1324
+				return $params[0];
1325
+			}
1326
+
1327
+			// array map
1328
+			$out = array();
1329
+			$cnt = count($params);
1330
+
1331
+			if (isset($addThis)) {
1332
+				array_unshift($params, $this);
1333
+				$items = $params[1];
1334
+				$keys  = array_keys($items);
1335
+
1336
+				if (is_string($callback) === false) {
1337
+					while (($i = array_shift($keys)) !== null) {
1338
+						$out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1339
+					}
1340
+				} elseif ($cnt === 1) {
1341
+					while (($i = array_shift($keys)) !== null) {
1342
+						$out[] = $callback($this, $items[$i]);
1343
+					}
1344
+				} elseif ($cnt === 2) {
1345
+					while (($i = array_shift($keys)) !== null) {
1346
+						$out[] = $callback($this, $items[$i], $params[2]);
1347
+					}
1348
+				} elseif ($cnt === 3) {
1349
+					while (($i = array_shift($keys)) !== null) {
1350
+						$out[] = $callback($this, $items[$i], $params[2], $params[3]);
1351
+					}
1352
+				} else {
1353
+					while (($i = array_shift($keys)) !== null) {
1354
+						$out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1355
+					}
1356
+				}
1357
+			} else {
1358
+				$items = $params[0];
1359
+				$keys  = array_keys($items);
1360
+
1361
+				if (is_string($callback) === false) {
1362
+					while (($i = array_shift($keys)) !== null) {
1363
+						$out[] = call_user_func_array($callback, array($items[$i]) + $params);
1364
+					}
1365
+				} elseif ($cnt === 1) {
1366
+					while (($i = array_shift($keys)) !== null) {
1367
+						$out[] = $callback($items[$i]);
1368
+					}
1369
+				} elseif ($cnt === 2) {
1370
+					while (($i = array_shift($keys)) !== null) {
1371
+						$out[] = $callback($items[$i], $params[1]);
1372
+					}
1373
+				} elseif ($cnt === 3) {
1374
+					while (($i = array_shift($keys)) !== null) {
1375
+						$out[] = $callback($items[$i], $params[1], $params[2]);
1376
+					}
1377
+				} elseif ($cnt === 4) {
1378
+					while (($i = array_shift($keys)) !== null) {
1379
+						$out[] = $callback($items[$i], $params[1], $params[2], $params[3]);
1380
+					}
1381
+				} else {
1382
+					while (($i = array_shift($keys)) !== null) {
1383
+						$out[] = call_user_func_array($callback, array($items[$i]) + $params);
1384
+					}
1385
+				}
1386
+			}
1387
+
1388
+			return $out;
1389
+		} else {
1390
+			return $params[0];
1391
+		}
1392
+	}
1393
+
1394
+	/**
1395
+	 * Reads a variable into the given data array.
1396
+	 *
1397
+	 * @param string $varstr   the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1398
+	 * @param mixed  $data     the data array or object to read from
1399
+	 * @param bool   $safeRead if true, the function will check whether the index exists to prevent any notices from
1400
+	 *                         being output
1401
+	 *
1402
+	 * @return mixed
1403
+	 */
1404
+	public function readVarInto($varstr, $data, $safeRead = false)
1405
+	{
1406
+		if ($data === null) {
1407
+			return null;
1408
+		}
1409
+
1410
+		if (is_array($varstr) === false) {
1411
+			preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1412
+		} else {
1413
+			$m = $varstr;
1414
+		}
1415
+		unset($varstr);
1416
+
1417
+		foreach ($m[1] as $k => $sep) {
1418
+			if ($sep === '.' || $sep === '[' || $sep === '') {
1419
+				// strip enclosing quotes if present
1420
+				$m[2][$k] = preg_replace('#^(["\']?)(.*?)\1$#', '$2', $m[2][$k]);
1421
+
1422
+				if ((is_array($data) || $data instanceof ArrayAccess) && ($safeRead === false || isset($data[$m[2][$k]]))) {
1423
+					$data = $data[$m[2][$k]];
1424
+				} else {
1425
+					return null;
1426
+				}
1427
+			} else {
1428
+				if (is_object($data) && ($safeRead === false || isset($data->{$m[2][$k]}))) {
1429
+					$data = $data->{$m[2][$k]};
1430
+				} else {
1431
+					return null;
1432
+				}
1433
+			}
1434
+		}
1435
+
1436
+		return $data;
1437
+	}
1438
+
1439
+	/**
1440
+	 * Reads a variable into the parent scope.
1441
+	 *
1442
+	 * @param int    $parentLevels the amount of parent levels to go from the current scope
1443
+	 * @param string $varstr       the variable string, using dwoo variable syntax (i.e.
1444
+	 *                             "var.subvar[subsubvar]->property")
1445
+	 *
1446
+	 * @return mixed
1447
+	 */
1448
+	public function readParentVar($parentLevels, $varstr = null)
1449
+	{
1450
+		$tree = $this->scopeTree;
1451
+		$cur  = $this->data;
1452
+
1453
+		while ($parentLevels -- !== 0) {
1454
+			array_pop($tree);
1455
+		}
1456
+
1457
+		while (($i = array_shift($tree)) !== null) {
1458
+			if (is_object($cur)) {
1459
+				$cur = $cur->{$i};
1460
+			} else {
1461
+				$cur = $cur[$i];
1462
+			}
1463
+		}
1464
+
1465
+		if ($varstr !== null) {
1466
+			return $this->readVarInto($varstr, $cur);
1467
+		} else {
1468
+			return $cur;
1469
+		}
1470
+	}
1471
+
1472
+	/**
1473
+	 * Reads a variable into the current scope.
1474
+	 *
1475
+	 * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1476
+	 *
1477
+	 * @return mixed
1478
+	 */
1479
+	public function readVar($varstr)
1480
+	{
1481
+		if (is_array($varstr) === true) {
1482
+			$m = $varstr;
1483
+			unset($varstr);
1484
+		} else {
1485
+			if (strstr($varstr, '.') === false && strstr($varstr, '[') === false && strstr($varstr, '->') === false) {
1486
+				if ($varstr === 'dwoo') {
1487
+					return $this->getGlobals();
1488
+				} elseif ($varstr === '__' || $varstr === '_root') {
1489
+					return $this->data;
1490
+				} elseif ($varstr === '_' || $varstr === '_parent') {
1491
+					$varstr = '.' . $varstr;
1492
+					$tree   = $this->scopeTree;
1493
+					$cur    = $this->data;
1494
+					array_pop($tree);
1495
+
1496
+					while (($i = array_shift($tree)) !== null) {
1497
+						if (is_object($cur)) {
1498
+							$cur = $cur->{$i};
1499
+						} else {
1500
+							$cur = $cur[$i];
1501
+						}
1502
+					}
1503
+
1504
+					return $cur;
1505
+				}
1506
+
1507
+				$cur = $this->scope;
1508
+
1509
+				if (isset($cur[$varstr])) {
1510
+					return $cur[$varstr];
1511
+				} else {
1512
+					return null;
1513
+				}
1514
+			}
1515
+
1516
+			if (substr($varstr, 0, 1) === '.') {
1517
+				$varstr = 'dwoo' . $varstr;
1518
+			}
1519
+
1520
+			preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
1521
+		}
1522
+
1523
+		$i = $m[2][0];
1524
+		if ($i === 'dwoo') {
1525
+			$cur = $this->getGlobals();
1526
+			array_shift($m[2]);
1527
+			array_shift($m[1]);
1528
+			switch ($m[2][0]) {
1529
+			case 'get':
1530
+				$cur = $_GET;
1531
+				break;
1532
+			case 'post':
1533
+				$cur = $_POST;
1534
+				break;
1535
+			case 'session':
1536
+				$cur = $_SESSION;
1537
+				break;
1538
+			case 'cookies':
1539
+			case 'cookie':
1540
+				$cur = $_COOKIE;
1541
+				break;
1542
+			case 'server':
1543
+				$cur = $_SERVER;
1544
+				break;
1545
+			case 'env':
1546
+				$cur = $_ENV;
1547
+				break;
1548
+			case 'request':
1549
+				$cur = $_REQUEST;
1550
+				break;
1551
+			case 'const':
1552
+				array_shift($m[2]);
1553
+				if (defined($m[2][0])) {
1554
+					return constant($m[2][0]);
1555
+				} else {
1556
+					return null;
1557
+				}
1558
+			}
1559
+			if ($cur !== $this->getGlobals()) {
1560
+				array_shift($m[2]);
1561
+				array_shift($m[1]);
1562
+			}
1563
+		} elseif ($i === '__' || $i === '_root') {
1564
+			$cur = $this->data;
1565
+			array_shift($m[2]);
1566
+			array_shift($m[1]);
1567
+		} elseif ($i === '_' || $i === '_parent') {
1568
+			$tree = $this->scopeTree;
1569
+			$cur  = $this->data;
1570
+
1571
+			while (true) {
1572
+				array_pop($tree);
1573
+				array_shift($m[2]);
1574
+				array_shift($m[1]);
1575
+				if (current($m[2]) === '_' || current($m[2]) === '_parent') {
1576
+					continue;
1577
+				}
1578
+
1579
+				while (($i = array_shift($tree)) !== null) {
1580
+					if (is_object($cur)) {
1581
+						$cur = $cur->{$i};
1582
+					} else {
1583
+						$cur = $cur[$i];
1584
+					}
1585
+				}
1586
+				break;
1587
+			}
1588
+		} else {
1589
+			$cur = $this->scope;
1590
+		}
1591
+
1592
+		foreach ($m[1] as $k => $sep) {
1593
+			if ($sep === '.' || $sep === '[' || $sep === '') {
1594
+				if ((is_array($cur) || $cur instanceof ArrayAccess) && isset($cur[$m[2][$k]])) {
1595
+					$cur = $cur[$m[2][$k]];
1596
+				} else {
1597
+					return null;
1598
+				}
1599
+			} elseif ($sep === '->') {
1600
+				if (is_object($cur)) {
1601
+					$cur = $cur->{$m[2][$k]};
1602
+				} else {
1603
+					return null;
1604
+				}
1605
+			} else {
1606
+				return null;
1607
+			}
1608
+		}
1609
+
1610
+		return $cur;
1611
+	}
1612
+
1613
+	/**
1614
+	 * Assign the value to the given variable.
1615
+	 *
1616
+	 * @param mixed  $value the value to assign
1617
+	 * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
1618
+	 *
1619
+	 * @return bool true if assigned correctly or false if a problem occured while parsing the var string
1620
+	 */
1621
+	public function assignInScope($value, $scope)
1622
+	{
1623
+		if (!is_string($scope)) {
1624
+			$this->triggerError('Assignments must be done into strings, (' . gettype($scope) . ') ' . var_export($scope, true) . ' given', E_USER_ERROR);
1625
+		}
1626
+		if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1627
+			$this->scope[$scope] = $value;
1628
+		} else {
1629
+			// TODO handle _root/_parent scopes ?
1630
+			preg_match_all('#(\[|->|\.)?([^.[\]-]+)\]?#i', $scope, $m);
1631
+
1632
+			$cur  = &$this->scope;
1633
+			$last = array(
1634
+				array_pop($m[1]),
1635
+				array_pop($m[2])
1636
+			);
1637
+
1638
+			foreach ($m[1] as $k => $sep) {
1639
+				if ($sep === '.' || $sep === '[' || $sep === '') {
1640
+					if (is_array($cur) === false) {
1641
+						$cur = array();
1642
+					}
1643
+					$cur = &$cur[$m[2][$k]];
1644
+				} elseif ($sep === '->') {
1645
+					if (is_object($cur) === false) {
1646
+						$cur = new stdClass();
1647
+					}
1648
+					$cur = &$cur->{$m[2][$k]};
1649
+				} else {
1650
+					return false;
1651
+				}
1652
+			}
1653
+
1654
+			if ($last[0] === '.' || $last[0] === '[' || $last[0] === '') {
1655
+				if (is_array($cur) === false) {
1656
+					$cur = array();
1657
+				}
1658
+				$cur[$last[1]] = $value;
1659
+			} elseif ($last[0] === '->') {
1660
+				if (is_object($cur) === false) {
1661
+					$cur = new stdClass();
1662
+				}
1663
+				$cur->{$last[1]} = $value;
1664
+			} else {
1665
+				return false;
1666
+			}
1667
+		}
1668
+	}
1669
+
1670
+	/**
1671
+	 * Sets the scope to the given scope string or array.
1672
+	 *
1673
+	 * @param mixed $scope    a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
1674
+	 * @param bool  $absolute if true, the scope is set from the top level scope and not from the current scope
1675
+	 *
1676
+	 * @return array the current scope tree
1677
+	 */
1678
+	public function setScope($scope, $absolute = false)
1679
+	{
1680
+		$old = $this->scopeTree;
1681
+
1682
+		if (is_string($scope) === true) {
1683
+			$scope = explode('.', $scope);
1684
+		}
1685
+
1686
+		if ($absolute === true) {
1687
+			$this->scope     = &$this->data;
1688
+			$this->scopeTree = array();
1689
+		}
1690
+
1691
+		while (($bit = array_shift($scope)) !== null) {
1692
+			if ($bit === '_' || $bit === '_parent') {
1693
+				array_pop($this->scopeTree);
1694
+				$this->scope = &$this->data;
1695
+				$cnt         = count($this->scopeTree);
1696
+				for ($i = 0; $i < $cnt; ++ $i) {
1697
+					$this->scope = &$this->scope[$this->scopeTree[$i]];
1698
+				}
1699
+			} elseif ($bit === '__' || $bit === '_root') {
1700
+				$this->scope     = &$this->data;
1701
+				$this->scopeTree = array();
1702
+			} elseif (isset($this->scope[$bit])) {
1703
+				if ($this->scope instanceof ArrayAccess) {
1704
+					$tmp         = $this->scope[$bit];
1705
+					$this->scope = &$tmp;
1706
+				} else {
1707
+					$this->scope = &$this->scope[$bit];
1708
+				}
1709
+				$this->scopeTree[] = $bit;
1710
+			} else {
1711
+				unset($this->scope);
1712
+				$this->scope = null;
1713
+			}
1714
+		}
1715
+
1716
+		return $old;
1717
+	}
1718
+
1719
+	/**
1720
+	 * Returns the entire data array.
1721
+	 *
1722
+	 * @return array
1723
+	 */
1724
+	public function getData()
1725
+	{
1726
+		return $this->data;
1727
+	}
1728
+
1729
+	/**
1730
+	 * Sets a return value for the currently running template.
1731
+	 *
1732
+	 * @param string $name  var name
1733
+	 * @param mixed  $value var value
1734
+	 *
1735
+	 * @return void
1736
+	 */
1737
+	public function setReturnValue($name, $value)
1738
+	{
1739
+		$this->returnData[$name] = $value;
1740
+	}
1741
+
1742
+	/**
1743
+	 * Retrieves the return values set by the template.
1744
+	 *
1745
+	 * @return array
1746
+	 */
1747
+	public function getReturnValues()
1748
+	{
1749
+		return $this->returnData;
1750
+	}
1751
+
1752
+	/**
1753
+	 * Returns a reference to the current scope.
1754
+	 *
1755
+	 * @return mixed
1756
+	 */
1757
+	public function &getScope()
1758
+	{
1759
+		return $this->scope;
1760
+	}
1761
+
1762
+	/**
1763
+	 * Redirects all calls to unexisting to plugin proxy.
1764
+	 *
1765
+	 * @param string $method the method name
1766
+	 * @param array  $args   array of arguments
1767
+	 *
1768
+	 * @return mixed
1769
+	 * @throws Exception
1770
+	 */
1771
+	public function __call($method, $args)
1772
+	{
1773
+		$proxy = $this->getPluginProxy();
1774
+		if (!$proxy) {
1775
+			throw new Exception('Call to undefined method ' . __CLASS__ . '::' . $method . '()');
1776
+		}
1777
+
1778
+		return call_user_func_array($proxy->getCallback($method), $args);
1779
+	}
1780
+
1781
+	/**
1782
+	 * Convert plugin name from `auto_escape` to `AutoEscape`.
1783
+	 * @param string $input
1784
+	 * @param string $separator
1785
+	 *
1786
+	 * @return mixed
1787
+	 */
1788
+	public static function toCamelCase($input, $separator = '_')
1789
+	{
1790
+		return join(array_map('ucfirst', explode($separator, $input)));
1791
+
1792
+		// TODO >= PHP5.4.32
1793
+		//return str_replace($separator, '', ucwords($input, $separator));
1794
+	}
1795 1795
 }
Please login to merge, or discard this patch.
Spacing   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -377,8 +377,8 @@  discard block
 block discarded – undo
377 377
             }
378 378
 
379 379
             if ($doCache === true) {
380
-                $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*' . $dynamicId . '*/ echo \'$1\'; ?>', $out);
381
-                if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS . 'PluginDynamic')) {
380
+                $out = preg_replace('/(<%|%>|<\?php|<\?|\?>)/', '<?php /*'.$dynamicId.'*/ echo \'$1\'; ?>', $out);
381
+                if (!class_exists(self::NAMESPACE_PLUGINS_BLOCKS.'PluginDynamic')) {
382 382
                     $this->getLoader()->loadPlugin('PluginDynamic');
383 383
                 }
384 384
                 $out = PluginDynamic::unescape($out, $dynamicId, $compiledTemplate);
@@ -588,16 +588,16 @@  discard block
 block discarded – undo
588 588
     public function addFilter($callback, $autoload = false)
589 589
     {
590 590
         if ($autoload) {
591
-            $class = self::NAMESPACE_PLUGINS_FILTERS . self::toCamelCase($callback);
591
+            $class = self::NAMESPACE_PLUGINS_FILTERS.self::toCamelCase($callback);
592 592
             if (!class_exists($class) && !function_exists($class)) {
593 593
                 try {
594 594
                     $this->getLoader()->loadPlugin($callback);
595 595
                 }
596 596
                 catch (Exception $e) {
597 597
                     if (strstr($callback, self::NAMESPACE_PLUGINS_FILTERS)) {
598
-                        throw new Exception('Wrong filter name : ' . $callback . ', the "Filter" prefix should not be used, please only use "' . str_replace('Filter', '', $callback) . '"');
598
+                        throw new Exception('Wrong filter name : '.$callback.', the "Filter" prefix should not be used, please only use "'.str_replace('Filter', '', $callback).'"');
599 599
                     } else {
600
-                        throw new Exception('Wrong filter name : ' . $callback . ', when using autoload the filter must be in one of your plugin dir as "name.php" containig a class or function named "Filter<name>"');
600
+                        throw new Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containig a class or function named "Filter<name>"');
601 601
                     }
602 602
                 }
603 603
             }
@@ -607,7 +607,7 @@  discard block
 block discarded – undo
607 607
             } elseif (function_exists($class)) {
608 608
                 $callback = $class;
609 609
             } else {
610
-                throw new Exception('Wrong filter name : ' . $callback . ', when using autoload the filter must be in one of your plugin dir as "name.php" containig a class or function named "Filter<name>"');
610
+                throw new Exception('Wrong filter name : '.$callback.', when using autoload the filter must be in one of your plugin dir as "name.php" containig a class or function named "Filter<name>"');
611 611
             }
612 612
 
613 613
             $this->filters[] = $callback;
@@ -625,14 +625,14 @@  discard block
 block discarded – undo
625 625
      */
626 626
     public function removeFilter($callback)
627 627
     {
628
-        if (($index = array_search(self::NAMESPACE_PLUGINS_FILTERS. 'Filter' . self::toCamelCase($callback), $this->filters,
628
+        if (($index = array_search(self::NAMESPACE_PLUGINS_FILTERS.'Filter'.self::toCamelCase($callback), $this->filters,
629 629
                 true)) !==
630 630
             false) {
631 631
             unset($this->filters[$index]);
632 632
         } elseif (($index = array_search($callback, $this->filters, true)) !== false) {
633 633
             unset($this->filters[$index]);
634 634
         } else {
635
-            $class = self::NAMESPACE_PLUGINS_FILTERS . 'Filter' . $callback;
635
+            $class = self::NAMESPACE_PLUGINS_FILTERS.'Filter'.$callback;
636 636
             foreach ($this->filters as $index => $filter) {
637 637
                 if (is_array($filter) && $filter[0] instanceof $class) {
638 638
                     unset($this->filters[$index]);
@@ -755,7 +755,7 @@  discard block
 block discarded – undo
755 755
     public function getCacheDir()
756 756
     {
757 757
         if ($this->cacheDir === null) {
758
-            $this->setCacheDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'cache' . DIRECTORY_SEPARATOR);
758
+            $this->setCacheDir(dirname(__DIR__).DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR);
759 759
         }
760 760
 
761 761
         return $this->cacheDir;
@@ -771,12 +771,12 @@  discard block
 block discarded – undo
771 771
      */
772 772
     public function setCacheDir($dir)
773 773
     {
774
-        $this->cacheDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
774
+        $this->cacheDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR;
775 775
         if (!file_exists($this->cacheDir)) {
776 776
             mkdir($this->cacheDir, 0777, true);
777 777
         }
778 778
         if (is_writable($this->cacheDir) === false) {
779
-            throw new Exception('The cache directory must be writable, chmod "' . $this->cacheDir . '" to make it writable');
779
+            throw new Exception('The cache directory must be writable, chmod "'.$this->cacheDir.'" to make it writable');
780 780
         }
781 781
     }
782 782
 
@@ -788,7 +788,7 @@  discard block
 block discarded – undo
788 788
     public function getCompileDir()
789 789
     {
790 790
         if ($this->compileDir === null) {
791
-            $this->setCompileDir(dirname(__DIR__) . DIRECTORY_SEPARATOR . 'compiled' . DIRECTORY_SEPARATOR);
791
+            $this->setCompileDir(dirname(__DIR__).DIRECTORY_SEPARATOR.'compiled'.DIRECTORY_SEPARATOR);
792 792
         }
793 793
 
794 794
         return $this->compileDir;
@@ -804,12 +804,12 @@  discard block
 block discarded – undo
804 804
      */
805 805
     public function setCompileDir($dir)
806 806
     {
807
-        $this->compileDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
807
+        $this->compileDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR;
808 808
         if (!file_exists($this->compileDir)) {
809 809
             mkdir($this->compileDir, 0777, true);
810 810
         }
811 811
         if (is_writable($this->compileDir) === false) {
812
-            throw new Exception('The compile directory must be writable, chmod "' . $this->compileDir . '" to make it writable');
812
+            throw new Exception('The compile directory must be writable, chmod "'.$this->compileDir.'" to make it writable');
813 813
         }
814 814
     }
815 815
 
@@ -833,9 +833,9 @@  discard block
 block discarded – undo
833 833
      */
834 834
     public function setTemplateDir($dir)
835 835
     {
836
-        $tmpDir = rtrim($dir, '/\\') . DIRECTORY_SEPARATOR;
836
+        $tmpDir = rtrim($dir, '/\\').DIRECTORY_SEPARATOR;
837 837
         if (is_dir($tmpDir) === false) {
838
-            throw new Exception('The template directory: "' . $tmpDir . '" does not exists, create the directory or specify an other location !');
838
+            throw new Exception('The template directory: "'.$tmpDir.'" does not exists, create the directory or specify an other location !');
839 839
         }
840 840
         $this->templateDir[] = $tmpDir;
841 841
     }
@@ -859,7 +859,7 @@  discard block
 block discarded – undo
859 859
      */
860 860
     public function setCacheTime($seconds)
861 861
     {
862
-        $this->cacheTime = (int)$seconds;
862
+        $this->cacheTime = (int) $seconds;
863 863
     }
864 864
 
865 865
     /**
@@ -883,7 +883,7 @@  discard block
 block discarded – undo
883 883
      */
884 884
     public function setCharset($charset)
885 885
     {
886
-        $this->charset = strtolower((string)$charset);
886
+        $this->charset = strtolower((string) $charset);
887 887
     }
888 888
 
889 889
     /**
@@ -1020,11 +1020,11 @@  discard block
 block discarded – undo
1020 1020
     public function clearCache($olderThan = - 1)
1021 1021
     {
1022 1022
         $iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->getCacheDir()), \RecursiveIteratorIterator::SELF_FIRST);
1023
-        $expired  = time() - $olderThan;
1023
+        $expired  = time()-$olderThan;
1024 1024
         $count    = 0;
1025 1025
         foreach ($iterator as $file) {
1026 1026
             if ($file->isFile() && $file->getCTime() < $expired) {
1027
-                $count += unlink((string)$file) ? 1 : 0;
1027
+                $count += unlink((string) $file) ? 1 : 0;
1028 1028
             }
1029 1029
         }
1030 1030
 
@@ -1057,7 +1057,7 @@  discard block
 block discarded – undo
1057 1057
             return $class::templateFactory($this, $resourceId, $cacheTime, $cacheId, $compileId, $parentTemplate);
1058 1058
         }
1059 1059
 
1060
-        throw new Exception('Unknown resource type : ' . $resourceName);
1060
+        throw new Exception('Unknown resource type : '.$resourceName);
1061 1061
     }
1062 1062
 
1063 1063
     /**
@@ -1157,7 +1157,7 @@  discard block
 block discarded – undo
1157 1157
         if (!($tplIdentifier = $this->template->getResourceIdentifier())) {
1158 1158
             $tplIdentifier = $this->template->getResourceName();
1159 1159
         }
1160
-        trigger_error('Dwoo error (in ' . $tplIdentifier . ') : ' . $message, $level);
1160
+        trigger_error('Dwoo error (in '.$tplIdentifier.') : '.$message, $level);
1161 1161
     }
1162 1162
 
1163 1163
     /**
@@ -1174,8 +1174,8 @@  discard block
 block discarded – undo
1174 1174
             $class = $this->plugins[$blockName]['class'];
1175 1175
         } else {
1176 1176
             $class = current(array_filter([
1177
-                'Plugin' . self::toCamelCase($blockName),
1178
-                self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin' . self::toCamelCase($blockName)
1177
+                'Plugin'.self::toCamelCase($blockName),
1178
+                self::NAMESPACE_PLUGINS_BLOCKS.'Plugin'.self::toCamelCase($blockName)
1179 1179
             ], 'class_exists'));
1180 1180
         }
1181 1181
 
@@ -1239,7 +1239,7 @@  discard block
 block discarded – undo
1239 1239
     {
1240 1240
         $index = array_search($block, $this->stack, true);
1241 1241
         if ($index !== false && $index > 0) {
1242
-            return $this->stack[$index - 1];
1242
+            return $this->stack[$index-1];
1243 1243
         }
1244 1244
 
1245 1245
         return false;
@@ -1257,7 +1257,7 @@  discard block
 block discarded – undo
1257 1257
         if (isset($this->plugins[$type])) {
1258 1258
             $type = $this->plugins[$type]['class'];
1259 1259
         } else {
1260
-            $type = self::NAMESPACE_PLUGINS_BLOCKS . 'Plugin_' . str_replace(self::NAMESPACE_PLUGINS_BLOCKS.'Plugin',
1260
+            $type = self::NAMESPACE_PLUGINS_BLOCKS.'Plugin_'.str_replace(self::NAMESPACE_PLUGINS_BLOCKS.'Plugin',
1261 1261
                     '', $type);
1262 1262
         }
1263 1263
 
@@ -1335,7 +1335,7 @@  discard block
 block discarded – undo
1335 1335
 
1336 1336
                 if (is_string($callback) === false) {
1337 1337
                     while (($i = array_shift($keys)) !== null) {
1338
-                        $out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1338
+                        $out[] = call_user_func_array($callback, array(1 => $items[$i])+$params);
1339 1339
                     }
1340 1340
                 } elseif ($cnt === 1) {
1341 1341
                     while (($i = array_shift($keys)) !== null) {
@@ -1351,7 +1351,7 @@  discard block
 block discarded – undo
1351 1351
                     }
1352 1352
                 } else {
1353 1353
                     while (($i = array_shift($keys)) !== null) {
1354
-                        $out[] = call_user_func_array($callback, array(1 => $items[$i]) + $params);
1354
+                        $out[] = call_user_func_array($callback, array(1 => $items[$i])+$params);
1355 1355
                     }
1356 1356
                 }
1357 1357
             } else {
@@ -1360,7 +1360,7 @@  discard block
 block discarded – undo
1360 1360
 
1361 1361
                 if (is_string($callback) === false) {
1362 1362
                     while (($i = array_shift($keys)) !== null) {
1363
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1363
+                        $out[] = call_user_func_array($callback, array($items[$i])+$params);
1364 1364
                     }
1365 1365
                 } elseif ($cnt === 1) {
1366 1366
                     while (($i = array_shift($keys)) !== null) {
@@ -1380,7 +1380,7 @@  discard block
 block discarded – undo
1380 1380
                     }
1381 1381
                 } else {
1382 1382
                     while (($i = array_shift($keys)) !== null) {
1383
-                        $out[] = call_user_func_array($callback, array($items[$i]) + $params);
1383
+                        $out[] = call_user_func_array($callback, array($items[$i])+$params);
1384 1384
                     }
1385 1385
                 }
1386 1386
             }
@@ -1450,7 +1450,7 @@  discard block
 block discarded – undo
1450 1450
         $tree = $this->scopeTree;
1451 1451
         $cur  = $this->data;
1452 1452
 
1453
-        while ($parentLevels -- !== 0) {
1453
+        while ($parentLevels-- !== 0) {
1454 1454
             array_pop($tree);
1455 1455
         }
1456 1456
 
@@ -1488,7 +1488,7 @@  discard block
 block discarded – undo
1488 1488
                 } elseif ($varstr === '__' || $varstr === '_root') {
1489 1489
                     return $this->data;
1490 1490
                 } elseif ($varstr === '_' || $varstr === '_parent') {
1491
-                    $varstr = '.' . $varstr;
1491
+                    $varstr = '.'.$varstr;
1492 1492
                     $tree   = $this->scopeTree;
1493 1493
                     $cur    = $this->data;
1494 1494
                     array_pop($tree);
@@ -1514,7 +1514,7 @@  discard block
 block discarded – undo
1514 1514
             }
1515 1515
 
1516 1516
             if (substr($varstr, 0, 1) === '.') {
1517
-                $varstr = 'dwoo' . $varstr;
1517
+                $varstr = 'dwoo'.$varstr;
1518 1518
             }
1519 1519
 
1520 1520
             preg_match_all('#(\[|->|\.)?((?:[^.[\]-]|-(?!>))+)\]?#i', $varstr, $m);
@@ -1621,7 +1621,7 @@  discard block
 block discarded – undo
1621 1621
     public function assignInScope($value, $scope)
1622 1622
     {
1623 1623
         if (!is_string($scope)) {
1624
-            $this->triggerError('Assignments must be done into strings, (' . gettype($scope) . ') ' . var_export($scope, true) . ' given', E_USER_ERROR);
1624
+            $this->triggerError('Assignments must be done into strings, ('.gettype($scope).') '.var_export($scope, true).' given', E_USER_ERROR);
1625 1625
         }
1626 1626
         if (strstr($scope, '.') === false && strstr($scope, '->') === false) {
1627 1627
             $this->scope[$scope] = $value;
@@ -1772,7 +1772,7 @@  discard block
 block discarded – undo
1772 1772
     {
1773 1773
         $proxy = $this->getPluginProxy();
1774 1774
         if (!$proxy) {
1775
-            throw new Exception('Call to undefined method ' . __CLASS__ . '::' . $method . '()');
1775
+            throw new Exception('Call to undefined method '.__CLASS__.'::'.$method.'()');
1776 1776
         }
1777 1777
 
1778 1778
         return call_user_func_array($proxy->getCallback($method), $args);
Please login to merge, or discard this patch.
lib/Dwoo/Template/File.php 1 patch
Indentation   +224 added lines, -224 removed lines patch added patch discarded remove patch
@@ -30,249 +30,249 @@
 block discarded – undo
30 30
  */
31 31
 class File extends Str
32 32
 {
33
-    /**
34
-     * Template filename.
35
-     *
36
-     * @var string
37
-     */
38
-    protected $file;
33
+	/**
34
+	 * Template filename.
35
+	 *
36
+	 * @var string
37
+	 */
38
+	protected $file;
39 39
 
40
-    /**
41
-     * Include path(s) to look into to find this template.
42
-     *
43
-     * @var array
44
-     */
45
-    protected $includePath = array();
40
+	/**
41
+	 * Include path(s) to look into to find this template.
42
+	 *
43
+	 * @var array
44
+	 */
45
+	protected $includePath = array();
46 46
 
47
-    /**
48
-     * Resolved path cache when looking for a file in multiple include paths.
49
-     * this is reset when the include path is changed
50
-     *
51
-     * @var string
52
-     */
53
-    protected $resolvedPath = null;
47
+	/**
48
+	 * Resolved path cache when looking for a file in multiple include paths.
49
+	 * this is reset when the include path is changed
50
+	 *
51
+	 * @var string
52
+	 */
53
+	protected $resolvedPath = null;
54 54
 
55
-    /**
56
-     * Creates a template from a file.
57
-     *
58
-     * @param string $file        the path to the template file, make sure it exists
59
-     * @param int    $cacheTime   duration of the cache validity for this template,
60
-     *                            if null it defaults to the Dwoo instance that will
61
-     *                            render this template
62
-     * @param string $cacheId     the unique cache identifier of this page or anything else that
63
-     *                            makes this template's content unique, if null it defaults
64
-     *                            to the current url
65
-     * @param string $compileId   the unique compiled identifier, which is used to distinguish this
66
-     *                            template from others, if null it defaults to the filename+bits of the path
67
-     * @param mixed  $includePath a string for a single path to look into for the given file, or an array of paths
68
-     */
69
-    public function __construct($file, $cacheTime = null, $cacheId = null, $compileId = null, $includePath = array())
70
-    {
71
-        parent::__construct($file, $cacheTime, $cacheId, $compileId);
72
-        $this->template = null;
73
-        $this->file     = $file;
74
-        $this->name     = basename($file);
75
-        $this->setIncludePath($includePath);
76
-        $this->compileId = $this->getResourceIdentifier();
77
-    }
55
+	/**
56
+	 * Creates a template from a file.
57
+	 *
58
+	 * @param string $file        the path to the template file, make sure it exists
59
+	 * @param int    $cacheTime   duration of the cache validity for this template,
60
+	 *                            if null it defaults to the Dwoo instance that will
61
+	 *                            render this template
62
+	 * @param string $cacheId     the unique cache identifier of this page or anything else that
63
+	 *                            makes this template's content unique, if null it defaults
64
+	 *                            to the current url
65
+	 * @param string $compileId   the unique compiled identifier, which is used to distinguish this
66
+	 *                            template from others, if null it defaults to the filename+bits of the path
67
+	 * @param mixed  $includePath a string for a single path to look into for the given file, or an array of paths
68
+	 */
69
+	public function __construct($file, $cacheTime = null, $cacheId = null, $compileId = null, $includePath = array())
70
+	{
71
+		parent::__construct($file, $cacheTime, $cacheId, $compileId);
72
+		$this->template = null;
73
+		$this->file     = $file;
74
+		$this->name     = basename($file);
75
+		$this->setIncludePath($includePath);
76
+		$this->compileId = $this->getResourceIdentifier();
77
+	}
78 78
 
79
-    /**
80
-     * Sets the include path(s) to where the given template filename must be looked up.
81
-     *
82
-     * @param mixed $paths the path to look into, can be string for a single path or an array of paths
83
-     */
84
-    public function setIncludePath($paths)
85
-    {
86
-        if ($paths == null) {
87
-          $paths = array();
88
-        } elseif (is_array($paths) === false) {
89
-            $paths = array($paths);
90
-        }
79
+	/**
80
+	 * Sets the include path(s) to where the given template filename must be looked up.
81
+	 *
82
+	 * @param mixed $paths the path to look into, can be string for a single path or an array of paths
83
+	 */
84
+	public function setIncludePath($paths)
85
+	{
86
+		if ($paths == null) {
87
+		  $paths = array();
88
+		} elseif (is_array($paths) === false) {
89
+			$paths = array($paths);
90
+		}
91 91
 
92
-        $this->includePath  = $paths;
93
-        $this->resolvedPath = null;
94
-    }
92
+		$this->includePath  = $paths;
93
+		$this->resolvedPath = null;
94
+	}
95 95
 
96
-    /**
97
-     * Return the current include path(s).
98
-     *
99
-     * @return array
100
-     */
101
-    public function getIncludePath()
102
-    {
103
-        return $this->includePath;
104
-    }
96
+	/**
97
+	 * Return the current include path(s).
98
+	 *
99
+	 * @return array
100
+	 */
101
+	public function getIncludePath()
102
+	{
103
+		return $this->includePath;
104
+	}
105 105
 
106
-    /**
107
-     * Checks if compiled file is valid (exists and it's the modification is greater or
108
-     * equal to the modification time of the template file).
109
-     *
110
-     * @param string file
111
-     *
112
-     * @return bool True cache file existance and it's modification time
113
-     */
114
-    protected function isValidCompiledFile($file)
115
-    {
116
-        return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file);
117
-    }
106
+	/**
107
+	 * Checks if compiled file is valid (exists and it's the modification is greater or
108
+	 * equal to the modification time of the template file).
109
+	 *
110
+	 * @param string file
111
+	 *
112
+	 * @return bool True cache file existance and it's modification time
113
+	 */
114
+	protected function isValidCompiledFile($file)
115
+	{
116
+		return parent::isValidCompiledFile($file) && (int)$this->getUid() <= filemtime($file);
117
+	}
118 118
 
119
-    /**
120
-     * Returns the template source of this template.
121
-     *
122
-     * @return string
123
-     */
124
-    public function getSource()
125
-    {
126
-        return file_get_contents($this->getResourceIdentifier());
127
-    }
119
+	/**
120
+	 * Returns the template source of this template.
121
+	 *
122
+	 * @return string
123
+	 */
124
+	public function getSource()
125
+	{
126
+		return file_get_contents($this->getResourceIdentifier());
127
+	}
128 128
 
129
-    /**
130
-     * Returns the resource name for this template class.
131
-     *
132
-     * @return string
133
-     */
134
-    public function getResourceName()
135
-    {
136
-        return 'file';
137
-    }
129
+	/**
130
+	 * Returns the resource name for this template class.
131
+	 *
132
+	 * @return string
133
+	 */
134
+	public function getResourceName()
135
+	{
136
+		return 'file';
137
+	}
138 138
 
139
-    /**
140
-     * Returns this template's source filename.
141
-     *
142
-     * @return string
143
-     * @throws DwooException
144
-     */
145
-    public function getResourceIdentifier()
146
-    {
147
-        if ($this->resolvedPath !== null) {
148
-            return $this->resolvedPath;
149
-        } elseif (array_filter($this->getIncludePath()) == array()) {
150
-            return $this->file;
151
-        } else {
152
-            foreach ($this->getIncludePath() as $path) {
153
-                $path = rtrim($path, DIRECTORY_SEPARATOR);
154
-                if (file_exists($path . DIRECTORY_SEPARATOR . $this->file) === true) {
155
-                    return $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file;
156
-                }
157
-            }
139
+	/**
140
+	 * Returns this template's source filename.
141
+	 *
142
+	 * @return string
143
+	 * @throws DwooException
144
+	 */
145
+	public function getResourceIdentifier()
146
+	{
147
+		if ($this->resolvedPath !== null) {
148
+			return $this->resolvedPath;
149
+		} elseif (array_filter($this->getIncludePath()) == array()) {
150
+			return $this->file;
151
+		} else {
152
+			foreach ($this->getIncludePath() as $path) {
153
+				$path = rtrim($path, DIRECTORY_SEPARATOR);
154
+				if (file_exists($path . DIRECTORY_SEPARATOR . $this->file) === true) {
155
+					return $this->resolvedPath = $path . DIRECTORY_SEPARATOR . $this->file;
156
+				}
157
+			}
158 158
 
159
-            throw new DwooException('Template "' . $this->file . '" could not be found in any of your include path(s)');
160
-        }
161
-    }
159
+			throw new DwooException('Template "' . $this->file . '" could not be found in any of your include path(s)');
160
+		}
161
+	}
162 162
 
163
-    /**
164
-     * Returns an unique value identifying the current version of this template,
165
-     * in this case it's the unix timestamp of the last modification.
166
-     *
167
-     * @return string
168
-     */
169
-    public function getUid()
170
-    {
171
-        return (string)filemtime($this->getResourceIdentifier());
172
-    }
163
+	/**
164
+	 * Returns an unique value identifying the current version of this template,
165
+	 * in this case it's the unix timestamp of the last modification.
166
+	 *
167
+	 * @return string
168
+	 */
169
+	public function getUid()
170
+	{
171
+		return (string)filemtime($this->getResourceIdentifier());
172
+	}
173 173
 
174
-    /**
175
-     * Returns a new template object from the given include name, null if no include is
176
-     * possible (resource not found), or false if include is not permitted by this resource type.
177
-     *
178
-     * @param Core      $core           the dwoo instance requiring it
179
-     * @param mixed     $resourceId     the filename (relative to this template's dir) of the template to
180
-     *                                  include
181
-     * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults
182
-     *                                  to the Dwoo instance that will render this template if null it
183
-     *                                  defaults to the Dwoo instance that will render this template if null
184
-     *                                  it defaults to the Dwoo instance that will render this template
185
-     * @param string    $cacheId        the unique cache identifier of this page or anything else that makes
186
-     *                                  this template's content unique, if null it defaults to the current
187
-     *                                  url makes this template's content unique, if null it defaults to the
188
-     *                                  current url makes this template's content unique, if null it defaults
189
-     *                                  to the current url
190
-     * @param string    $compileId      the unique compiled identifier, which is used to distinguish this
191
-     *                                  template from others, if null it defaults to the filename+bits of the
192
-     *                                  path template from others, if null it defaults to the filename+bits
193
-     *                                  of the path template from others, if null it defaults to the
194
-     *                                  filename+bits of the path
195
-     * @param ITemplate $parentTemplate the template that is requesting a new template object (through an
196
-     *                                  include, extends or any other plugin) an include, extends or any
197
-     *                                  other plugin) an include, extends or any other plugin)
198
-     *
199
-     * @return TemplateFile|null
200
-     * @throws DwooException
201
-     * @throws SecurityException
202
-     */
203
-    public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
204
-                                           $compileId = null, ITemplate $parentTemplate = null)
205
-    {
206
-        if (DIRECTORY_SEPARATOR === '\\') {
207
-            $resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array(
208
-                '\\t',
209
-                '\\n',
210
-                '\\r',
211
-                '\\f',
212
-                '\\v'
213
-            ), $resourceId);
214
-        }
215
-        $resourceId = strtr($resourceId, '\\', '/');
174
+	/**
175
+	 * Returns a new template object from the given include name, null if no include is
176
+	 * possible (resource not found), or false if include is not permitted by this resource type.
177
+	 *
178
+	 * @param Core      $core           the dwoo instance requiring it
179
+	 * @param mixed     $resourceId     the filename (relative to this template's dir) of the template to
180
+	 *                                  include
181
+	 * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults
182
+	 *                                  to the Dwoo instance that will render this template if null it
183
+	 *                                  defaults to the Dwoo instance that will render this template if null
184
+	 *                                  it defaults to the Dwoo instance that will render this template
185
+	 * @param string    $cacheId        the unique cache identifier of this page or anything else that makes
186
+	 *                                  this template's content unique, if null it defaults to the current
187
+	 *                                  url makes this template's content unique, if null it defaults to the
188
+	 *                                  current url makes this template's content unique, if null it defaults
189
+	 *                                  to the current url
190
+	 * @param string    $compileId      the unique compiled identifier, which is used to distinguish this
191
+	 *                                  template from others, if null it defaults to the filename+bits of the
192
+	 *                                  path template from others, if null it defaults to the filename+bits
193
+	 *                                  of the path template from others, if null it defaults to the
194
+	 *                                  filename+bits of the path
195
+	 * @param ITemplate $parentTemplate the template that is requesting a new template object (through an
196
+	 *                                  include, extends or any other plugin) an include, extends or any
197
+	 *                                  other plugin) an include, extends or any other plugin)
198
+	 *
199
+	 * @return TemplateFile|null
200
+	 * @throws DwooException
201
+	 * @throws SecurityException
202
+	 */
203
+	public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
204
+										   $compileId = null, ITemplate $parentTemplate = null)
205
+	{
206
+		if (DIRECTORY_SEPARATOR === '\\') {
207
+			$resourceId = str_replace(array("\t", "\n", "\r", "\f", "\v"), array(
208
+				'\\t',
209
+				'\\n',
210
+				'\\r',
211
+				'\\f',
212
+				'\\v'
213
+			), $resourceId);
214
+		}
215
+		$resourceId = strtr($resourceId, '\\', '/');
216 216
 
217
-        $includePath = null;
217
+		$includePath = null;
218 218
 
219
-        if (file_exists($resourceId) === false) {
220
-            if ($parentTemplate === null) {
221
-                $parentTemplate = $core->getTemplate();
222
-            }
223
-            if ($parentTemplate instanceof self) {
224
-                if ($includePath = $parentTemplate->getIncludePath()) {
225
-                    if (strstr($resourceId, '../')) {
226
-                        throw new DwooException('When using an include path you can not reference a template into a parent directory (using ../)');
227
-                    }
228
-                } else {
229
-                    $resourceId = dirname($parentTemplate->getResourceIdentifier()) . DIRECTORY_SEPARATOR . $resourceId;
230
-                    if (file_exists($resourceId) === false) {
231
-                        return null;
232
-                    }
233
-                }
234
-            } else {
235
-                return null;
236
-            }
237
-        }
219
+		if (file_exists($resourceId) === false) {
220
+			if ($parentTemplate === null) {
221
+				$parentTemplate = $core->getTemplate();
222
+			}
223
+			if ($parentTemplate instanceof self) {
224
+				if ($includePath = $parentTemplate->getIncludePath()) {
225
+					if (strstr($resourceId, '../')) {
226
+						throw new DwooException('When using an include path you can not reference a template into a parent directory (using ../)');
227
+					}
228
+				} else {
229
+					$resourceId = dirname($parentTemplate->getResourceIdentifier()) . DIRECTORY_SEPARATOR . $resourceId;
230
+					if (file_exists($resourceId) === false) {
231
+						return null;
232
+					}
233
+				}
234
+			} else {
235
+				return null;
236
+			}
237
+		}
238 238
 
239
-        if ($policy = $core->getSecurityPolicy()) {
240
-            while (true) {
241
-                if (preg_match('{^([a-z]+?)://}i', $resourceId)) {
242
-                    throw new SecurityException('The security policy prevents you to read files from external sources : <em>' . $resourceId . '</em>.');
243
-                }
239
+		if ($policy = $core->getSecurityPolicy()) {
240
+			while (true) {
241
+				if (preg_match('{^([a-z]+?)://}i', $resourceId)) {
242
+					throw new SecurityException('The security policy prevents you to read files from external sources : <em>' . $resourceId . '</em>.');
243
+				}
244 244
 
245
-                if ($includePath) {
246
-                    break;
247
-                }
245
+				if ($includePath) {
246
+					break;
247
+				}
248 248
 
249
-                $resourceId = realpath($resourceId);
250
-                $dirs       = $policy->getAllowedDirectories();
251
-                foreach ($dirs as $dir => $dummy) {
252
-                    if (strpos($resourceId, $dir) === 0) {
253
-                        break 2;
254
-                    }
255
-                }
256
-                throw new SecurityException('The security policy prevents you to read <em>' . $resourceId . '</em>');
257
-            }
258
-        }
249
+				$resourceId = realpath($resourceId);
250
+				$dirs       = $policy->getAllowedDirectories();
251
+				foreach ($dirs as $dir => $dummy) {
252
+					if (strpos($resourceId, $dir) === 0) {
253
+						break 2;
254
+					}
255
+				}
256
+				throw new SecurityException('The security policy prevents you to read <em>' . $resourceId . '</em>');
257
+			}
258
+		}
259 259
 
260
-        $class = 'Dwoo\Template\File';
261
-        if ($parentTemplate) {
262
-            $class = get_class($parentTemplate);
263
-        }
260
+		$class = 'Dwoo\Template\File';
261
+		if ($parentTemplate) {
262
+			$class = get_class($parentTemplate);
263
+		}
264 264
 
265
-        return new $class($resourceId, $cacheTime, $cacheId, $compileId, $includePath);
266
-    }
265
+		return new $class($resourceId, $cacheTime, $cacheId, $compileId, $includePath);
266
+	}
267 267
 
268
-    /**
269
-     * Returns some php code that will check if this template has been modified or not.
270
-     * if the function returns null, the template will be instanciated and then the Uid checked
271
-     *
272
-     * @return string
273
-     */
274
-    public function getIsModifiedCode()
275
-    {
276
-        return '"' . $this->getUid() . '" == filemtime(' . var_export($this->getResourceIdentifier(), true) . ')';
277
-    }
268
+	/**
269
+	 * Returns some php code that will check if this template has been modified or not.
270
+	 * if the function returns null, the template will be instanciated and then the Uid checked
271
+	 *
272
+	 * @return string
273
+	 */
274
+	public function getIsModifiedCode()
275
+	{
276
+		return '"' . $this->getUid() . '" == filemtime(' . var_export($this->getResourceIdentifier(), true) . ')';
277
+	}
278 278
 }
Please login to merge, or discard this patch.
lib/Dwoo/Loader.php 2 patches
Indentation   +164 added lines, -164 removed lines patch added patch discarded remove patch
@@ -23,168 +23,168 @@
 block discarded – undo
23 23
  */
24 24
 class Loader implements ILoader
25 25
 {
26
-    /**
27
-     * Stores the plugin directories.
28
-     *
29
-     * @see addDirectory
30
-     * @var array
31
-     */
32
-    protected $paths = array();
33
-
34
-    /**
35
-     * Stores the plugins names/paths relationships
36
-     * don't edit this on your own, use addDirectory.
37
-     *
38
-     * @see addDirectory
39
-     * @var array
40
-     */
41
-    protected $classPath = array();
42
-
43
-    /**
44
-     * Path where class paths cache files are written.
45
-     *
46
-     * @var string
47
-     */
48
-    protected $cacheDir;
49
-
50
-    /**
51
-     * Path where builtin plugins are stored.
52
-     *
53
-     * @var string
54
-     */
55
-    protected $corePluginDir;
56
-
57
-    /**
58
-     * Loader constructor.
59
-     *
60
-     * @param $cacheDir
61
-     */
62
-    public function __construct($cacheDir)
63
-    {
64
-        $this->corePluginDir = __DIR__ . DIRECTORY_SEPARATOR . 'Plugins';
65
-        $this->cacheDir      = rtrim($cacheDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
66
-
67
-        // include class paths or rebuild paths if the cache file isn't there
68
-        $cacheFile = $this->cacheDir . 'classpath.cache.d' . Core::RELEASE_TAG . '.php';
69
-
70
-        $chachedClassPath = null;
71
-
72
-        if (file_exists($cacheFile)) {
73
-
74
-            $chachedClassPath = unserialize(file_get_contents($cacheFile));
75
-
76
-            if (is_array($chachedClassPath)) {
77
-                $this->classPath = $chachedClassPath + $this->classPath;
78
-            }
79
-        }
80
-
81
-        if (!is_array($chachedClassPath)) {
82
-            $this->rebuildClassPathCache($this->corePluginDir, $cacheFile);
83
-        }
84
-    }
85
-
86
-    /**
87
-     * Rebuilds class paths, scans the given directory recursively and saves all paths in the given file.
88
-     *
89
-     * @param string         $path      the plugin path to scan
90
-     * @param string|boolean $cacheFile the file where to store the plugin paths cache, it will be overwritten
91
-     *
92
-     * @throws Exception
93
-     */
94
-    protected function rebuildClassPathCache($path, $cacheFile)
95
-    {
96
-        $tmp = array();
97
-        if ($cacheFile !== false) {
98
-            $tmp             = $this->classPath;
99
-            $this->classPath = array();
100
-        }
101
-
102
-        // iterates over all files/folders
103
-        foreach (new \DirectoryIterator($path) as $fileInfo) {
104
-            if (!$fileInfo->isDot()) {
105
-                if ($fileInfo->isDir()) {
106
-                    $this->rebuildClassPathCache($fileInfo->getPathname(), false);
107
-                } else {
108
-                    $this->classPath[$fileInfo->getBasename('.php')] = $fileInfo->getPathname();
109
-                }
110
-            }
111
-        }
112
-
113
-        // save in file if it's the first call (not recursed)
114
-        if ($cacheFile !== false) {
115
-            if (!file_put_contents($cacheFile, serialize($this->classPath), LOCK_EX)) {
116
-                throw new Exception('Could not write into ' . $cacheFile . ', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()');
117
-            }
118
-            $this->classPath += $tmp;
119
-        }
120
-    }
121
-
122
-    /**
123
-     * Loads a plugin file.
124
-     *
125
-     * @param string $class       the plugin name, without the `Plugin` prefix
126
-     * @param bool   $forceRehash if true, the class path caches will be rebuilt if the plugin is not found, in case it
127
-     *                            has just been added, defaults to true
128
-     *
129
-     * @throws Exception
130
-     */
131
-    public function loadPlugin($class, $forceRehash = true)
132
-    {
133
-        /**
134
-         * An unknown class was requested (maybe newly added) or the
135
-         * include failed so we rebuild the cache. include() will fail
136
-         * with an uncatchable error if the file doesn't exist, which
137
-         * usually means that the cache is stale and must be rebuilt,
138
-         * so we check for that before trying to include() the plugin.
139
-         */
140
-        if ((!isset($this->classPath[$class]) || !is_readable($this->classPath[$class])) || (!isset
141
-                ($this->classPath[$class . 'Compile']) || !is_readable($this->classPath[$class . 'Compile']))) {
142
-            if ($forceRehash) {
143
-                $this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir . 'classpath.cache.d' .
144
-                    Core::RELEASE_TAG . '.php');
145
-                foreach ($this->paths as $path => $file) {
146
-                    $this->rebuildClassPathCache($path, $file);
147
-                }
148
-                if (isset($this->classPath[$class])) {
149
-                    include_once $this->classPath[$class];
150
-                } elseif (isset($this->classPath[$class . 'Compile'])) {
151
-                    include_once $this->classPath[$class . 'Compile'];
152
-                } else {
153
-                    throw new Exception('Plugin "' . $class . '" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
154
-                }
155
-            } else {
156
-                throw new Exception('Plugin "' . $class . '" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
157
-            }
158
-        }
159
-    }
160
-
161
-    /**
162
-     * Adds a plugin directory, the plugins found in the new plugin directory
163
-     * will take precedence over the other directories (including the default
164
-     * dwoo plugin directory), you can use this for example to override plugins
165
-     * in a specific directory for a specific application while keeping all your
166
-     * usual plugins in the same place for all applications.
167
-     * TOCOM don't forget that php functions overrides are not rehashed so you
168
-     * need to clear the classpath caches by hand when adding those.
169
-     *
170
-     * @param string $pluginDirectory the plugin path to scan
171
-     *
172
-     * @throws Exception
173
-     */
174
-    public function addDirectory($pluginDirectory)
175
-    {
176
-        $pluginDir = realpath($pluginDirectory);
177
-        if (!$pluginDir) {
178
-            throw new Exception('Plugin directory does not exist or can not be read : ' . $pluginDirectory);
179
-        }
180
-        $cacheFile = $this->cacheDir . 'classpath-' . substr(strtr($pluginDir, '/\\:' . PATH_SEPARATOR, '----'),
181
-                strlen($pluginDir) > 80 ? - 80 : 0) . '.d' . Core::RELEASE_TAG . '.php';
182
-        $this->paths[$pluginDir] = $cacheFile;
183
-        if (file_exists($cacheFile)) {
184
-            $classpath       = file_get_contents($cacheFile);
185
-            $this->classPath = unserialize($classpath) + $this->classPath;
186
-        } else {
187
-            $this->rebuildClassPathCache($pluginDir, $cacheFile);
188
-        }
189
-    }
26
+	/**
27
+	 * Stores the plugin directories.
28
+	 *
29
+	 * @see addDirectory
30
+	 * @var array
31
+	 */
32
+	protected $paths = array();
33
+
34
+	/**
35
+	 * Stores the plugins names/paths relationships
36
+	 * don't edit this on your own, use addDirectory.
37
+	 *
38
+	 * @see addDirectory
39
+	 * @var array
40
+	 */
41
+	protected $classPath = array();
42
+
43
+	/**
44
+	 * Path where class paths cache files are written.
45
+	 *
46
+	 * @var string
47
+	 */
48
+	protected $cacheDir;
49
+
50
+	/**
51
+	 * Path where builtin plugins are stored.
52
+	 *
53
+	 * @var string
54
+	 */
55
+	protected $corePluginDir;
56
+
57
+	/**
58
+	 * Loader constructor.
59
+	 *
60
+	 * @param $cacheDir
61
+	 */
62
+	public function __construct($cacheDir)
63
+	{
64
+		$this->corePluginDir = __DIR__ . DIRECTORY_SEPARATOR . 'Plugins';
65
+		$this->cacheDir      = rtrim($cacheDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
66
+
67
+		// include class paths or rebuild paths if the cache file isn't there
68
+		$cacheFile = $this->cacheDir . 'classpath.cache.d' . Core::RELEASE_TAG . '.php';
69
+
70
+		$chachedClassPath = null;
71
+
72
+		if (file_exists($cacheFile)) {
73
+
74
+			$chachedClassPath = unserialize(file_get_contents($cacheFile));
75
+
76
+			if (is_array($chachedClassPath)) {
77
+				$this->classPath = $chachedClassPath + $this->classPath;
78
+			}
79
+		}
80
+
81
+		if (!is_array($chachedClassPath)) {
82
+			$this->rebuildClassPathCache($this->corePluginDir, $cacheFile);
83
+		}
84
+	}
85
+
86
+	/**
87
+	 * Rebuilds class paths, scans the given directory recursively and saves all paths in the given file.
88
+	 *
89
+	 * @param string         $path      the plugin path to scan
90
+	 * @param string|boolean $cacheFile the file where to store the plugin paths cache, it will be overwritten
91
+	 *
92
+	 * @throws Exception
93
+	 */
94
+	protected function rebuildClassPathCache($path, $cacheFile)
95
+	{
96
+		$tmp = array();
97
+		if ($cacheFile !== false) {
98
+			$tmp             = $this->classPath;
99
+			$this->classPath = array();
100
+		}
101
+
102
+		// iterates over all files/folders
103
+		foreach (new \DirectoryIterator($path) as $fileInfo) {
104
+			if (!$fileInfo->isDot()) {
105
+				if ($fileInfo->isDir()) {
106
+					$this->rebuildClassPathCache($fileInfo->getPathname(), false);
107
+				} else {
108
+					$this->classPath[$fileInfo->getBasename('.php')] = $fileInfo->getPathname();
109
+				}
110
+			}
111
+		}
112
+
113
+		// save in file if it's the first call (not recursed)
114
+		if ($cacheFile !== false) {
115
+			if (!file_put_contents($cacheFile, serialize($this->classPath), LOCK_EX)) {
116
+				throw new Exception('Could not write into ' . $cacheFile . ', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()');
117
+			}
118
+			$this->classPath += $tmp;
119
+		}
120
+	}
121
+
122
+	/**
123
+	 * Loads a plugin file.
124
+	 *
125
+	 * @param string $class       the plugin name, without the `Plugin` prefix
126
+	 * @param bool   $forceRehash if true, the class path caches will be rebuilt if the plugin is not found, in case it
127
+	 *                            has just been added, defaults to true
128
+	 *
129
+	 * @throws Exception
130
+	 */
131
+	public function loadPlugin($class, $forceRehash = true)
132
+	{
133
+		/**
134
+		 * An unknown class was requested (maybe newly added) or the
135
+		 * include failed so we rebuild the cache. include() will fail
136
+		 * with an uncatchable error if the file doesn't exist, which
137
+		 * usually means that the cache is stale and must be rebuilt,
138
+		 * so we check for that before trying to include() the plugin.
139
+		 */
140
+		if ((!isset($this->classPath[$class]) || !is_readable($this->classPath[$class])) || (!isset
141
+				($this->classPath[$class . 'Compile']) || !is_readable($this->classPath[$class . 'Compile']))) {
142
+			if ($forceRehash) {
143
+				$this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir . 'classpath.cache.d' .
144
+					Core::RELEASE_TAG . '.php');
145
+				foreach ($this->paths as $path => $file) {
146
+					$this->rebuildClassPathCache($path, $file);
147
+				}
148
+				if (isset($this->classPath[$class])) {
149
+					include_once $this->classPath[$class];
150
+				} elseif (isset($this->classPath[$class . 'Compile'])) {
151
+					include_once $this->classPath[$class . 'Compile'];
152
+				} else {
153
+					throw new Exception('Plugin "' . $class . '" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
154
+				}
155
+			} else {
156
+				throw new Exception('Plugin "' . $class . '" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
157
+			}
158
+		}
159
+	}
160
+
161
+	/**
162
+	 * Adds a plugin directory, the plugins found in the new plugin directory
163
+	 * will take precedence over the other directories (including the default
164
+	 * dwoo plugin directory), you can use this for example to override plugins
165
+	 * in a specific directory for a specific application while keeping all your
166
+	 * usual plugins in the same place for all applications.
167
+	 * TOCOM don't forget that php functions overrides are not rehashed so you
168
+	 * need to clear the classpath caches by hand when adding those.
169
+	 *
170
+	 * @param string $pluginDirectory the plugin path to scan
171
+	 *
172
+	 * @throws Exception
173
+	 */
174
+	public function addDirectory($pluginDirectory)
175
+	{
176
+		$pluginDir = realpath($pluginDirectory);
177
+		if (!$pluginDir) {
178
+			throw new Exception('Plugin directory does not exist or can not be read : ' . $pluginDirectory);
179
+		}
180
+		$cacheFile = $this->cacheDir . 'classpath-' . substr(strtr($pluginDir, '/\\:' . PATH_SEPARATOR, '----'),
181
+				strlen($pluginDir) > 80 ? - 80 : 0) . '.d' . Core::RELEASE_TAG . '.php';
182
+		$this->paths[$pluginDir] = $cacheFile;
183
+		if (file_exists($cacheFile)) {
184
+			$classpath       = file_get_contents($cacheFile);
185
+			$this->classPath = unserialize($classpath) + $this->classPath;
186
+		} else {
187
+			$this->rebuildClassPathCache($pluginDir, $cacheFile);
188
+		}
189
+	}
190 190
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -61,11 +61,11 @@  discard block
 block discarded – undo
61 61
      */
62 62
     public function __construct($cacheDir)
63 63
     {
64
-        $this->corePluginDir = __DIR__ . DIRECTORY_SEPARATOR . 'Plugins';
65
-        $this->cacheDir      = rtrim($cacheDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
64
+        $this->corePluginDir = __DIR__.DIRECTORY_SEPARATOR.'Plugins';
65
+        $this->cacheDir      = rtrim($cacheDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
66 66
 
67 67
         // include class paths or rebuild paths if the cache file isn't there
68
-        $cacheFile = $this->cacheDir . 'classpath.cache.d' . Core::RELEASE_TAG . '.php';
68
+        $cacheFile = $this->cacheDir.'classpath.cache.d'.Core::RELEASE_TAG.'.php';
69 69
 
70 70
         $chachedClassPath = null;
71 71
 
@@ -74,7 +74,7 @@  discard block
 block discarded – undo
74 74
             $chachedClassPath = unserialize(file_get_contents($cacheFile));
75 75
 
76 76
             if (is_array($chachedClassPath)) {
77
-                $this->classPath = $chachedClassPath + $this->classPath;
77
+                $this->classPath = $chachedClassPath+$this->classPath;
78 78
             }
79 79
         }
80 80
 
@@ -113,7 +113,7 @@  discard block
 block discarded – undo
113 113
         // save in file if it's the first call (not recursed)
114 114
         if ($cacheFile !== false) {
115 115
             if (!file_put_contents($cacheFile, serialize($this->classPath), LOCK_EX)) {
116
-                throw new Exception('Could not write into ' . $cacheFile . ', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()');
116
+                throw new Exception('Could not write into '.$cacheFile.', either because the folder is not there (create it) or because of the chmod configuration (please ensure this directory is writable by php), alternatively you can change the directory used with $dwoo->setCompileDir() or provide a custom loader object with $dwoo->setLoader()');
117 117
             }
118 118
             $this->classPath += $tmp;
119 119
         }
@@ -138,22 +138,22 @@  discard block
 block discarded – undo
138 138
          * so we check for that before trying to include() the plugin.
139 139
          */
140 140
         if ((!isset($this->classPath[$class]) || !is_readable($this->classPath[$class])) || (!isset
141
-                ($this->classPath[$class . 'Compile']) || !is_readable($this->classPath[$class . 'Compile']))) {
141
+                ($this->classPath[$class.'Compile']) || !is_readable($this->classPath[$class.'Compile']))) {
142 142
             if ($forceRehash) {
143
-                $this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir . 'classpath.cache.d' .
144
-                    Core::RELEASE_TAG . '.php');
143
+                $this->rebuildClassPathCache($this->corePluginDir, $this->cacheDir.'classpath.cache.d'.
144
+                    Core::RELEASE_TAG.'.php');
145 145
                 foreach ($this->paths as $path => $file) {
146 146
                     $this->rebuildClassPathCache($path, $file);
147 147
                 }
148 148
                 if (isset($this->classPath[$class])) {
149 149
                     include_once $this->classPath[$class];
150
-                } elseif (isset($this->classPath[$class . 'Compile'])) {
151
-                    include_once $this->classPath[$class . 'Compile'];
150
+                } elseif (isset($this->classPath[$class.'Compile'])) {
151
+                    include_once $this->classPath[$class.'Compile'];
152 152
                 } else {
153
-                    throw new Exception('Plugin "' . $class . '" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
153
+                    throw new Exception('Plugin "'.$class.'" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
154 154
                 }
155 155
             } else {
156
-                throw new Exception('Plugin "' . $class . '" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
156
+                throw new Exception('Plugin "'.$class.'" can not be found, maybe you forgot to bind it if it\'s a custom plugin ?', E_USER_NOTICE);
157 157
             }
158 158
         }
159 159
     }
@@ -175,14 +175,14 @@  discard block
 block discarded – undo
175 175
     {
176 176
         $pluginDir = realpath($pluginDirectory);
177 177
         if (!$pluginDir) {
178
-            throw new Exception('Plugin directory does not exist or can not be read : ' . $pluginDirectory);
178
+            throw new Exception('Plugin directory does not exist or can not be read : '.$pluginDirectory);
179 179
         }
180
-        $cacheFile = $this->cacheDir . 'classpath-' . substr(strtr($pluginDir, '/\\:' . PATH_SEPARATOR, '----'),
181
-                strlen($pluginDir) > 80 ? - 80 : 0) . '.d' . Core::RELEASE_TAG . '.php';
180
+        $cacheFile = $this->cacheDir.'classpath-'.substr(strtr($pluginDir, '/\\:'.PATH_SEPARATOR, '----'),
181
+                strlen($pluginDir) > 80 ? -80 : 0).'.d'.Core::RELEASE_TAG.'.php';
182 182
         $this->paths[$pluginDir] = $cacheFile;
183 183
         if (file_exists($cacheFile)) {
184 184
             $classpath       = file_get_contents($cacheFile);
185
-            $this->classPath = unserialize($classpath) + $this->classPath;
185
+            $this->classPath = unserialize($classpath)+$this->classPath;
186 186
         } else {
187 187
             $this->rebuildClassPathCache($pluginDir, $cacheFile);
188 188
         }
Please login to merge, or discard this patch.