Location: PHPKode > scripts > Siviglia Templating > siviglia-templates/templating/TemplateParser2.php
<?php
/*

  Siviglia Framework templating engine

  BSD License

  Copyright (c) 2012, Jose Maria Rodriguez Millan
  All rights reserved.

  Redistribution and use in source and binary forms, with or without modification, are permitted provided that 
  the following conditions are met:

  * Redistributions of source code must retain the above copyright notice, this list of conditions and 
    the following disclaimer.
  * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
    the following disclaimer in the documentation and/or other materials provided with the distribution.
  * Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or 
    promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
ARE DISCLAIMED. 
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


Please, send bugs, feature requests or comments to: 
 
dashiad at hotmail.com 
 
You can find more information about this class at: 
 
http://xphperiments.blogspot.com 

*/

include_once("Grammar.class.php");
define("WIDGET_EXTENSION","wid");      
function print_backtrace_and_exit($msg)
{
    echo $msg;
    exit();
}
function debug($msg)
{
    echo '<div style="color:red;padding:3p;color:white;font-family:Calibri">'.$msg.'</div>';
}
abstract class CGrammarParser {
    var $grammar;
    function createGrammar(& $grammarObj)
    {          
        $this->grammar=$grammarObj;
       
        $funcs=array_keys($this->grammar->params["nt"]);
        $prefix=create_function('$a','return "eval_".$a;');
        
        $nonTerminals=array_map($prefix,$funcs);
        for($k=0;$k<count($nonTerminals);$k++)
        {
            $callbackName=$nonTerminals[$k];
            if(!method_exists(get_called_class(),$callbackName))
                $callbackName="defaultCallback";
            $callbacks[substr($nonTerminals[$k],5)]=new FunctionObject($this,$callbackName);
        }
        $this->grammar->setPointCuts($callbacks);
    }
    abstract function initializeGrammar();
    function compile($text)
    {
        $output=$this->grammar->compile($text);

        if($output=="")
        {
            echo "There's an error in the following template:";
            echo "<pre>".htmlentities($text)."</pre>";
            echo "<br><br>Exiting...";
            exit();
        }
        return $output;
    }
    function defaultCallback($data)
    {
        //echo "<div style=\"background-color:red;color:white;margin:1px\">LLAMADO DEFAULTCALLBACK";
        //print_r($data);
        //echo "</div>";
        return $data;
    }

}

class CWidgetGrammarParser extends CGrammarParser {


    function __construct($codeExpr,$curLevel,$parentWidget,$manager)
    {       
        $this->parentWidget=$parentWidget;
        $this->layoutManager=$manager;
        $this->codeExpr=$codeExpr;
        $this->curLevel=$curLevel;
        $this->initializeGrammar();
    }
    function initializeGrammar()
    {
    include_once(SIVIGLIA_PATH."/Grammar.class.php");
    $this->grammar= new Grammar(array(
            'root'=>'code',
            'nt'=>array(

            'tag_close_start'=>new Symbol("[#"),
            'tag'=>new EregSymbol("~[/a-zA-Z0-9_]+~"),
            
            'widget_open_start'=>new EregSymbol("~\[[*@]:*~"),
            'tag_open_start'=>new EregSymbol("~\[_:*~"),
            'tag_close'=>new Symbol("]"),
            'content_tag_start'=>new EregSymbol("~\[_\*~"),
            'php_identifier'=>new EregSymbol("~\$[a-zA-Z_][a-zA-Z0-9_]*~"),
            'html_text'=>new EregSymbol("~([^[<{]++|\[(?![#@_*])|<(?![?])|\{(?![%]))*~ms"),
            'php_text'=>new EregSymbol("~<\?php?.*\?>~sU"),
            'passthruText'=>new AltParser(array("text"=>new SubParser("html_text"),"php"=>new SubParser("php_text"))),
            'datasource_text'=>new EregSymbol("~\{%([^%]|%(?!\}))*%\}~"),
            "datasource_end"=>new Symbol("{%end%}"),
            //"json_tag"=>new EregSymbol('~"[a-zA-Z0-9_]+"~'),
            //"json_str"=>new EregSymbol('~"[^"]*"~'),
            //"json_number"=>new EregSymbol("~[+-]*[0-9]*[\.]*[0-9]*~"),
            "json_value"=>new AltParser(array(new EregSymbol('~"[^"]*"~'),
                                        new EregSymbol("~[+-]*[0-9]*[\.]*[0-9]*~"),
                                        new SubParser(json_expr))),
                
            "json_assignable"=>new AltParser(array(new SubParser("json_value"),new SubParser("json_array"))),
            "json_array"=>new SeqParser(array(new Symbol("["),
                                              new ListParser(new SubParser("json_assignable"),new Symbol(",")),
                                              new Symbol("]"))
                                        ),
            "json_assign_expr"=>new SeqParser(array("tag"=>new EregSymbol('~"[a-zA-Z0-9_]+"~'),
                                                           new Symbol(":"),
                                                            "data"=>new SubParser("json_assignable"))),
                
            "json_expr"=>new SeqParser(array(new Symbol("{"),new ListParser(new SubParser("json_assign_expr"),new Symbol(",")),new Symbol("}"))),
            "tagDefinition"=>new SeqParser(array(new SubParser("json_expr"))),
            "tagParams"=>new SeqParser(array(new Symbol("("),"expr"=>new SubParser("json_expr"),new Symbol(")"))),
            "content_tag"=>new SeqParser(array(
                            new SubParser("content_tag_start"),
                            new MaybeParser(new SeqParser(array("parameters"=>new SubParser("tagParams")))),
                            new Symbol("]"))),
             "widget_open_tag"=>new SeqParser(array(
                                            "openTag"=>new EregSymbol("~\[[*@]:*~"),
                                            "tag"=>new EregSymbol("~[/a-zA-Z0-9_]+~"),
                                            "parameters"=>new MaybeParser(new AltParser(array(
                                                                                "tagDefinition"=>new SubParser("tagDefinition"),
                                                                                "tagParams"=>new SubParser("tagParams")
                                                                                )
                                                                                         )
                                                                           ),
                                            "control"=>new MaybeParser(new EregSymbol("~<\?php?.*\?>~sU")),
                                            new SubParser("tag_close")
                                                )
                                              ),
                "open_tag"=>new SeqParser(array(
                                            "openTag"=>new EregSymbol("~\[_:*~"),
                                            "tag"=>new EregSymbol("~[/a-zA-Z0-9_]+~"),
                                            "parameters"=>new MaybeParser(new AltParser(array(
                                                                                "tagDefinition"=>new SubParser("tagDefinition"),
                                                                                "tagParams"=>new SubParser("tagParams")
                                                                                )
                                                                                         )
                                                                           ),
                                            "control"=>new MaybeParser(new EregSymbol("~<\?php?.*\?>~sU")),
                                            new SubParser("tag_close")
                                                )
                                           ),

              "close_tag"=>new SeqParser(array(new SubParser("tag_close_start"),new MaybeParser(new SubParser("tag")),
                                               "control"=>new MaybeParser(new EregSymbol("~<\?php?.*\?>~sU")),new SubParser("tag_close"))),
              "tag_contents"=>new MaybeParser(new AltParser(array(
                                                            "simpleText"=>new MultiParser(new AltParser(array(
                                                                                            "dataText"=>new SubParser("datasource_text"),
                                                                                            "passthru"=>new SubParser("passthruText"),
                                                                                            "content"=>new SubParser("content_tag"),
                                                                                            "subwidget"=>new SubParser("subwidget"),
                                                                                            "widget"=>new SubParser("widget")
                                                                                                             )
                                                                                                        )
                                                                                          ),
                                                            "compound"=>new SeqParser(array(
                                                                "dsstart"=>new SubParser("datasource_text"),
                                                                "subwidget"=>new SubParser("subwidget"),
                                                                "dsend"=>new SubParser("datasource_end")
                                                                )
                                                                                      )
                                                                 )
                                                            )
                                              ),

              "subwidget"=>new SeqParser(array("tag"=>new SubParser("open_tag"),"contents"=>new SubParser("tag_contents"),"tag_close"=>new SubParser("close_tag"))),
              "widget"=>new SeqParser(array("tag"=>new SubParser("widget_open_tag"),"contents"=>new SubParser("tag_contents"),"tag_close"=>new SubParser("close_tag"))),
                
              "subwidgetFile"=>new SeqParser(array("contents"=>new SubParser("tag_contents"))),
              "layoutFile"=>new MultiParser(new AltParser(array(new SubParser("passthruText"),new SubParser("widget")))),
              "code"=>new SubParser("subwidgetFile")
        

            )
            ));
    $this->createGrammar($this->grammar);
    }
    var $treeRoot;

    function eval_php_assign_block($params)
    {   
        
        $nParams=count($params["assigns"]);
        $assigns=array();
        for($k=0;$k<$nParams;$k++)
        {
            $curAssign=$params["assigns"][$k];
            $assigns[]=array("VAR"=>$curAssign["id"],"TAG"=>$curAssign["tag"]["tag"]);
        }
        return new CAssignBlock($assigns,$this->parentWidget);
    }

    //         tag_contents::= dataText=><datasource_text> || 
    //                         simpleText=>( passthru=><passthruText>
    //                                     || subwidget=><subwidget> 
    //                                     || widget=><widget>)* 
    //                        || compound=>(dsstart-><datasource_text> subwidget-><subwidget> dsend-><datasource_text>).
    //
    //         subwidget::=  tag-><open_tag>           assign->[ assign_block-><php_assign_block> ] contents-><tag_contents> tag_close-><close_tag>.                
    //         widget::=     widget-><widget_open_tag> assign->[ assign_block-><php_assign_block> ] contents-><tag_contents> tag_close-><close_tag>.
    //
    //         code::= <widget>.

    /**
     * 
     *    EVALUACION DE ESTRUCTURA JSON:
     * 
     **/
    function eval_json_value($params)
    {

        return $params["result"];
    }
    function eval_json_assignable($params)
    {
        return $params["result"];
    }
    function eval_json_array($params)
    {
        return "[".implode("",$params[1])."]";

    }
    function eval_json_assign_expr($params)
    {
        return $params["tag"].":".$params["data"];
    }
    function eval_json_expr($params)
    {
        return "{".implode("",$params[1])."}";
    }
    /**
     * FIN DE EVALUACION DE JSON
     */

    function eval_content_tag($params)
    {
        $contentTag=new CContentTag($this->parentWidget);
        $contentTag->level=$this->curLevel;
        if($params["parameters"])            
            $contentTag->setParams(json_decode($params["parameters"],true));

        return $contentTag;
    }
    
    function common_widget_eval($params,$className)
    {
        $subwidgetPrefix=$params["tag"]["openTag"];
        $h=$params["tag"];
        
        $len=strlen($subwidgetPrefix);
        
        if($subwidgetPrefix[1]=="@") // Es un plugin
        {
            $isPlugin=true;
        }
        $level=strlen($subwidgetPrefix)-2;

        $subwidgetTag=$params["tag"]["tag"];
        $widgetPath=null;
        if($subwidgetTag[0]=="/")
        {
            $parts=explode("/",$subwidgetTag);
            $nParts=count($parts);
            $tagName=$parts[$nParts-1];
            unset($parts[$nParts-1]);
            $widgetPath=implode("/",$parts);
            
        }
        else
            $tagName=$subwidgetTag;

        $subWidget=new $className($tagName,$this->parentWidget,$this->layoutManager);
        $subWidget->setControl($params["tag"]["control"],$params["tag_close"]["control"]);
        
        if($widgetPath)
            $subWidget->setPath($widgetPath);
        if($isPlugin)
        {
            $subWidget->setPlugin(true);
        }
        $paramExpr=$params["tag"]["parameters"]["result"]["expr"];
        $param1=$params["tag"]["parameters"];
        if($paramExpr)
        {
            
            $subWidget->setParams(json_decode($paramExpr,true));
        }

        $definitionExpr=$params["tag"]["parameters"]["result"]["tagDefinition"]["expr"];

        if($definitionExpr)
        {
            $subWidget->setDefinition(json_decode($definitionExpr));
        }



        $subWidget->setLevel($level+$this->curLevel);
        $subWidget->setRelativeLevel($level);
        $assign=$params["assign"];
        if($assign)
        {

            $assignObj=new CAssignBlock($params["assign"]["assign_block"],$this->parentWidget);
            $subWidget->addAssignBlock($assignBlock);
        }
        if(!is_array($params["contents"]))
        {
            if($params["contents"])
                $subWidget->addContent($params["contents"]);        
        }
        else
        {
            $nContents=count($params["contents"]);
            for($k=0;$k<$nContents;$k++)
                $subWidget->addContent($params["contents"][$k]);                
        }        
        return $subWidget;
    }

    function eval_subwidget($params)
    {
        return $this->common_widget_eval($params,"CSubWidget");
    }
    function eval_widget($params)
    {
        $common=$this->common_widget_eval($params,"CWidget");
        $common->subLoad();
        return $common;
    }
    
    function eval_passthruText($params)
    {
        switch($params["selector"])
        {
        case "text":
            {
                $trimmed=trim($params["result"]);
                if($trimmed[0]=="$" )
                    $el = new CPHPElement("<?php echo ".$trimmed.";?>",$this->parentWidget);
                else
                    $el= new CHTMLElement($params["result"],$this->parentWidget);
            }break;
        case "php":
            {
                $el= new CPHPElement($params["result"],$this->parentWidget);
            }break;
        }
        $el->level=$this->curLevel;
        return $el;
    }

    function eval_datasource_text($params)
    {   
        $el=new CDataSourceElement($params,$this->parentWidget);             
        $el->level=$this->curLevel;
        return $el;
    }

    /**
     *         tag_contents::= dataText-><datasource_text> || simpleText=>( passthru-><passthruText>
                               || subwidget-><subwidget> 
                               || widget-><widget>)*.
     */
    function eval_tag_contents($params)
    {
        
        switch($params["selector"])
        {
        case "dataText":
            {                
                return $params["result"];
            }break;
        case "simpleText":
            {
                $nItems=count($params["result"]);
                for($k=0;$k<$nItems;$k++)
                {
                    $results[]=$params["result"][$k]["result"];
                }                
                return $results;
            }break;            
        }
    }
    function eval_subwidgetFile($param)
    {
        $el= new SubWidgetFile($param["assign"],$param["contents"],$this->parentWidget);
        $el->level=$this->curLevel;
        return $el;
    }
    function eval_layoutFile($param)
    {
        $nParams=count($param);
        for($k=0;$k<$nParams;$k++)
        {
            $results[]=$param[$k]["result"];
        }
        $el= new SubWidgetFile(null,$results,$this->parentWidget);
        $el->level=$this->curLevel;
        return $el;
    }
}


abstract class CLayoutElement
{
    var $parentWidget;
    function __construct($parentWidget)
    {
        $this->parentWidget=$parentWidget;
    }
    abstract function getClone();
    function cloneContents($arr)
    {
        if(!is_array($arr))
        {
           $c=array($arr);
        }
        else
            $c=& $arr;
        $result=array();
        $nEl=count($c);
        for($k=0;$k<$nEl;$k++)
        {
            if(!$c[$k])
                continue;
            /*
            if(!is_object($c[$k]))
            {
                debug($this->contents);
            }
            if(!is_object($c[$k]))
            {
                _d($this);
            } 
            */ 
            $result[]=$c[$k]->getClone();
        }
        return $result;
    }
}

class CAssignBlock extends CLayoutElement{
    function __construct($contents,$parentWidget)
    {
        CLayoutElement::__construct($parentWidget);
        $this->preparedContents=$contents;
    }
    function prepare($level,$contents,$parentNode)
    {
        return $this;
    }

    function process()
    {
        return $this->preparedContents;
    }
    function getClone()
    {
        return new CAssignBlock($this->preparedContents,$this->parentWidget);
        
    }
}



class CPHPElement extends CLayoutElement{
    var $preparedContents;
    function __construct($contents,$parentWidget,$processed=0)
    {        
        CLayoutElement::__construct($parentWidget);
        $this->preparedContents=$contents;
        if(!$processed)
        {
            $currentPrefix="";
            if($parentWidget)
            {
                $currentPrefix=$parentWidget->getPrefix();
            }
            
            $this->remapVariables($currentPrefix);
            
        }
    }

    function remapVariables($prefix)
    {
        if($this->parentWidget)
            $state=$this->parentWidget->getPHPState();
        else
            $state["CONTEXT"]="global";

        $tokens=token_get_all($this->preparedContents);
        $nTokens=count($tokens);
        $newText="";
        $k=0;   
        $globalVars=array();
        
        while($k < $nTokens)
        {
    
        if(is_array($tokens[$k]))
        { 
                     
            if($oldPrefix)
            {
                $prefix=$oldPrefix;
                $oldPrefix="";
            }
            if($lastWasObject)
            {
                $newText.=$tokens[$k][1];
                $lastWasObject=false;
                $k++;
                continue;
            }
            if($lastWasGlobal  && $tokens[$k][0]!=T_WHITESPACE )
            {
                $lastWasGlobal=false;
                if($this->parentWidget)
                    $this->parentWidget->addGlobal($tokens[$k][1]);                

            }
            if($this->parentWidget)
            {
                if($this->parentWidget->isGlobal($tokens[$k][1]))
                {                
                    
                    $oldPrefix=$prefix;
                    $prefix="";
                }
            }
            else
            {
                
                
                $prefix="";
            }
            
            switch($tokens[$k][0])
            {
                
                //case T_OPEN_TAG:{$newText.='<?php ';echo "<h1>OPEN</h1>";}break;
                //case T_OPEN_TAG_WITH_ECHO:{$newText.='<?=';}break;
                case T_STRING_VARNAME:{$newText.='$'.$prefix.substr($tokens[$k][1],1);}break;
                case T_ENCAPSED_AND_WHITESPACE:{$newText.='$'.$prefix.substr($tokens[$k][1],1);}break;
            case T_FUNCTION:{
                if($state["CONTEXT"]=="global")
                    $state["CONTEXT"]="function";
                $newText.=$tokens[$k][1];
            }break;
                case T_VARIABLE:{
                        if($state["CONTEXT"]=="global")
                        $newText.='$'.$prefix.substr($tokens[$k][1],1);
                        else
                            $newText.=$tokens[$k][1];
                    }break;
                case T_DOUBLE_COLON:
                case T_OBJECT_OPERATOR:{$lastWasObject=true;$newText.=$tokens[$k][1];}break;
                case T_GLOBAL:{$lastWasGlobal=true;$newText.=$tokens[$k][1];
                    }break;
                default:
                {
                    $newText.=$tokens[$k][1];
                }
            }
        }
        else 
        {
            $lastWasObject=false;
            $newText.=$tokens[$k];
            if($state["CONTEXT"]!="global")
            {
            
                if($tokens[$k]=="{")
                    $state["BRACKETS"]++;
                if($tokens[$k]=="}")
                {
                    $state["BRACKETS"]--;
                    if($state["BRACKETS"]==0)
                        $state["CONTEXT"]="global";
                }
            }

        }
        
        $k++;
    }
    
        $this->preparedContents=$newText;
         if($this->parentWidget)
            $state=$this->parentWidget->setPHPState($state);
    }
    function prepare($level,$contents,$parentNode)
    {
        return $this;
    }
    function process()
    {
        return $this->preparedContents;
    }
    function getClone()
    {
                return new CPHPElement($this->preparedContents,$this->parentWidget,1);
    }
}

class CHTMLElement extends CLayoutElement  {
    var $preparedContents;
    function __construct($contents,$parentWidget)
    {
        CLayoutElement::__construct($parentWidget);
        $this->preparedContents=$contents;                               
    }
    function prepare($level,$value,$currentNode)
    {
        return $this;
    }
    
    function process()
    {
        return $this->preparedContents;
    }
    function getClone()
    {
        return new CHTMLElement($this->preparedContents,$this->parentWidget);
    }
}

class CDataSourceElement extends CLayoutElement {
    function __construct($contents,$parentWidget)
    {
        CLayoutElement::__construct($parentWidget);
        $this->preparedContents=$contents;
    }
    function prepare($level,$contents,$parentNode)
    {
        return $this;
    }
    function getClone()
    {
        //$contentClone=$this->cloneContents($this->contents);
        return new CDataSourceElement($this->preparedContents,$this->parentWidget);
    }


    function process()
    {
        return $this->preparedContents;
    }
}

class CContentTag extends CLayoutElement{

    
    var $contents=array();
    var $processed=false;

    function setValue($contents)
    {
        if(!$contents)
            return $this;
        if($contents[0]==$this)
            $h=1;
        if($this->processed==true)
        {
            for($k=0;$k<count($this->contents);$k++)
            {
                if(method_exists($this->contents[$k],"setValue"))
                    $newContents[]=$this->contents[$k]->setValue($contents);
                else
                    $newContents[]=$this->contents[$k];
            }
            $this->contents=$newContents;
        }
        else
        {
            $this->processed=true;
            $nLayout=count($contents);
            for($k=0;$k<$nLayout;$k++)
            {
                    if(is_a($contents[$k],"CWidget"))
                    {

                        if(!$contents[$k]->parsed)
                            $this->contents[]=$contents[$k]->subLoad();
                        else
                            $this->contents[]=$contents[$k];
                    }
                    else
                    {
                        if(is_a($contents[$k],"CSubWidget"))
                        {
                            if($contents[$k]->level==$this->level-1)
                            {
                                debug("ERROR: SUBTAG DESCONOCIDO:".$contents[$k]->name);
                            }
                        }
                        if($contents[$k]==$this)
                        {
                            $this->processed=false;
                            $this->contents=array();
                        return $this;
                    }
                        $this->contents[]=$contents[$k];
                    }
            }
        }        
        return $this;
    }
     function setParams($params)
        {
            
            $this->params=$params;
        }
       
    function getClone()
    {
        $newContent=new CContentTag($this->parentWidget);
        $newContent->contents=$this->cloneContents($this->contents);
        $newContent->level=$this->level;
        $newContent->processed=$this->processed;
        $newContent->params=$this->params;

        return $newContent;
    }
}

abstract class CWidgetItem extends CLayoutElement {
    var $name;
    var $assignBlock;
    var $contents;
    var $startBlockControl;
    var $endBlockControl;

        function __construct($name,$parentWidget)
        {
            
            CLayoutElement::__construct($parentWidget);
            
            $this->name=$name;
            
        }
        function setControl($startBlock,$endBlock)
        {
          
        if($startBlock)
            $this->startBlockControl=new CPHPElement($startBlock,$this->parentWidget);
        if($endBlock)
            $this->endBlockControl=new CPHPElement($endBlock,$this->parentWidget);
        }
        function addAssignBlock($block)
        {
            $this->assignBlock=$block;
        }
        function addContent($content)
        {
            $this->contents[]=$content;
        }
        
        function setLevel($level)
        {
            $this->level=$level;
        }
        function setRelativeLevel($relLevel)
        {
            $this->relativeLevel=$relLevel;
        }
        function setParentTag($tag)
        {
            $this->parentTag=$tag;
        }   
        function setParams($params)
        {
            
            $this->params=$params;
        }
        function setDefinition($definition)
        {
            $this->definition=$definition;
        }
        function commonClone($clone)
        {
            $clone->level        = $this->level;
            $clone->parentTag    = $this->parentTag;
            $clone->contents     = $this->cloneContents($this->contents);
            $clone->relativeLevel= $this->relativeLevel;
            $clone->definition   = $this->definition;
            $clone->params       = $this->params;
            $clone->processed    = $this->processed;
            $clone->startBlockControl=$this->startBlockControl;
            $clone->endBlockControl=$this->endBlockControl;
            return $clone;
        }    
         function setValue($val)
        {
            if($this->processed==true)
            {
                for($k=0;$k<count($this->contents);$k++)
                {
                     if(method_exists($this->contents[$k],"setValue"))
                         $result=$this->contents[$k]->setValue($val);                        
                }
                return $this;
            }
            
            $this->processed=true;
            $nVals=count($val);
            $finalResults=array();
            for($k=0;$k<$nVals;$k++)
            {                
                if($val[$k]->name==$this->name)
                {                    
                    if(!($val[$k]->level==$this->level-1))
                    {
                        for($j=0;$j<count($this->contents);$j++)
                        {
                            if( method_exists($this->contents[$j],"setValue") )
                            {
                                $newContents[]=$this->contents[$j]->setValue($val[$k]->contents);
                            }
                            else
                                $newContents[]=$this->contents[$j];
                        }
                        continue;
                    }
                    $instance=$this->getClone();
                    $instance->setParentTag($this);
                    $instance->params=$val[$k]->params;
                    $instance->processed=true;
                    $instance->definition=$val[$k]->definition; 

                    // Control blocks are copied to the clone, without copying it to ourselves.
                    // Note that, the generated tree for a certain [_A] tag , has a "generic" [_A] root (the $this), with children ($instance)
                    // that are copies of this node, for each [_A] in the template.The startBlock and endBlock are related to those children,
                    // and not to the generic [_A] root.
                    $instance->startBlockControl=$val[$k]->startBlockControl;
                    $instance->endBlockControl=$val[$k]->endBlockControl;
                                                            
                    for($j=0;$j<count($instance->contents);$j++)
                    {                       
                        if(method_exists($instance->contents[$j],"setValue"))
                        {
                             $instance->contents[$j]->setValue($val[$k]->contents);
                        }                                                
                    }                                        
                    $newContents[]=$instance;
                }
               
            }
            
            

            $this->contents=$newContents;
            return $this;   
            
        }         
}

class SubWidgetFile extends CWidgetItem
{
    function __construct($assign,$contents,$parentWidget)
    {
        $this->assignBlock=$assign;
        $this->contents=$contents;
        CWidgetItem::__construct(null,$parentWidget);
    }
    function setName($name)
    {
        $this->name=$name;
    }
    function getClone()
    {
        $obj=new SubWidgetFile($this->assignBlock,null,$this->parentWidget);
        $this->commonClone($obj);
        $obj->assignBlock=$this->assignBlock;
        return $obj;
    }
}

class CWidget extends CWidgetItem{
    var $isPlugin;
    var $pluginProcessed;
    var $parsed=false;
    var $widgetPath;
    var $finalPath;
    var $phpState=null;
    
    function __construct($name,$parentWidget,$layoutManager)
    {
        $this->layoutManager=$layoutManager;
        
        $this->varPrefix=$this->layoutManager->getVarPrefix($name);
        CWidgetItem::__construct($name,$parentWidget);
    }
    function getPHPState()
    {
        if($this->phpState==null)
            return array("CONTEXT"=>"global");
        return $this->phpState;
    }
    function setPHPState($state)
    {
        $this->phpState=$state;
    }
    

    function setPath($path)
    {
        $this->widgetPath=$path;
    }
    function getPrefix()
    {
        return $this->varPrefix;
    }
    function addGlobal($varName)
    {
        $this->globalVars[$varName]=1;
    }
    function isGlobal($varName)
    {
        return $this->globalVars[$varName]==1;
    }
    function setPlugin($val)
    {
        $this->isPlugin=$val;
    }
    
    function subLoad()
    {
        
        
        if($this->isPlugin)
        {
            if(!$this->pluginProcessed)
            {
                $this->contents=$this->parsePlugin();
                $this->layout=$this;
            }
            $this->pluginProcessed=true;
            
            return $this;
        }
        
        //$this->parentWidget=$parentWidget;
       
        
        //flush();
        $layout=$this->getDefinition($this->name);
        $this->layoutManager->addDependency($this->finalPath,$this->isPlugin?"plugin":"widget");
        $this->setValue($this->contents);
        
       
        return $this;
    }

    function setValue($contents)
    {
            
        $layout=$this->layout;
        $nContents=count($layout->contents);
        $curResult=array();
        $newContents=array();

        for($k=0;$k<$nContents;$k++)
        {
            
                if(method_exists($layout->contents[$k],"setValue"))
                {
                    $layout->contents[$k]->setValue($contents);
                    $result=$layout->contents[$k];
                }
                else
                    $result=$layout->contents[$k];             
                $newContents[]=$result;
        }
        
        $this->contents=$newContents;
        $this->layout->contents=$this->contents;         
        $this->parsed=true;
        return $this;
        
    }
   

    function parsePlugin()
    {
        return $this->layoutManager->parsePlugin($this,$this->name,$this->contents);
        
        //$pluginTree=new CWidgetGrammarParser("<layoutFile>",$this->level+1,$this,$this->layoutManager);
        //return $pluginTree->compile($this->contents);
    }
    
    function getDefinition($name)
    {
        

        $widgetFile=$this->layoutManager->findWidget($this->name,$this->finalPath,$this->widgetPath);

        //$contents=$this->extractNodes($contents);

        // Del contenido, se extraen los scripts y el css
        
        $widgetDef=$oParser=new CWidgetGrammarParser("subwidgetFile",$this->level+1,$this,$this->layoutManager);
        $this->layoutManager->currentWidget=array("FILE"=>$this->finalPath,"NAME"=>$this->name);

        $this->layout=$oParser->compile($widgetFile,$this->layoutManager->getLang(),$this->layoutManager->getTargetProtocol());
        if(!$this->layout)
        {
            debug("ERROR AL COMPILAR ".$this->name);
            exit();
        }
        
        $this->layout->setName($this->name);
        return $this->layout;
    }
  /*  function extractNodes($contents)
    {

        // Para evitar que el parser HTML elimine el codigo PHP, se sustituyen los bloques de PHP por ids unicos
        // Estos ids unicos se restauran a codigo php al final de la funcion

        $subs=array();


        $callback=function($match) use (&$subs)
        {
            $id=uniqid();$subs[$id]=$match[0];return $id;};
        $contents=preg_replace_callback("/((?:<\?(?:php|=| )).*?\?>)/s",$callback,$contents);
        $contents=str_replace("&","#@#",$contents);
        
        // Se encierran los contenidos dentro de un div, para poder eliminar mas facilmente
        // los tags DOCTYPE,HTML,BODY aniadidos por saveHTML
        $contents="<div>".$contents."</div>";
        $doc=new DomDocument();      
        $doc->recover=true;
        $doc->strictErrorChecking=false;
        $doc->substituteEntities=false;
        $doc->loadHTML($contents);
        $extractTags=array("script","style","link","meta");
        
        $isProcessed=$this->layoutManager->isProcessed($this->name);
        for($j=0;$j<count($extractTags);$j++)
        {
            $elems=$doc->getElementsByTagName($extractTags[$j]);
         
            if(!$isProcessed)
            {
                for($k=0;$k<$elems->length;$k++)        
                {
                    $item=$elems->item($k);
                    $length = $item->attributes->length;
                    $attrParts=array($item->tagName);
                    for ($i = 0; $i < $length; ++$i) {
                        $name = $item->attributes->item($i)->name;
                        $value= $item->getAttribute($name);
                        $attrParts[]=$name.'="'.$value.'"';                
                        }                            
                    $data='<'.implode(" ",$attrParts).'>'.$item->textContent.'</'.$item->tagName.'>';
                    $this->layoutManager->addStaticData($this->name,$extractTags[$j],$data);
                }
            }
            for($k=0;$k<$elems->length;$k++)
            {
                $this->helper_deleteNode($elems->item(0));
            }
        }
        $newContent=$doc->saveHTML();
        $newContent=substr($newContent,strpos($newContent,"<div>")+5);
        $newContent= preg_replace(array('#</div></body></html>.#s'),
                                  array(''),
                                  $newContent,-1,$nElems);
        // Se restaura el codigo php
        $newContent=str_replace(array_keys($subs),array_values($subs),$newContent);
        $newContent=str_replace("#@#","&",$newContent);
        
        return $newContent;
    }*/    
    function getClone()
    {
        $obj=new CWidget($this->name,$this->parentWidget,$this->layoutManager);
        $this->commonClone($obj);
        if(!$this->isPlugin)
        {
            $obj->layout=$this->layout->getClone();
        }
        else
            $obj->layout=$obj;
        $obj->isPlugin=$this->isPlugin;
        
        $obj->pluginProcessed=$this->pluginProcessed;
        $obj->varPrefix=$this->varPrefix;
        return $obj;
    }
    function helper_deleteNode($node) { 
        $this->helper_deleteChildren($node); 
        $parent = $node->parentNode; 
        $oldnode = $parent->removeChild($node); 
        } 

    function helper_deleteChildren($node) { 
        while (isset($node->firstChild)) { 
            $this->helper_deleteChildren($node->firstChild); 
            $node->removeChild($node->firstChild); 
            } 
        } 

}

class CSubWidget extends CWidgetItem {
    function __construct($subwidgetTag,$parentWidget)
    {    
        CWidgetItem::__construct($subwidgetTag,$parentWidget);
    }
    function getClone()
    {
        $obj=new CSubWidget($this->name,$this->parentWidget);
        return $this->commonClone($obj);
    }
}


class CLayoutManager
{
    var $dependencies;
    var $widgetPath;
    var $pluginParams;
    var $lang;
    var $currentWidget;
    var $currentLayout;
    var $initializedPlugins=array();
    var $varCounter=0;
    
    function __construct($targetProtocol,$widgetPath,$pluginParams=array(),$lang="es")
    {
        $this->targetProtocol=$targetProtocol;
        $this->widgetPath=$widgetPath;
        $this->dependencies=array();
        $this->staticData=array();
        $this->pluginParams=$pluginParams;
        $this->lang=$lang;
        
    }
    function getTargetProtocol()
    {
        return $this->targetProtocol;
    }
    function getLang()
    {
        return $this->lang;
    }
    function addDependency($widgetName,$widgetType="widget",$pluginParam=null)
    {
        if($widgetName=="")
            return;

        $this->dependencies[$widgetName]["TYPE"]=$widgetType;
        if($widgetType=="plugin")
            $this->dependencies[$widgetName]["PARAM"][]=$pluginParam;
        
    }

    function getPluginParams($pluginName)
    {
        return $this->pluginParams[$pluginName];
    }
    function parsePlugin($parent,$name,$contents)
    {
        $pluginName=SIVIGLIA_PATH.'/'.$this->getTargetProtocol().'/plugins/'.$name.".php";
        include_once($pluginName);        
        $plugin=new $name($parent,$contents,$this);
        if(!in_array($pluginName,$this->initializedPlugins))
        {
            $plugin->initialize();
            $this->initializedPlugins[]=$pluginName;
        }
        return $plugin->parse();        
    }

    function getVarPrefix($widgetName)
    {
        return "v".($this->varCounter++);
        $widgetName=str_replace("/","_",$widgetName);
        $suffix="_".$this->suffixes[$widgetName]["COUNTER"];
        if($suffix=="_0")
            $suffix="";
        $this->suffixes[$widgetName]["COUNTER"]++;
        
        return $widgetName.$suffix;
    }
    function getLayout()
    {
        return $this->currentLayout;
    }
    function renderLayout($layoutDefinition,$layoutParser,$include=false)
    {
        
        $fileName=$layoutDefinition["TEMPLATE"];
        $this->currentLayout=$fileName;
        $targetDir=$layoutDefinition["TARGET"];

        if($targetDir)
            $compiledDir=$targetDir;
        else
        {
            $compiledDir=str_replace(PROJECTPATH,PROJECTPATH."/cache/",dirname($fileName))."/".$this->lang."/".$this->targetProtocol."/";
        }           
        $pathInfo=pathinfo($fileName);
        $base=$pathInfo["basename"];

        // El siguiente codigo  supone que la extension (ej, .wid) solo aparece al final del nombre de fichero.
        $suffix=$layoutDefinition["CACHE_SUFFIX"];
        if($suffix)
            $base=str_replace(".".$pathInfo["extension"],
                        $suffix[0]=="."?$suffix:".".$suffix,
                        $base
                        );
        

        $compiledFile=$compiledDir.$base;
        //include_once($compiledFile);
        //return;

        $depsFile=$compiledDir."deps_".$base;

        $this->currentWidget=array("FILE"=>$fileName);
        
        if(!is_file($compiledFile))
        {
            $mustRebuild=true;
        }
        else
        {
            
            clearstatcache();
            $mustRebuild=false;
            $compiledInfo=stat($compiledFile);
            $layoutInfo=stat($fileName);
            
            if($layoutInfo["mtime"] > $compiledInfo["mtime"])
                $mustRebuild=true;
     
                  
            if($mustRebuild==false)
            {
                
                if(!is_file($depsFile))
                    $mustRebuild=true;
                else
                {
                    $widgetDeps=explode(",",file_get_contents($depsFile));

                    foreach($widgetDeps as $key=>$value)
                    {
                        if($value[0]=="*")
                            continue;
                        
                        $widgetInfo=@stat($value);
                        if(!$widgetInfo || $widgetInfo["mtime"]>$compiledInfo["mtime"])
                        {
                            $mustRebuild=true;
                            break;
                        }
                    }
                }
            }
        }

        //$mustRebuild=true;
        if($mustRebuild)
        {
            $contents=file_get_contents($fileName);
                   
        
            $widgetParser=new CWidgetGrammarParser('layoutFile',1,null,$this);
            $layout=$widgetParser->compile($contents);            
            if($layout=="")
            {
                debug("ERROR DE COMPILACION DE PLANTILLA ".$fileName);
                exit();
            }
            
            $result=$layoutParser->process($layout,$this);
            
            @mkdir($compiledDir,0777,true);
            
            if(is_array($this->dependencies))
            {
                foreach($this->dependencies as $key=>$value)
                {
                    if($value["TYPE"]=="plugin")
                    {
                        $deps[]="*".$key."[".implode("@@",$value["PARAM"])."]";
                    }
                    else
                        $deps[]=$key;
                }
                if($deps)
                    file_put_contents($depsFile,implode(",",$deps));
            }
            // El texto final se envia a los plugins, para que hagan las
            // ultimas sustituciones.
            
            foreach($this->initializedPlugins as $pluginClass)
            {
                $cName=basename($pluginClass,".php");
                $obj=new $cName(null,null,$this);
                $result=$obj->postParse($result);
            }           
            file_put_contents($compiledFile,$result);
        }
        
        if($include)
        {                        
           include($compiledFile);
        }
        else
        {
            if($mustRebuild)
                return $result;
            else
            {
                $contents=file_get_contents($compiledFile);
                var_dump($contents);
                var_dump($compiledFile);
                return file_get_contents($compiledFile);
            }
        }
    }

    function findWidgetFile($widgetName,$widgetPath)
    {
        if(!$widgetPath)
            $widgetPath="";
        reset($this->widgetPath);
        foreach($this->widgetPath as $key=>$value)
        {
            //echo "TRYING ".PROJECTPATH.$value."/".$widgetPath."/".$widgetName.".".WIDGET_EXTENSION."<br>";
            if(is_file(PROJECTPATH.$value."/".$widgetPath."/".$widgetName.".".WIDGET_EXTENSION))
            {
            
                return PROJECTPATH.$value."/".$widgetPath."/".$widgetName.".".WIDGET_EXTENSION;
            }
        }
        
        return null;
    }
    function findWidget($widgetName,& $widgetLocation,$widgetPath=null)
    {
        $widgetFile=$this->findWidgetFile($widgetName,$widgetPath);
        
        if(!$widgetFile)
        {            
            return PROJECTPATH."/".$widgetPath[0]."/DEFAULT.wid";
        }
        $widgetLocation=$widgetFile;
        return file_get_contents($widgetFile);
    }

    function isProcessed($widgetName)
    {
        if($this->staticData[$widgetName])
            return true;
        return false;            
    }
    function addStaticData($widgetName,$datatype,$data)
    {
        $this->staticData[$widgetName][$dataType][]=$data;
    }
}
Return current item: Siviglia Templating