Autodoc
  • Namespace
  • Class
  • Tree

Namespaces

  • BlueTihi
    • Context
  • Brickrouge
    • Element
      • Nodes
    • Renderer
    • Widget
  • ICanBoogie
    • ActiveRecord
    • AutoConfig
    • CLDR
    • Composer
    • Core
    • Event
    • Exception
    • HTTP
      • Dispatcher
      • Request
    • I18n
      • Translator
    • Mailer
    • Modules
      • Taxonomy
        • Support
      • Thumbnailer
        • Versions
    • Object
    • Operation
      • Dispatcher
    • Prototype
    • Routes
    • Routing
      • Dispatcher
    • Session
  • Icybee
    • ActiveRecord
      • Model
    • ConfigOperation
    • Document
    • EditBlock
    • Element
      • ActionbarContextual
      • ActionbarSearch
      • ActionbarToolbar
    • FormBlock
    • Installer
    • ManageBlock
    • Modules
      • Articles
      • Cache
        • Collection
        • ManageBlock
      • Comments
        • ManageBlock
      • Contents
        • ManageBlock
      • Dashboard
      • Editor
        • Collection
      • Files
        • File
        • ManageBlock
      • Forms
        • Form
        • ManageBlock
      • I18n
      • Images
        • ManageBlock
      • Members
      • Modules
        • ManageBlock
      • Nodes
        • ManageBlock
        • Module
      • Pages
        • BreadcrumbElement
        • LanguagesElement
        • ManageBlock
        • NavigationBranchElement
        • NavigationElement
        • Page
        • PageController
      • Registry
      • Search
      • Seo
      • Sites
        • ManageBlock
      • Taxonomy
        • Terms
          • ManageBlock
        • Vocabulary
          • ManageBlock
      • Users
        • ManageBlock
        • NonceLogin
        • Roles
      • Views
        • ActiveRecordProvider
        • Collection
        • View
    • Operation
      • ActiveRecord
      • Constructor
      • Module
      • Widget
    • Rendering
  • None
  • Patron
  • PHP

Classes

  • Compiler
  • ControlNode
  • Engine
  • EvaluateNode
  • ExpressionNode
  • Hook
  • Hooks
  • HTMLParser
  • Node
  • Template
  • TextHole
  • TextNode
  • TranslateNode
  • URLNode

Functions

  • by_columns
  • render
  • tr
  1 <?php
  2 
  3 /*
  4  * This file is part of the Patron package.
  5  *
  6  * (c) Olivier Laviale <olivier.laviale@gmail.com>
  7  *
  8  * For the full copyright and license information, please view the LICENSE
  9  * file that was distributed with this source code.
 10  */
 11 
 12 namespace Patron;
 13 
 14 use ICanBoogie\Debug;
 15 use ICanBoogie\Exception;
 16 
 17 use Brickrouge\Alert;
 18 
 19 define('WDPATRON_DELIMIT_MACROS', false);
 20 
 21 class Engine extends TextHole
 22 {
 23     const PREFIX = 'p:';
 24 
 25     protected $trace_templates = false;
 26 
 27     public function __construct()
 28     {
 29         #
 30         # create context
 31         #
 32 
 33         $this->contextInit();
 34 
 35         #
 36         # add functions
 37         #
 38 
 39         $this->functions['to_s'] = function($a)
 40         {
 41             if (is_array($a) || (is_object($a) && !method_exists($a, '__toString')))
 42             {
 43                 return \ICanBoogie\dump($a);
 44             }
 45 
 46             return (string) $a;
 47         };
 48 
 49         $this->functions['add'] = function($a,$b)
 50         {
 51             return ($a + $b);
 52         };
 53 
 54         $this->addFunction('try', array($this, '_get_try'));
 55 
 56         #
 57         # some operations
 58         #
 59 
 60         //FIXME: add more operators
 61 
 62         $this->addFunction('if', function($a, $b, $c=null) { return $a ? $b : $c; });
 63         $this->addFunction('or', function($a, $b) { return $a ? $a : $b; });
 64         $this->addFunction('not', function($a) { return !$a; });
 65         $this->addFunction('mod', function($a, $b) { return $a % $b; });
 66         $this->addFunction('bit', function($a, $b) { return (int) $a & (1 << $b); });
 67 
 68         $this->addFunction('greater', function($a, $b) { return ($a > $b); });
 69         $this->addFunction('smaller', function($a, $b) { return ($a < $b); });
 70         $this->addFunction('equals', function($a, $b) { return ($a == $b); });
 71         $this->addFunction('different', function($a, $b) { return ($a != $b); });
 72 
 73         #
 74         # maths
 75         #
 76 
 77         $this->addFunction('minus', function($a, $b) { return $a - $b; });
 78         $this->addFunction('plus', function($a, $b) { return $a + $b; });
 79         $this->addFunction('times', function($a, $b) { return $a * $b; });
 80         $this->addFunction('by', function($a, $b) { return $a / $b; });
 81 
 82         #
 83         #
 84         #
 85 
 86         $this->addFunction('split', function($a, $b=",") { return explode($b,$a); });
 87         $this->addFunction('join', function($a, $b=",") { return implode($b,$a); });
 88         $this->addFunction('index', function() { $a = func_get_args(); $i = array_shift($a); return $a[$i]; });
 89         $this->addFunction('replace', function($a, $b, $c="") { return str_replace($b, $c, $a); });
 90 
 91         #
 92         # array (mostly from ruby)
 93         #
 94 
 95         /**
 96          * Returns the first element, or the first n elements, of the array. If the array is empty,
 97          * the first form returns nil, and the second form returns an empty array.
 98          *
 99          * a = [ "q", "r", "s", "t" ]
100          * a.first    // "q"
101          * a.first(1) // ["q"]
102          * a.first(3) // ["q", "r", "s"]
103          *
104          */
105 
106         $this->addFunction('first', function($a, $n=null) { $rc = array_slice($a, 0, $n ? $n : 1); return $n === null ? array_shift($rc) : $rc; });
107 
108         // TODO-20100507: add the 'last' method
109 
110         #
111         #
112         #
113 
114         $this->addFunction('markdown', function($txt) { require_once __DIR__ . '/../textmark.php'; return Markdown($txt); });
115     }
116 
117     private static $singleton;
118 
119     static public function get_singleton()
120     {
121         if (self::$singleton)
122         {
123             return self::$singleton;
124         }
125 
126         $class = get_called_class();
127 
128         self::$singleton = $singleton = new $class();
129 
130         return $singleton;
131     }
132 
133     public function _get_try($from, $which, $default=null)
134     {
135         $form = (array) $from;
136 
137         return isset($from[$which]) ? $from[$which] : $default;
138     }
139 
140     /*
141     **
142 
143     SYSTEM
144 
145     **
146     */
147 
148     protected $trace = array();
149     protected $errors = array();
150 
151     public function trace_enter($a)
152     {
153         array_unshift($this->trace, $a);
154     }
155 
156     public function trace_exit()
157     {
158         array_shift($this->trace);
159     }
160 
161     public function error($alert, array $args=array())
162     {
163         if ($alert instanceof \ICanBoogie\Exception\Config)
164         {
165             $this->errors[] = new Alert($alert->getMessage());
166 
167             return;
168         }
169         else if ($alert instanceof \Exception)
170         {
171             $alert = Debug::format_alert($alert);
172         }
173         else
174         {
175             $alert = \ICanBoogie\format($alert, $args);
176         }
177 
178         #
179         #
180         #
181 
182         $trace_html = null;
183 
184         if ($this->trace)
185         {
186             $i = count($this->trace);
187             $root = \ICanBoogie\DOCUMENT_ROOT;
188             $root_length = strlen($root);
189 
190             foreach ($this->trace as $trace)
191             {
192                 list($which, $message) = $trace;
193 
194                 if ($which == 'file')
195                 {
196                     if (strpos($message, $root_length) === 0)
197                     {
198                         $message = substr($message, $root_length);
199                     }
200                 }
201 
202                 $trace_html .= sprintf('#%02d: in %s "%s"', $i--, $which, $message) . '<br />';
203             }
204 
205             if ($trace_html)
206             {
207                 $trace = '<pre>' . $trace_html . '</pre>';
208             }
209         }
210 
211         #
212         #
213         #
214 
215         $this->errors[] = '<div class="alert alert-error">' . $alert . $trace_html . '</div>';
216     }
217 
218     public function handle_exception(\Exception $e)
219     {
220         if ($e instanceof \ICanBoogie\HTTP\HTTP\Error)
221         {
222             throw $e;
223         }
224         else if ($e instanceof \ICanBoogie\ActiveRecord\ActiveRecordException)
225         {
226             throw $e;
227         }
228 
229         $this->error($e);
230     }
231 
232     public function fetchErrors()
233     {
234         $rc = implode(PHP_EOL, $this->errors);
235 
236         $this->errors = array();
237 
238         return $rc;
239     }
240 
241     public function get_file()
242     {
243         foreach ($this->trace as $trace)
244         {
245             list($which, $data) = $trace;
246 
247             if ($which == 'file')
248             {
249                 return $data;
250             }
251         }
252     }
253 
254     public function get_template_dir()
255     {
256         return dirname($this->get_file());
257     }
258 
259     /*
260     **
261 
262     TEMPLATES
263 
264     **
265     */
266 
267     protected $templates = array();
268     protected $templates_searched = false;
269 
270     protected function search_templates()
271     {
272         global $core;
273 
274         if ($this->templates_searched)
275         {
276             return;
277         }
278 
279         $templates = $core->site->partial_templates;
280 
281         foreach ($templates as $id => $path)
282         {
283             $this->addTemplate($id, '!f:' . $path);
284         }
285 
286         $this->templates_searched = true;
287     }
288 
289     public function addTemplate($name, $template)
290     {
291         if (isset($this->templates[$name]))
292         {
293             $this->error
294             (
295                 'The template %name is already defined ! !template', array
296                 (
297                     '%name' => $name, '!template' => $template
298                 )
299             );
300 
301             return;
302         }
303 
304         $this->templates[$name] = $template;
305     }
306 
307     protected function get_template($name)
308     {
309         #
310         # if the template is not defined, and we haven't searched templates
311         # defined by modules, now is the time
312         #
313 
314         if (empty($this->templates[$name]))
315         {
316             $this->search_templates();
317         }
318 
319         if (isset($this->templates[$name]))
320         {
321             $template = $this->templates[$name];
322 
323             #
324             # we convert the template into a tree of nodes to speed up following parsings
325             #
326 
327             if (is_string($template))
328             {
329                 $file = null;
330 
331                 if ($template{0} == '!' && $template{1} == 'f' && $template{2} == ':')
332                 {
333                     $file = substr($template, 3);
334                     $template = file_get_contents($file);
335                     $file = substr($file, strlen(\ICanBoogie\DOCUMENT_ROOT));
336                 }
337 
338                 /*TODO-20120106: because the template is evaluated elsewhere, we can't attach
339                  * its file location.
340                 $template = $this->htmlparser->parse($template, self::PREFIX);
341 
342                 if ($file)
343                 {
344                     $template['file'] = $file;
345                 }
346                 */
347 
348                 $this->templates[$name] = $template;
349             }
350 
351             return $template;
352         }
353     }
354 
355     public function callTemplate($name, array $args=array())
356     {
357 //      echo __FUNCTION__ . '::disabled<br />'; return;
358 
359         $template = $this->get_template($name);
360 
361         if (!$template)
362         {
363             $er = 'Unknown template %name';
364             $params = array('%name' => $name);
365 
366             if ($this->templates)
367             {
368                 $er .= ', available templates: :list';
369                 $params[':list'] = implode(', ', array_keys($this->templates));
370             }
371 
372             $this->error($er, $params);
373 
374             return;
375         }
376 
377         array_unshift($this->trace, array('template', $name));
378 
379         if (version_compare(PHP_VERSION, '5.3.4', '>='))
380         {
381             $this->context['self']['arguments'] = $args;
382         }
383         else // COMPAT
384         {
385             $self = $this->context['self'];
386             $self['arguments'] = $args;
387             $this->context['self'] = $self;
388         }
389 
390         $rc = $this($template);
391 
392         array_shift($this->trace);
393 
394         return $rc;
395     }
396 
397     /*
398     **
399 
400     CONTEXT
401 
402     **
403     */
404 
405     protected function contextInit()
406     {
407         $this->context = new \BlueTihi\Context(array('self' => null, 'this' => null));
408     }
409 
410     /*
411     **
412 
413     PUBLISH
414 
415     **
416     */
417 
418     protected function get_compiled($template)
419     {
420         static $compiler;
421 
422         if ($compiler === null)
423         {
424             $compiler = new Compiler();
425         }
426 
427         return $compiler($template);
428     }
429 
430     public function publish($template, $bind=null, array $options=array())
431     {
432         trigger_error('The <q>publish</q> method is deprecated, please use invoke.');
433 
434         return $this->__invoke($template, $bind, $options);
435     }
436 
437     public function __invoke($template, $bind=null, array $options=array())
438     {
439         if (!$template)
440         {
441             return;
442         }
443 
444         if ($bind !== null)
445         {
446             $this->context['this'] = $bind;
447         }
448 
449         $file = null;
450 
451         foreach ($options as $option => $value)
452         {
453             switch ((string) $option)
454             {
455                 case 'variables':
456                 {
457                     $this->context = array_merge($this->context, $value);
458                 }
459                 break;
460 
461                 case 'file':
462                 {
463                     $file = $value;
464                 }
465                 break;
466 
467                 default:
468                 {
469                     trigger_error(\ICanBoogie\format('Suspicious option: %option :value', array('%option' => $option, ':value' => $value)));
470                 }
471                 break;
472             }
473         }
474 
475         if (is_array($template) && isset($template['file']))
476         {
477             $file = $template['file'];
478 
479             unset($template['file']);
480         }
481 
482         if ($file)
483         {
484             array_unshift($this->trace, array('file', $file));
485         }
486 
487         #
488         #
489         #
490 
491         if (!is_array($template))
492         {
493             $template = $this->get_compiled($template);
494         }
495 
496         $rc = '';
497 
498         foreach ($template as $node)
499         {
500             if (!($node instanceof Node))
501             {
502                 var_dump($node); continue;
503             }
504 
505 //          echo get_class($node) . '//' . is_callable($node) . '<br />';
506 
507             try
508             {
509                 $rc .= $node($this, $this->context);
510             }
511             catch (\Exception $e)
512             {
513                 $rc .= Debug::format_alert($e);
514             }
515 
516             $rc .= $this->fetchErrors();
517         }
518 
519         $rc .= $this->fetchErrors();
520 
521         #
522         #
523         #
524 
525         if ($file)
526         {
527             array_shift($this->trace);
528         }
529 
530         return $rc;
531     }
532 
533     /*
534 
535     #
536     # $context_markup is used to keep track of two variables associated with each markup :
537     # self and this.
538     #
539     # 'self' is a reference to the markup itsef, holding its name and the arguments with which
540     # it was called, it is also used to store special markup data as for the foreach markup
541     #
542     # 'this' is a reference to the object of the markup, that being an array, an object or a value
543     #
544     #
545 
546     <p:articles>
547 
548         self.range.start
549         self.range.limit
550         self.range.count
551 
552         this = array of Articles
553 
554         <p:foreach>
555 
556             self.name = foreach
557             self.arguments = array()
558             self.position
559             self.key
560             self.left
561 
562             this = an Article object
563 
564         </p:foreach>
565     </p:articles>
566 
567     */
568 
569     public $context_markup = array(); // should be protected
570 }
Autodoc API documentation generated by ApiGen 2.8.0