Source for file Dwoo.php

Documentation is available at Dwoo.php

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

Documentation generated on Sun, 07 Sep 2008 23:57:43 +0200 by phpDocumentor 1.4.0