Source for file Dwoo.php

Documentation is available at Dwoo.php

  1. <?php
  2.  
  3. define('DWOO_DIRECTORY'dirname(__FILE__).DIRECTORY_SEPARATOR);
  4.  
  5. include 'Dwoo/IPluginProxy.php';
  6. include 'Dwoo/ILoader.php';
  7. include 'Dwoo/Loader.php';
  8. include 'Dwoo/Exception.php';
  9. include 'Dwoo/Security/Policy.php';
  10. include 'Dwoo/Security/Exception.php';
  11. include 'Dwoo/ICompilable.php';
  12. include 'Dwoo/ICompiler.php';
  13. include 'Dwoo/IDataProvider.php';
  14. include 'Dwoo/ITemplate.php';
  15. include 'Dwoo/ICompilable/Block.php';
  16. include 'Dwoo/Plugin.php';
  17. include 'Dwoo/Block/Plugin.php';
  18. include 'Dwoo/Filter.php';
  19. include 'Dwoo/Processor.php';
  20. include 'Dwoo/Template/String.php';
  21. include 'Dwoo/Template/File.php';
  22. include 'Dwoo/Data.php';
  23.  
  24. // TODO BC Checks, remove
  25. if (defined('DWOO_CACHE_DIRECTORY'))
  26.     throw new Dwoo_Exception('DWOO_CACHE_DIRECTORY is deprecated, you should now set this in Dwoo\'s constructor using new Dwoo([ $compileDir [, $cacheDir ]])');
  27. if (defined('DWOO_COMPILE_DIRECTORY'))
  28.     throw new Dwoo_Exception('DWOO_COMPILE_DIRECTORY is deprecated, you should now set this in Dwoo\'s constructor using new Dwoo([ $compileDir [, $cacheDir ]])');
  29. // end
  30.  
  31. if (defined('DWOO_CHMOD'=== false)
  32.     define('DWOO_CHMOD'0777);
  33.  
  34. /**
  35.  * main dwoo class, allows communication between the compiler, template and data classes
  36.  *
  37.  * <pre>
  38.  * requirements :
  39.  *  php 5.2.0 or above
  40.  *  SPL and PCRE extensions (for php versions prior to 5.3.0)
  41.  *  mbstring extension for some string manipulation plugins (especially if you intend to use UTF-8)
  42.  * recommended :
  43.  *  hash extension (for Dwoo_Template_String - minor performance boost)
  44.  *
  45.  * project created :
  46.  *  2008-01-05
  47.  * </pre>
  48.  *
  49.  * This software is provided 'as-is', without any express or implied warranty.
  50.  * In no event will the authors be held liable for any damages arising from the use of this software.
  51.  *
  52.  * This file is released under the LGPL
  53.  * "GNU Lesser General Public License"
  54.  * More information can be found here:
  55.  * {@link http://www.gnu.org/copyleft/lesser.html}
  56.  *
  57.  * @author     Jordi Boggiano <[email protected]>
  58.  * @copyright  Copyright (c) 2008, Jordi Boggiano
  59.  * @license    http://www.gnu.org/copyleft/lesser.html  GNU Lesser General Public License
  60.  * @link       http://dwoo.org/
  61.  * @version    0.9.2
  62.  * @date       2008-06-28
  63.  * @package    Dwoo
  64.  */
  65. class Dwoo
  66. {
  67.     /**
  68.      * current version number
  69.      *
  70.      * @var string 
  71.      */
  72.     const VERSION "0.9.3";
  73.  
  74.     /**
  75.      * unique number of this dwoo release
  76.      *
  77.      * this can be used by templates classes to check whether the compiled template
  78.      * has been compiled before this release or not, so that old templates are
  79.      * recompiled automatically when Dwoo is updated
  80.      */
  81.     const RELEASE_TAG 12;
  82.  
  83.     /**#@+
  84.      * constants that represents all plugin types
  85.      *
  86.      * these are bitwise-operation-safe values to allow multiple types
  87.      * on a single plugin
  88.      *
  89.      * @var int
  90.      */
  91.     const CLASS_PLUGIN 1;
  92.     const FUNC_PLUGIN 2;
  93.     const NATIVE_PLUGIN 4;
  94.     const BLOCK_PLUGIN 8;
  95.     const COMPILABLE_PLUGIN 16;
  96.     const CUSTOM_PLUGIN 32;
  97.     const SMARTY_MODIFIER 64;
  98.     const SMARTY_BLOCK 128;
  99.     const SMARTY_FUNCTION 256;
  100.     const PROXY_PLUGIN 512;
  101.     /**#@-*/
  102.  
  103.     /**
  104.      * character set of the template, used by string manipulation plugins
  105.      *
  106.      * it must be lowercase, but setCharset() will take care of that
  107.      *
  108.      * @see setCharset
  109.      * @see getCharset
  110.      * @var string 
  111.      */
  112.     protected $charset = 'utf-8';
  113.  
  114.     /**
  115.      * global variables that are accessible through $dwoo.* in the templates
  116.      *
  117.      * default values include:
  118.      *
  119.      * $dwoo.version - current version number
  120.      * $dwoo.ad - a Powered by Dwoo link pointing to dwoo.org
  121.      * $dwoo.now - the current time
  122.      * $dwoo.template - the current template filename
  123.      * $dwoo.charset - the character set used by the template
  124.      *
  125.      * on top of that, foreach and other plugins can store special values in there,
  126.      * see their documentation for more details.
  127.      *
  128.      * @var array 
  129.      */
  130.     protected $globals;
  131.  
  132.     /**
  133.      * directory where the compiled templates are stored
  134.      *
  135.      * defaults to DWOO_COMPILEDIR (= DWOO_DIRECTORY/compiled by default)
  136.      *
  137.      * @var string 
  138.      */
  139.     protected $compileDir;
  140.  
  141.     /**
  142.      * directory where the cached templates are stored
  143.      *
  144.      * defaults to DWOO_CACHEDIR (= DWOO_DIRECTORY/cache by default)
  145.      *
  146.      * @var string 
  147.      */
  148.     protected $cacheDir;
  149.  
  150.     /**
  151.      * defines how long (in seconds) the cached files must remain valid
  152.      *
  153.      * can be overriden on a per-template basis
  154.      *
  155.      * -1 = never delete
  156.      * 0 = disabled
  157.      * >0 = duration in seconds
  158.      *
  159.      * @var int 
  160.      */
  161.     protected $cacheTime = 0;
  162.  
  163.     /**
  164.      * security policy object
  165.      *
  166.      * @var Dwoo_Security_Policy 
  167.      */
  168.     protected $securityPolicy = null;
  169.  
  170.     /**
  171.      * stores the custom plugins callbacks
  172.      *
  173.      * @see addPlugin
  174.      * @see removePlugin
  175.      * @var array 
  176.      */
  177.     protected $plugins = array();
  178.  
  179.     /**
  180.      * stores the filter callbacks
  181.      *
  182.      * @see addFilter
  183.      * @see removeFilter
  184.      * @var array 
  185.      */
  186.     protected $filters = array();
  187.  
  188.     /**
  189.      * stores the resource types and associated
  190.      * classes / compiler classes
  191.      *
  192.      * @var array 
  193.      */
  194.     protected $resources = array
  195.     (
  196.         'file'        =>    array
  197.         (
  198.             'class'        =>    'Dwoo_Template_File',
  199.             'compiler'    =>    null
  200.         ),
  201.         'string'    =>    array
  202.         (
  203.             'class'        =>    'Dwoo_Template_String',
  204.             'compiler'    =>    null
  205.         )
  206.     );
  207.  
  208.     /**
  209.      * the dwoo loader object used to load plugins by this dwoo instance
  210.      *
  211.      * @var Dwoo_ILoader 
  212.      */
  213.     protected $loader = null;
  214.  
  215.     /**
  216.      * currently rendered template, set to null when not-rendering
  217.      *
  218.      * @var Dwoo_ITemplate 
  219.      */
  220.     protected $template = null;
  221.  
  222.     /**
  223.      * stores the instances of the class plugins during template runtime
  224.      *
  225.      * @var array 
  226.      */
  227.     protected $runtimePlugins;
  228.  
  229.     /**
  230.      * stores the data during template runtime
  231.      *
  232.      * @var array 
  233.      */
  234.     protected $data;
  235.  
  236.     /**
  237.      * stores the current scope during template runtime
  238.      *
  239.      * @var mixed 
  240.      */
  241.     protected $scope;
  242.  
  243.     /**
  244.      * stores the scope tree during template runtime
  245.      *
  246.      * @var array 
  247.      */
  248.     protected $scopeTree;
  249.  
  250.     /**
  251.      * stores the block plugins stack during template runtime
  252.      *
  253.      * @var array 
  254.      */
  255.     protected $stack;
  256.  
  257.     /**
  258.      * stores the current block plugin at the top of the stack during template runtime
  259.      *
  260.      * @var Dwoo_Block_Plugin 
  261.      */
  262.     protected $curBlock;
  263.  
  264.     /**
  265.      * stores the output buffer during template runtime
  266.      *
  267.      * @var string 
  268.      */
  269.     protected $buffer;
  270.  
  271.     /**
  272.      * stores plugin proxy
  273.      *
  274.      * @var Dwoo_IPluginProxy 
  275.      */
  276.     protected $pluginProxy;
  277.  
  278.      /**
  279.      * constructor, sets the cache and compile dir to the default values if not provided
  280.      *
  281.      * @param string $compileDir path to the compiled directory, defaults to lib/compiled
  282.      * @param string $cacheDir path to the cache directory, defaults to lib/cache
  283.      */
  284.     public function __construct($compileDir null$cacheDir null)
  285.     {
  286.         if ($cacheDir === null{
  287.             $this->cacheDir = DWOO_DIRECTORY.'cache'.DIRECTORY_SEPARATOR;
  288.         else {
  289.             $this->cacheDir = $cacheDir.DIRECTORY_SEPARATOR;
  290.         }
  291.  
  292.         if ($compileDir === null{
  293.             $this->compileDir = DWOO_DIRECTORY.'compiled'.DIRECTORY_SEPARATOR;
  294.         else {
  295.             $this->compileDir = $compileDir.DIRECTORY_SEPARATOR;
  296.         }
  297.  
  298.         if (is_writable($this->cacheDir=== false)
  299.             throw new Dwoo_Exception('Dwoo cache directory must be writable, chmod "'.$this->cacheDir.'" to make it writable');
  300.         if (is_writable($this->compileDir=== false)
  301.             throw new Dwoo_Exception('Dwoo compile directory must be writable, chmod "'.$this->compileDir.'" to make it writable');
  302.     }
  303.  
  304.     /**
  305.      * resets some runtime variables to allow a cloned object to be used to render sub-templates
  306.      */
  307.     public function __clone()
  308.     {
  309.         $this->template = null;
  310.     }
  311.  
  312.     /**
  313.      * outputs the template instead of returning it, this is basically a shortcut for get(*, *, *, true)
  314.      *
  315.      * @see get
  316.      * @param mixed $tpl template, can either be a Dwoo_ITemplate object (i.e. Dwoo_Template_File), a valid path to a template, or
  317.      *                       a template as a string it is recommended to provide a Dwoo_ITemplate as it will probably make things faster,
  318.      *                       especially if you render a template multiple times
  319.      * @param mixed $data the data to use, can either be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array. if you're
  320.      *                        rendering the template from cache, it can be left null
  321.      * @param Dwoo_ICompiler $compiler the compiler that must be used to compile the template, if left empty a default
  322.      *                                    Dwoo_Compiler will be used.
  323.      * @return string nothing or the template output if $output is true
  324.      */
  325.     public function output($tpl$data array()Dwoo_ICompiler $compiler null)
  326.     {
  327.         return $this->get($tpl$data$compilertrue);
  328.     }
  329.  
  330.     /**
  331.      * returns the given template rendered using the provided data and optional compiler
  332.      *
  333.      * @param mixed $tpl template, can either be a Dwoo_ITemplate object (i.e. Dwoo_Template_File), a valid path to a template, or
  334.      *                       a template as a string it is recommended to provide a Dwoo_ITemplate as it will probably make things faster,
  335.      *                       especially if you render a template multiple times
  336.      * @param mixed $data the data to use, can either be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array. if you're
  337.      *                        rendering the template from cache, it can be left null
  338.      * @param Dwoo_ICompiler $compiler the compiler that must be used to compile the template, if left empty a default
  339.      *                                    Dwoo_Compiler will be used.
  340.      * @param bool $output flag that defines whether the function returns the output of the template (false, default) or echoes it directly (true)
  341.      * @return string nothing or the template output if $output is true
  342.      */
  343.     public function get($_tpl$data array()$_compiler null$_output false)
  344.     {
  345.         // a render call came from within a template, so we need a new dwoo instance in order to avoid breaking this one
  346.         if ($this->template instanceof Dwoo_ITemplate{
  347.             $proxy clone $this;
  348.             return $proxy->get($_tpl$data$_compiler$_output);
  349.         }
  350.  
  351.         // auto-create template if required
  352.         if ($_tpl instanceof Dwoo_ITemplate{
  353.             // valid, skip
  354.         elseif (is_string($_tpl)) {
  355.             if (file_exists($_tpl)) {
  356.                 $_tpl new Dwoo_Template_File($_tpl);
  357.             elseif (strstr($_tpl':')) {
  358.                 $_bits explode(':'$_tpl2);
  359.                 $_tpl $this->templateFactory($_bits[0]$_bits[1]);
  360.             else {
  361.                 $_tpl new Dwoo_Template_String($_tpl);
  362.             }
  363.         else {
  364.             throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s first argument must be a Dwoo_ITemplate (i.e. Dwoo_Template_File) or a valid path to a template file'E_USER_NOTICE);
  365.         }
  366.  
  367.         // save the current template, enters render mode at the same time
  368.         // if another rendering is requested it will be proxied to a new Dwoo instance
  369.         $this->template = $_tpl;
  370.  
  371.         // load data
  372.         if ($data instanceof Dwoo_IDataProvider{
  373.             $this->data = $data->getData();
  374.         elseif (is_array($data)) {
  375.             $this->data = $data;
  376.         else {
  377.             throw new Dwoo_Exception('Dwoo->get/Dwoo->output\'s data argument must be a Dwoo_IDataProvider object (i.e. Dwoo_Data) or an associative array'E_USER_NOTICE);
  378.         }
  379.  
  380.         $this->initGlobals($_tpl);
  381.         $this->initRuntimeVars($_tpl);
  382.  
  383.         // try to get cached template
  384.         $file $_tpl->getCachedTemplate($this);
  385.         $doCache $file === true;
  386.         $cacheLoaded is_string($file);
  387.  
  388.         if ($cacheLoaded === true{
  389.             // cache is present, run it
  390.             if ($_output === true{
  391.                 include $file;
  392.                 $this->template = null;
  393.             else {
  394.                 ob_start();
  395.                 include $file;
  396.                 $this->template = null;
  397.                 return ob_get_clean();
  398.             }
  399.         else {
  400.             // no cache present
  401.  
  402.             if ($doCache === true{
  403.                 $dynamicId uniqid();
  404.             }
  405.  
  406.             // render template
  407.             $out include $_tpl->getCompiledTemplate($this$_compiler);
  408.  
  409.             // template returned false so it needs to be recompiled
  410.             if ($out === false{
  411.                 $_tpl->forceCompilation();
  412.                 $out include $_tpl->getCompiledTemplate($this$_compiler);
  413.             }
  414.  
  415.             if ($doCache === true{
  416.                 $out preg_replace('/(<%|%>|<\?php|<\?|\?>)/''<?php /*'.$dynamicId.'*/ echo \'$1\'; ?>'$out);
  417.                 if (!class_exists('Dwoo_plugin_dynamic'false)) {
  418.                     $this->getLoader()->loadPlugin('dynamic');
  419.                 }
  420.                 $out Dwoo_Plugin_dynamic::unescape($out$dynamicId);
  421.             }
  422.  
  423.             // process filters
  424.             foreach ($this->filters as $filter{
  425.                 if (is_array($filter&& $filter[0instanceof Dwoo_Filter{
  426.                     $out call_user_func($filter$out);
  427.                 else {
  428.                     $out call_user_func($filter$this$out);
  429.                 }
  430.             }
  431.  
  432.             if ($doCache === true{
  433.                 // building cache
  434.                 $file $_tpl->cache($this$out);
  435.  
  436.                 // run it from the cache to be sure dynamics are rendered
  437.                 if ($_output === true{
  438.                     include $file;
  439.                     // exit render mode
  440.                     $this->template = null;
  441.                 else {
  442.                     ob_start();
  443.                     include $file;
  444.                     // exit render mode
  445.                     $this->template = null;
  446.                     return ob_get_clean();
  447.                 }
  448.             else {
  449.                 // no need to build cache
  450.                 // exit render mode
  451.                 $this->template = null;
  452.                 // output
  453.                 if ($_output === true{
  454.                     echo $out;
  455.                 else {
  456.                     return $out;
  457.                 }
  458.             }
  459.         }
  460.     }
  461.  
  462.     /**
  463.      * re-initializes the globals array before each template run
  464.      *
  465.      * @param Dwoo_ITemplate $tpl the template that is going to be rendered
  466.      */
  467.     protected function initGlobals(Dwoo_ITemplate $tpl)
  468.     {
  469.         $this->globals = array
  470.         (
  471.             'version'    =>    self::VERSION,
  472.             'ad'        =>    '<a href="http://dwoo.org/">Powered by Dwoo</a>',
  473.             'now'        =>    $_SERVER['REQUEST_TIME'],
  474.             'template'    =>    $tpl->getName(),
  475.             'charset'    =>    $this->charset,
  476.         );
  477.     }
  478.  
  479.     /**
  480.      * re-initializes the runtime variables before each template run
  481.      *
  482.      * @param Dwoo_ITemplate $tpl the template that is going to be rendered
  483.      */
  484.     protected function initRuntimeVars(Dwoo_ITemplate $tpl)
  485.     {
  486.         $this->runtimePlugins = array();
  487.         $this->scope =$this->data;
  488.         $this->scopeTree = array();
  489.         $this->stack = array();
  490.         $this->curBlock = null;
  491.         $this->buffer = '';
  492.     }
  493.  
  494.     /*
  495.      * --------- settings functions ---------
  496.      */
  497.  
  498.     /**
  499.      * adds a custom plugin that is not in one of the plugin directories
  500.      *
  501.      * @param string $name the plugin name to be used in the templates
  502.      * @param callback $callback the plugin callback, either a function name,
  503.      *                               a class name or an array containing an object
  504.      *                               or class name and a method name
  505.      * @param bool $compilable if set to true, the plugin is assumed to be compilable
  506.      */
  507.     public function addPlugin($name$callback$compilable false)
  508.     {
  509.         $compilable $compilable self::COMPILABLE_PLUGIN 0;
  510.         if (is_array($callback)) {
  511.             if (is_subclass_of(is_object($callback[0]get_class($callback[0]$callback[0]'Dwoo_Block_Plugin')) {
  512.                 $this->plugins[$namearray('type'=>self::BLOCK_PLUGIN $compilable'callback'=>$callback'class'=>(is_object($callback[0]get_class($callback[0]$callback[0]));
  513.             else {
  514.                 $this->plugins[$namearray('type'=>self::CLASS_PLUGIN $compilable'callback'=>$callback'class'=>(is_object($callback[0]get_class($callback[0]$callback[0])'function'=>$callback[1]);
  515.             }
  516.         elseif (class_exists($callbackfalse)) {
  517.             if (is_subclass_of($callback'Dwoo_Block_Plugin')) {
  518.                 $this->plugins[$namearray('type'=>self::BLOCK_PLUGIN $compilable'callback'=>$callback'class'=>$callback);
  519.             else {
  520.                 $this->plugins[$namearray('type'=>self::CLASS_PLUGIN $compilable'callback'=>$callback'class'=>$callback'function'=>'process');
  521.             }
  522.         elseif (function_exists($callback)) {
  523.             $this->plugins[$namearray('type'=>self::FUNC_PLUGIN $compilable'callback'=>$callback);
  524.         else {
  525.             throw new Dwoo_Exception('Callback could not be processed correctly, please check that the function/class you used exists');
  526.         }
  527.     }
  528.  
  529.     /**
  530.      * removes a custom plugin
  531.      *
  532.      * @param string $name the plugin name
  533.      */
  534.     public function removePlugin($name)
  535.     {
  536.         if (isset($this->plugins[$name])) {
  537.             unset($this->plugins[$name]);
  538.         }
  539.     }
  540.  
  541.     /**
  542.      * adds a filter to this Dwoo instance, it will be used to filter the output of all the templates rendered by this instance
  543.      *
  544.      * @param mixed $callback a callback or a filter name if it is autoloaded from a plugin directory
  545.      * @param bool $autoload if true, the first parameter must be a filter name from one of the plugin directories
  546.      */
  547.     public function addFilter($callback$autoload false)
  548.     {
  549.         if ($autoload{
  550.             $name str_replace('Dwoo_Filter_'''$callback);
  551.             $class 'Dwoo_Filter_'.$name;
  552.  
  553.             if (!class_exists($classfalse&& !function_exists($class)) {
  554.                 $this->getLoader()->loadPlugin($name);
  555.             }
  556.  
  557.             if (class_exists($classfalse)) {
  558.                 $callback array(new $class($this)'process');
  559.             elseif (function_exists($class)) {
  560.                 $callback $class;
  561.             else {
  562.                 throw new Dwoo_Exception('Wrong filter name, when using autoload the filter must be in one of your plugin dir as "name.php" containg a class or function named "Dwoo_Filter_name"');
  563.             }
  564.  
  565.             $this->filters[$callback;
  566.         else {
  567.             $this->filters[$callback;
  568.         }
  569.     }
  570.  
  571.     /**
  572.      * removes a filter
  573.      *
  574.      * @param mixed $callback callback or filter name if it was autoloaded
  575.      */
  576.     public function removeFilter($callback)
  577.     {
  578.         if (($index array_search($callback$this->filterstrue)) !== false{
  579.             unset($this->filters[$index]);
  580.         elseif (($index array_search('Dwoo_Filter_'.str_replace('Dwoo_Filter_'''$callback)$this->filterstrue)) !== false{
  581.             unset($this->filters[$index]);
  582.         else    {
  583.             $class 'Dwoo_Filter_' str_replace('Dwoo_Filter_'''$callback);
  584.             foreach ($this->filters as $index=>$filter{
  585.                 if (is_array($filter&& $filter[0instanceof $class{
  586.                     unset($this->filters[$index]);
  587.                     break;
  588.                 }
  589.             }
  590.         }
  591.     }
  592.  
  593.     /**
  594.      * adds a resource or overrides a default one
  595.      *
  596.      * @param string $name the resource name
  597.      * @param string $class the resource class (which must implement Dwoo_ITemplate)
  598.      * @param callback $compilerFactory the compiler factory callback, a function that must return a compiler instance used to compile this resource, if none is provided. by default it will produce a Dwoo_Compiler object
  599.      */
  600.     public function addResource($name$class$compilerFactory null)
  601.     {
  602.         if (strlen($name2{
  603.             throw new Dwoo_Exception('Resource names must be at least two-character long to avoid conflicts with Windows paths');
  604.         }
  605.  
  606.         if (!class_exists($class)) {
  607.             throw new Dwoo_Exception('Resource class does not exist');
  608.         }
  609.  
  610.         $interfaces class_implements($class);
  611.         if (in_array('Dwoo_ITemplate'$interfaces=== false{
  612.             throw new Dwoo_Exception('Resource class must implement Dwoo_ITemplate');
  613.         }
  614.  
  615.         $this->resources[$namearray('class'=>$class'compiler'=>$compilerFactory);
  616.     }
  617.  
  618.     /**
  619.      * removes a custom resource
  620.      *
  621.      * @param string $name the resource name
  622.      */
  623.     public function removeResource($name)
  624.     {
  625.         unset($this->resources[$name]);
  626.         if ($name==='file'{
  627.             $this->resources['file'array('class'=>'Dwoo_Template_File''compiler'=>null);
  628.         }
  629.     }
  630.  
  631.     /*
  632.      * --------- getters and setters ---------
  633.      */
  634.  
  635.     /**
  636.      * sets the loader object to use to load plugins
  637.      *
  638.      * @param Dwoo_ILoader $loader loader object
  639.      */
  640.     public function setLoader(Dwoo_ILoader $loader)
  641.     {
  642.         $this->loader = $loader;
  643.     }
  644.  
  645.     /**
  646.      * returns the current loader object or a default one if none is currently found
  647.      *
  648.      * @param Dwoo_ILoader 
  649.      */
  650.     public function getLoader()
  651.     {
  652.         if ($this->loader === null{
  653.             $this->loader = new Dwoo_Loader($this->compileDir);
  654.         }
  655.  
  656.         return $this->loader;
  657.     }
  658.  
  659.     /**
  660.      * returns the custom plugins loaded
  661.      *
  662.      * used by the Dwoo_ITemplate classes to pass the custom plugins to their Dwoo_ICompiler instance
  663.      *
  664.      * @return array 
  665.      */
  666.     public function getCustomPlugins()
  667.     {
  668.         return $this->plugins;
  669.     }
  670.  
  671.     /**
  672.      * returns the cache directory with a trailing DIRECTORY_SEPARATOR
  673.      *
  674.      * @return string 
  675.      */
  676.     public function getCacheDir()
  677.     {
  678.         return $this->cacheDir;
  679.     }
  680.  
  681.     /**
  682.      * sets the cache directory and automatically appends a DIRECTORY_SEPARATOR
  683.      *
  684.      * @param string $dir the cache directory
  685.      */
  686.     public function setCacheDir($dir)
  687.     {
  688.         $this->cacheDir = rtrim($dir'/\\').DIRECTORY_SEPARATOR;
  689.         if (is_writable($this->cacheDir=== false{
  690.             throw new Dwoo_Exception('The cache directory must be writable, chmod "'.$this->cacheDir.'" to make it writable');
  691.         }
  692.     }
  693.  
  694.     /**
  695.      * returns the compile directory with a trailing DIRECTORY_SEPARATOR
  696.      *
  697.      * @return string 
  698.      */
  699.     public function getCompileDir()
  700.     {
  701.         return $this->compileDir;
  702.     }
  703.  
  704.     /**
  705.      * sets the compile directory and automatically appends a DIRECTORY_SEPARATOR
  706.      *
  707.      * @param string $dir the compile directory
  708.      */
  709.     public function setCompileDir($dir)
  710.     {
  711.         $this->compileDir = rtrim($dir'/\\').DIRECTORY_SEPARATOR;
  712.         if (is_writable($this->compileDir=== false{
  713.             throw new Dwoo_Exception('The compile directory must be writable, chmod "'.$this->compileDir.'" to make it writable');
  714.         }
  715.     }
  716.  
  717.     /**
  718.      * returns the default cache time that is used with templates that do not have a cache time set
  719.      *
  720.      * @return int the duration in seconds
  721.      */
  722.     public function getCacheTime()
  723.     {
  724.         return $this->cacheTime;
  725.     }
  726.  
  727.     /**
  728.      * sets the default cache time to use with templates that do not have a cache time set
  729.      *
  730.      * @param int $seconds the duration in seconds
  731.      */
  732.     public function setCacheTime($seconds)
  733.     {
  734.         $this->cacheTime = (int) $seconds;
  735.     }
  736.  
  737.     /**
  738.      * returns the character set used by the string manipulation plugins
  739.      *
  740.      * the charset is automatically lowercased
  741.      *
  742.      * @return string 
  743.      */
  744.     public function getCharset()
  745.     {
  746.         return $this->charset;
  747.     }
  748.  
  749.     /**
  750.      * sets the character set used by the string manipulation plugins
  751.      *
  752.      * the charset will be automatically lowercased
  753.      *
  754.      * @param string $charset the character set
  755.      */
  756.     public function setCharset($charset)
  757.     {
  758.         $this->charset = strtolower((string) $charset);
  759.     }
  760.  
  761.     /**
  762.      * returns the current template being rendered, when applicable, or null
  763.      *
  764.      * @return Dwoo_ITemplate|null
  765.      */
  766.     public function getTemplate()
  767.     {
  768.         return $this->template;
  769.     }
  770.  
  771.     /**
  772.      * sets the default compiler factory function for the given resource name
  773.      *
  774.      * a compiler factory must return a Dwoo_ICompiler object pre-configured to fit your needs
  775.      *
  776.      * @param string $resourceName the resource name (i.e. file, string)
  777.      * @param callback $compilerFactory the compiler factory callback
  778.      */
  779.     public function setDefaultCompilerFactory($resourceName$compilerFactory)
  780.     {
  781.         $this->resources[$resourceName]['compiler'$compilerFactory;
  782.     }
  783.  
  784.     /**
  785.      * returns the default compiler factory function for the given resource name
  786.      *
  787.      * @param string $resourceName the resource name
  788.      * @return callback the compiler factory callback
  789.      */
  790.     public function getDefaultCompilerFactory($resourceName)
  791.     {
  792.         return $this->resources[$resourceName]['compiler'];
  793.     }
  794.  
  795.     /**
  796.      * sets the security policy object to enforce some php security settings
  797.      *
  798.      * use this if untrusted persons can modify templates
  799.      *
  800.      * @param Dwoo_Security_Policy $policy the security policy object
  801.      */
  802.     public function setSecurityPolicy(Dwoo_Security_Policy $policy null)
  803.     {
  804.         $this->securityPolicy = $policy;
  805.     }
  806.  
  807.     /**
  808.      * returns the current security policy object or null by default
  809.      *
  810.      * @return Dwoo_Security_Policy|nullthe security policy object if any
  811.      */
  812.     public function getSecurityPolicy()
  813.     {
  814.         return $this->securityPolicy;
  815.     }
  816.  
  817.     /**
  818.      * sets the object that must be used as a plugin proxy when plugin can't be found
  819.      * by dwoo's loader
  820.      *
  821.      * @param Dwoo_IPluginProxy $pluginProxy the proxy object
  822.      */
  823.     public function setPluginProxy(Dwoo_IPluginProxy $pluginProxy{
  824.         $this->pluginProxy = $pluginProxy;
  825.     }
  826.  
  827.     /**
  828.      * returns the current plugin proxy object or null by default
  829.      *
  830.      * @param Dwoo_IPluginProxy|nullthe proxy object if any
  831.      */
  832.     public function getPluginProxy({
  833.         return $this->pluginProxy;
  834.     }
  835.  
  836.     /*
  837.      * --------- util functions ---------
  838.      */
  839.  
  840.     /**
  841.      * [util function] checks whether the given template is cached or not
  842.      *
  843.      * @param Dwoo_ITemplate $tpl the template object
  844.      * @return bool 
  845.      */
  846.     public function isCached(Dwoo_ITemplate $tpl)
  847.     {
  848.         return is_string($tpl->getCachedTemplate($this));
  849.     }
  850.  
  851.     /**
  852.      * [util function] clears the cached templates if they are older than the given time
  853.      *
  854.      * @param int $olderThan minimum time (in seconds) required for a cached template to be cleared
  855.      * @return int the amount of templates cleared
  856.      */
  857.     public function clearCache($olderThan=-1)
  858.     {
  859.         $cacheDirs new RecursiveDirectoryIterator($this->cacheDir);
  860.         $cache new RecursiveIteratorIterator($cacheDirs);
  861.         $expired time($olderThan;
  862.         $count 0;
  863.         foreach ($cache as $file{
  864.             if ($cache->isDot(|| $cache->isDir(|| substr($file-5!== '.html'{
  865.                 continue;
  866.             }
  867.             if ($cache->getCTime($expired{
  868.                 $count += unlink((string) $file0;
  869.             }
  870.         }
  871.         return $count;
  872.     }
  873.  
  874.     /**
  875.      * [util function] fetches a template object of the given resource
  876.      *
  877.      * @param string $resourceName the resource name (i.e. file, string)
  878.      * @param string $resourceId the resource identifier (i.e. file path)
  879.      * @param int $cacheTime the cache time setting for this resource
  880.      * @param string $cacheId the unique cache identifier
  881.      * @param string $compileId the unique compiler identifier
  882.      * @return Dwoo_ITemplate 
  883.      */
  884.     public function templateFactory($resourceName$resourceId$cacheTime null$cacheId null$compileId null)
  885.     {
  886.         if (isset($this->resources[$resourceName])) {
  887.             return call_user_func(array($this->resources[$resourceName]['class']'templateFactory')$this$resourceId$cacheTime$cacheId$compileId);
  888.         else {
  889.             throw new Dwoo_Exception('Unknown resource type : '.$resourceName);
  890.         }
  891.     }
  892.  
  893.     /**
  894.      * [util function] checks if the input is an array or an iterator object, optionally it can also check if it's empty
  895.      *
  896.      * @param mixed $value the variable to check
  897.      * @param bool $checkIsEmpty if true, the function will also check if the array is empty
  898.      * @param bool $allowNonCountable if true, the function will return true if
  899.      *  an object is not empty but does not implement Countable, by default a
  900.      *  non- countable object is considered empty, this setting is only used if
  901.      *  $checkIsEmpty is true
  902.      * @return bool true if it's an array (and not empty) or false if it's not an array (or if it's empty)
  903.      */
  904.     public function isArray($value$checkIsEmpty=false$allowNonCountable=false)
  905.     {
  906.         if (is_array($value=== true{
  907.             if ($checkIsEmpty === false{
  908.                 return true;
  909.             else {
  910.                 return count($value0;
  911.             }
  912.         elseif ($value instanceof Iterator{
  913.             if ($checkIsEmpty === false{
  914.                 return true;
  915.             else {
  916.                 if ($allowNonCountable === false{
  917.                     return count($value0;
  918.                 else {
  919.                     if ($value instanceof Countable{
  920.                         return count($value0;
  921.                     else    {
  922.                         $value->rewind();
  923.                         return $value->valid();
  924.                     }
  925.                 }
  926.             }
  927.         }
  928.         return false;
  929.     }
  930.  
  931.     /**
  932.      * [util function] triggers a dwoo error
  933.      *
  934.      * @param string $message the error message
  935.      * @param int $level the error level, one of the PHP's E_* constants
  936.      */
  937.     public function triggerError($message$level=E_USER_NOTICE)
  938.     {
  939.         trigger_error('Dwoo error (in '.$this->template->getResourceIdentifier().') : '.$message$level);
  940.     }
  941.  
  942.     /*
  943.      * --------- runtime functions ---------
  944.      */
  945.  
  946.     /**
  947.      * [runtime function] adds a block to the block stack
  948.      *
  949.      * @param string $blockName the block name (without Dwoo_Plugin_ prefix)
  950.      * @param array $args the arguments to be passed to the block's init() function
  951.      * @return Dwoo_Block_Plugin the newly created block
  952.      */
  953.     public function addStack($blockNamearray $args=array())
  954.     {
  955.         if (isset($this->plugins[$blockName])) {
  956.             $class $this->plugins[$blockName]['class'];
  957.         else {
  958.             $class 'Dwoo_Plugin_'.$blockName;
  959.         }
  960.  
  961.         if ($this->curBlock !== null{
  962.             $this->curBlock->buffer(ob_get_contents());
  963.             ob_clean();
  964.         else {
  965.             $this->buffer .= ob_get_contents();
  966.             ob_clean();
  967.         }
  968.  
  969.         $block new $class($this);
  970.  
  971.         $cnt count($args);
  972.         if ($cnt===0{
  973.             $block->init();
  974.         elseif ($cnt===1{
  975.             $block->init($args[0]);
  976.         elseif ($cnt===2{
  977.             $block->init($args[0]$args[1]);
  978.         elseif ($cnt===3{
  979.             $block->init($args[0]$args[1]$args[2]);
  980.         elseif ($cnt===4{
  981.             $block->init($args[0]$args[1]$args[2]$args[3]);
  982.         else {
  983.             call_user_func_array(array($block,'init')$args);
  984.         }
  985.  
  986.         $this->stack[$this->curBlock = $block;
  987.         return $block;
  988.     }
  989.  
  990.     /**
  991.      * [runtime function] removes the plugin at the top of the block stack
  992.      *
  993.      * calls the block buffer() function, followed by a call to end()
  994.      * and finally a call to process()
  995.      */
  996.     public function delStack()
  997.     {
  998.         $args func_get_args();
  999.  
  1000.         $this->curBlock->buffer(ob_get_contents());
  1001.         ob_clean();
  1002.  
  1003.         $cnt count($args);
  1004.         if ($cnt===0{
  1005.             $this->curBlock->end();
  1006.         elseif ($cnt===1{
  1007.             $this->curBlock->end($args[0]);
  1008.         elseif ($cnt===2{
  1009.             $this->curBlock->end($args[0]$args[1]);
  1010.         elseif ($cnt===3{
  1011.             $this->curBlock->end($args[0]$args[1]$args[2]);
  1012.         elseif ($cnt===4{
  1013.             $this->curBlock->end($args[0]$args[1]$args[2]$args[3]);
  1014.         else {
  1015.             call_user_func_array(array($this->curBlock'end')$args);
  1016.         }
  1017.  
  1018.         $tmp array_pop($this->stack);
  1019.  
  1020.         if (count($this->stack0{
  1021.             $this->curBlock = end($this->stack);
  1022.             $this->curBlock->buffer($tmp->process());
  1023.         else {
  1024.             $this->curBlock = null;
  1025.             echo $tmp->process();
  1026.         }
  1027.  
  1028.         unset($tmp);
  1029.     }
  1030.  
  1031.     /**
  1032.      * [runtime function] returns the parent block of the given block
  1033.      *
  1034.      * @param Dwoo_Block_Plugin $block 
  1035.      * @return Dwoo_Block_Plugin or false if the given block isn't in the stack
  1036.      */
  1037.     public function getParentBlock(Dwoo_Block_Plugin $block)
  1038.     {
  1039.         $index array_search($block$this->stacktrue);
  1040.         if ($index !== false && $index 0{
  1041.             return $this->stack[$index-1];
  1042.         }
  1043.         return false;
  1044.     }
  1045.  
  1046.     /**
  1047.      * [runtime function] finds the closest block of the given type, starting at the top of the stack
  1048.      *
  1049.      * @param string $type the type of plugin you want to find
  1050.      * @return Dwoo_Block_Plugin or false if no plugin of such type is in the stack
  1051.      */
  1052.     public function findBlock($type)
  1053.     {
  1054.         if (isset($this->plugins[$type])) {
  1055.             $type $this->plugins[$type]['class'];
  1056.         else {
  1057.             $type 'Dwoo_Plugin_'.str_replace('Dwoo_Plugin_'''$type);
  1058.         }
  1059.  
  1060.         $keys array_keys($this->stack);
  1061.         while (($key array_pop($keys)) !== false{
  1062.             if ($this->stack[$keyinstanceof $type{
  1063.                 return $this->stack[$key];
  1064.             }
  1065.         }
  1066.         return false;
  1067.     }
  1068.  
  1069.     /**
  1070.      * [runtime function] returns a Dwoo_Plugin of the given class
  1071.      *
  1072.      * this is so a single instance of every class plugin is created at each template run,
  1073.      * allowing class plugins to have "per-template-run" static variables
  1074.      *
  1075.      * @param string $class the class name
  1076.      * @return mixed an object of the given class
  1077.      */
  1078.     protected function getObjectPlugin($class)
  1079.     {
  1080.         if (isset($this->runtimePlugins[$class])) {
  1081.             return $this->runtimePlugins[$class];
  1082.         }
  1083.         return $this->runtimePlugins[$classnew $class($this);
  1084.     }
  1085.  
  1086.     /**
  1087.      * [runtime function] calls the process() method of the given class-plugin name
  1088.      *
  1089.      * @param string $plugName the class plugin name (without Dwoo_Plugin_ prefix)
  1090.      * @param array $params an array of parameters to send to the process() method
  1091.      * @return string the process() return value
  1092.      */
  1093.     public function classCall($plugNamearray $params array())
  1094.     {
  1095.         $class 'Dwoo_Plugin_'.$plugName;
  1096.  
  1097.         $plugin $this->getObjectPlugin($class);
  1098.  
  1099.         $cnt count($params);
  1100.         if ($cnt===0{
  1101.             return $plugin->process();
  1102.         elseif ($cnt===1{
  1103.             return $plugin->process($params[0]);
  1104.         elseif ($cnt===2{
  1105.             return $plugin->process($params[0]$params[1]);
  1106.         elseif ($cnt===3{
  1107.             return $plugin->process($params[0]$params[1]$params[2]);
  1108.         elseif ($cnt===4{
  1109.             return $plugin->process($params[0]$params[1]$params[2]$params[3]);
  1110.         else {
  1111.             return call_user_func_array(array($plugin'process')$params);
  1112.         }
  1113.     }
  1114.  
  1115.     /**
  1116.      * [runtime function] calls a php function
  1117.      *
  1118.      * @param string $callback the function to call
  1119.      * @param array $params an array of parameters to send to the function
  1120.      * @return mixed the return value of the called function
  1121.      */
  1122.     public function arrayMap($callbackarray $params)
  1123.     {
  1124.         if ($params[0=== $this{
  1125.             $addThis true;
  1126.             array_shift($params);
  1127.         }
  1128.         if ((is_array($params[0]|| ($params[0instanceof Iterator && $params[0instanceof ArrayAccess))) {
  1129.             if (empty($params[0])) {
  1130.                 return $params[0];
  1131.             }
  1132.  
  1133.             // array map
  1134.             $out array();
  1135.             $cnt count($params);
  1136.  
  1137.             if (isset($addThis)) {
  1138.                 array_unshift($params$this);
  1139.                 $items $params[1];
  1140.                 $keys array_keys($items);
  1141.  
  1142.                 if (is_string($callback=== false{
  1143.                     while (($i array_shift($keys)) !== null{
  1144.                         $out[call_user_func_array($callbackarray(1=>$items[$i]$params);
  1145.                     }
  1146.                 elseif ($cnt===1{
  1147.                     while (($i array_shift($keys)) !== null{
  1148.                         $out[$callback($this$items[$i]);
  1149.                     }
  1150.                 elseif ($cnt===2{
  1151.                     while (($i array_shift($keys)) !== null{
  1152.                         $out[$callback($this$items[$i]$params[2]);
  1153.                     }
  1154.                 elseif ($cnt===3{
  1155.                     while (($i array_shift($keys)) !== null{
  1156.                         $out[$callback($this$items[$i]$params[2]$params[3]);
  1157.                     }
  1158.                 else {
  1159.                     while (($i array_shift($keys)) !== null{
  1160.                         $out[call_user_func_array($callbackarray(1=>$items[$i]$params);
  1161.                     }
  1162.                 }
  1163.             else {
  1164.                 $items $params[0];
  1165.                 $keys array_keys($items);
  1166.  
  1167.                 if (is_string($callback=== false{
  1168.                     while (($i array_shift($keys)) !== null{
  1169.                         $out[call_user_func_array($callbackarray($items[$i]$params);
  1170.                     }
  1171.                 elseif ($cnt===1{
  1172.                     while (($i array_shift($keys)) !== null{
  1173.                         $out[$callback($items[$i]);
  1174.                     }
  1175.                 elseif ($cnt===2{
  1176.                     while (($i array_shift($keys)) !== null{
  1177.                         $out[$callback($items[$i]$params[1]);
  1178.                     }
  1179.                 elseif ($cnt===3{
  1180.                     while (($i array_shift($keys)) !== null{
  1181.                         $out[$callback($items[$i]$params[1]$params[2]);
  1182.                     }
  1183.                 elseif ($cnt===4{
  1184.                     while (($i array_shift($keys)) !== null{
  1185.                         $out[$callback($items[$i]$params[1]$params[2]$params[3]);
  1186.                     }
  1187.                 else {
  1188.                     while (($i array_shift($keys)) !== null{
  1189.                         $out[call_user_func_array($callbackarray($items[$i]$params);
  1190.                     }
  1191.                 }
  1192.             }
  1193.             return $out;
  1194.         else {
  1195.             return $params[0];
  1196.         }
  1197.     }
  1198.  
  1199.     /**
  1200.      * [runtime function] reads a variable into the given data array
  1201.      *
  1202.      * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
  1203.      * @param mixed $data the data array or object to read from
  1204.      * @return mixed 
  1205.      */
  1206.     public function readVarInto($varstr$data)
  1207.     {
  1208.         if ($data === null{
  1209.             return null;
  1210.         }
  1211.  
  1212.         if (is_array($varstr=== false{
  1213.             preg_match_all('#(\[|->|\.)?([a-z0-9_]+)\]?#i'$varstr$m);
  1214.         else {
  1215.             $m $varstr;
  1216.         }
  1217.         unset($varstr);
  1218.  
  1219.         while (list($k$sepeach($m[1])) {
  1220.             if ($sep === '.' || $sep === '[' || $sep === ''{
  1221.                 if ((is_array($data|| $data instanceof ArrayAccess&& isset($data[$m[2][$k]])) {
  1222.                     $data $data[$m[2][$k]];
  1223.                 else {
  1224.                     return null;
  1225.                 }
  1226.             else {
  1227.                 if (is_object($data)) {
  1228.                     $data $data->$m[2][$k];
  1229.                 else {
  1230.                     return null;
  1231.                 }
  1232.             }
  1233.         }
  1234.  
  1235.         return $data;
  1236.     }
  1237.  
  1238.     /**
  1239.      * [runtime function] reads a variable into the parent scope
  1240.      *
  1241.      * @param int $parentLevels the amount of parent levels to go from the current scope
  1242.      * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
  1243.      * @return mixed 
  1244.      */
  1245.     public function readParentVar($parentLevels$varstr null)
  1246.     {
  1247.         $tree $this->scopeTree;
  1248.         $cur $this->data;
  1249.  
  1250.         while ($parentLevels--!==0{
  1251.             array_pop($tree);
  1252.         }
  1253.  
  1254.         while (($i array_shift($tree)) !== null{
  1255.             if (is_object($cur)) {
  1256.                 $cur $cur->$i;
  1257.             else {
  1258.                 $cur $cur[$i];
  1259.             }
  1260.         }
  1261.  
  1262.         if ($varstr!==null{
  1263.             return $this->readVarInto($varstr$cur);
  1264.         else {
  1265.             return $cur;
  1266.         }
  1267.     }
  1268.  
  1269.     /**
  1270.      * [runtime function] reads a variable into the current scope
  1271.      *
  1272.      * @param string $varstr the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
  1273.      * @return mixed 
  1274.      */
  1275.     public function readVar($varstr)
  1276.     {
  1277.         if (is_array($varstr)===true{
  1278.             $m $varstr;
  1279.             unset($varstr);
  1280.         else {
  1281.             if (strstr($varstr'.'=== false && strstr($varstr'['=== false && strstr($varstr'->'=== false{
  1282.                 if ($varstr === 'dwoo'{
  1283.                     return $this->globals;
  1284.                 elseif ($varstr === '__' || $varstr === '_root' {
  1285.                     return $this->data;
  1286.                     $varstr substr($varstr6);
  1287.                 elseif ($varstr === '_' || $varstr === '_parent'{
  1288.                     $varstr '.'.$varstr;
  1289.                     $tree $this->scopeTree;
  1290.                     $cur $this->data;
  1291.                     array_pop($tree);
  1292.  
  1293.                     while (($i array_shift($tree)) !== null{
  1294.                         if (is_object($cur)) {
  1295.                             $cur $cur->$i;
  1296.                         else {
  1297.                             $cur $cur[$i];
  1298.                         }
  1299.                     }
  1300.  
  1301.                     return $cur;
  1302.                 }
  1303.  
  1304.                 $cur $this->scope;
  1305.  
  1306.                 if (isset($cur[$varstr])) {
  1307.                     return $cur[$varstr];
  1308.                 else {
  1309.                     return null;
  1310.                 }
  1311.             }
  1312.  
  1313.             if (substr($varstr01=== '.'{
  1314.                 $varstr 'dwoo'.$varstr;
  1315.             }
  1316.  
  1317.             preg_match_all('#(\[|->|\.)?([a-z0-9_]+)\]?#i'$varstr$m);
  1318.         }
  1319.  
  1320.         $i $m[2][0];
  1321.         if ($i === 'dwoo'{
  1322.             $cur $this->globals;
  1323.             array_shift($m[2]);
  1324.             array_shift($m[1]);
  1325.             switch ($m[2][0]{
  1326.  
  1327.             case 'get':
  1328.                 $cur $_GET;
  1329.                 break;
  1330.             case 'post':
  1331.                 $cur $_POST;
  1332.                 break;
  1333.             case 'session':
  1334.                 $cur $_SESSION;
  1335.                 break;
  1336.             case 'cookies':
  1337.             case 'cookie':
  1338.                 $cur $_COOKIE;
  1339.                 break;
  1340.             case 'server':
  1341.                 $cur $_SERVER;
  1342.                 break;
  1343.             case 'env':
  1344.                 $cur $_ENV;
  1345.                 break;
  1346.             case 'request':
  1347.                 $cur $_REQUEST;
  1348.                 break;
  1349.             case 'const':
  1350.                 array_shift($m[2]);
  1351.                 if (defined($m[2][0])) {
  1352.                     return constant($m[2][0]);
  1353.                 else {
  1354.                     return null;
  1355.                 }
  1356.  
  1357.             }
  1358.             if ($cur !== $this->globals{
  1359.                 array_shift($m[2]);
  1360.                 array_shift($m[1]);
  1361.             }
  1362.         elseif ($i === '__' || $i === '_root'{
  1363.             $cur $this->data;
  1364.             array_shift($m[2]);
  1365.             array_shift($m[1]);
  1366.         elseif ($i === '_' || $i === '_parent'{
  1367.             $tree $this->scopeTree;
  1368.             $cur $this->data;
  1369.  
  1370.             while (true{
  1371.                 array_pop($tree);
  1372.                 array_shift($m[2]);
  1373.                 array_shift($m[1]);
  1374.                 if (current($m[2]=== '_' || current($m[2]=== '_parent'{
  1375.                     continue;
  1376.                 }
  1377.  
  1378.                 while (($i array_shift($tree)) !== null{
  1379.                     if (is_object($cur)) {
  1380.                         $cur $cur->$i;
  1381.                     else {
  1382.                         $cur $cur[$i];
  1383.                     }
  1384.                 }
  1385.                 break;
  1386.             }
  1387.         else {
  1388.             $cur $this->scope;
  1389.         }
  1390.  
  1391.         while (list($k$sepeach($m[1])) {
  1392.             if ($sep === '.' || $sep === '[' || $sep === ''{
  1393.                 if ((is_array($cur|| $cur instanceof ArrayAccess&& isset($cur[$m[2][$k]])) {
  1394.                     $cur $cur[$m[2][$k]];
  1395.                 else {
  1396.                     return null;
  1397.                 }
  1398.             elseif ($sep === '->'{
  1399.                 if (is_object($cur)) {
  1400.                     $cur $cur->$m[2][$k];
  1401.                 else {
  1402.                     return null;
  1403.                 }
  1404.             else {
  1405.                 return null;
  1406.             }
  1407.         }
  1408.  
  1409.         return $cur;
  1410.     }
  1411.  
  1412.     /**
  1413.      * [runtime function] assign the value to the given variable
  1414.      *
  1415.      * @param mixed $value the value to assign
  1416.      * @param string $scope the variable string, using dwoo variable syntax (i.e. "var.subvar[subsubvar]->property")
  1417.      * @return bool true if assigned correctly or false if a problem occured while parsing the var string
  1418.      */
  1419.     public function assignInScope($value$scope)
  1420.     {
  1421.         $tree =$this->scopeTree;
  1422.         $data =$this->data;
  1423.  
  1424.         if (strstr($scope'.'=== false && strstr($scope'->'=== false{
  1425.             $this->scope[$scope$value;
  1426.         else {
  1427.             // TODO handle _root/_parent scopes ?
  1428.             preg_match_all('#(\[|->|\.)?([a-z0-9_]+)\]?#i'$scope$m);
  1429.  
  1430.             $cur =$this->scope;
  1431.             $last array(array_pop($m[1])array_pop($m[2]));
  1432.  
  1433.             while (list($k$sepeach($m[1])) {
  1434.                 if ($sep === '.' || $sep === '[' || $sep === ''{
  1435.                     if (is_array($cur=== false{
  1436.                         $cur array();
  1437.                     }
  1438.                     $cur =$cur[$m[2][$k]];
  1439.                 elseif ($sep === '->'{
  1440.                     if (is_object($cur=== false{
  1441.                         $cur new stdClass;
  1442.                     }
  1443.                     $cur =$cur->$m[2][$k];
  1444.                 else {
  1445.                     return false;
  1446.                 }
  1447.             }
  1448.  
  1449.             if ($last[0=== '.' || $last[0=== '[' || $last[0=== ''{
  1450.                 if (is_array($cur=== false{
  1451.                     $cur array();
  1452.                 }
  1453.                 $cur[$last[1]] $value;
  1454.             elseif ($last[0=== '->'{
  1455.                 if (is_object($cur=== false{
  1456.                     $cur new stdClass;
  1457.                 }
  1458.                 $cur->$last[1$value;
  1459.             else {
  1460.                 return false;
  1461.             }
  1462.         }
  1463.     }
  1464.  
  1465.     /**
  1466.      * [runtime function] sets the scope to the given scope string or array
  1467.      *
  1468.      * @param mixed $scope a string i.e. "level1.level2" or an array i.e. array("level1", "level2")
  1469.      * @param bool $absolute if true, the scope is set from the top level scope and not from the current scope
  1470.      * @return array the current scope tree
  1471.      */
  1472.     public function setScope($scope$absolute false)
  1473.     {
  1474.         $old $this->scopeTree;
  1475.  
  1476.         if (is_string($scope)===true{
  1477.             $scope explode('.'$scope);
  1478.         }
  1479.  
  1480.         if ($absolute===true{
  1481.             $this->scope =$this->data;
  1482.             $this->scopeTree array();
  1483.         }
  1484.  
  1485.         while (($bit array_shift($scope)) !== null{
  1486.             if ($bit === '_' || $bit === '_parent'{
  1487.                 array_pop($this->scopeTree);
  1488.                 $this->scope =$this->data;
  1489.                 $cnt count($this->scopeTree);
  1490.                 for ($i=0;$i<$cnt;$i++)
  1491.                     $this->scope =$this->scope[$this->scopeTree[$i]];
  1492.             elseif ($bit === '__' || $bit === '_root'{
  1493.                 $this->scope =$this->data;
  1494.                 $this->scopeTree array();
  1495.             elseif (isset($this->scope[$bit])) {
  1496.                 $this->scope =$this->scope[$bit];
  1497.                 $this->scopeTree[$bit;
  1498.             else {
  1499.                 unset($this->scope);
  1500.                 $this->scope null;
  1501.             }
  1502.         }
  1503.  
  1504.         return $old;
  1505.     }
  1506.  
  1507.     /**
  1508.      * [runtime function] returns the entire data array
  1509.      *
  1510.      * @return array 
  1511.      */
  1512.     public function getData()
  1513.     {
  1514.         return $this->data;
  1515.     }
  1516.  
  1517.     /**
  1518.      * [runtime function] returns a reference to the current scope
  1519.      *
  1520.      * @return &mixed 
  1521.      */
  1522.     public function &getScope()
  1523.     {
  1524.         return $this->scope;
  1525.     }
  1526.  
  1527.     /**
  1528.      * [runtime function] forces an absolute scope
  1529.      *
  1530.      * @deprecated
  1531.      * @see setScope
  1532.      * @param mixed $scope a scope as a string or array
  1533.      * @return array the current scope tree
  1534.      */
  1535.     public function forceScope($scope)
  1536.     {
  1537.         return $this->setScope($scopetrue);
  1538.     }
  1539. }

Documentation generated on Sun, 03 Aug 2008 15:12:30 +0200 by phpDocumentor 1.4.0