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

Documentation generated on Sat, 28 Jun 2008 01:38:19 +0200 by phpDocumentor 1.4.0