PageRenderTime 235ms CodeModel.GetById 121ms app.highlight 15ms RepoModel.GetById 96ms app.codeStats 0ms

/atk4/lib/GiTemplate.php

https://github.com/mahimarathore/mahi
PHP | 311 lines | 243 code | 26 blank | 42 comment | 33 complexity | a758a48231470fd396da4c6e3638b4d2 MD5 | raw file
  1<?php // vim:ts=4:sw=4:et:fdm=marker
  2/*
  3 * Undocumented
  4 *
  5 * @link http://agiletoolkit.org/
  6*//*
  7==ATK4===================================================
  8   This file is part of Agile Toolkit 4
  9    http://agiletoolkit.org/
 10
 11   (c) 2008-2013 Agile Toolkit Limited <info@agiletoolkit.org>
 12   Distributed under Affero General Public License v3 and
 13   commercial license.
 14
 15   See LICENSE or LICENSE_COM for more information
 16 =====================================================ATK4=*/
 17/**
 18  * Really fast template parser.
 19  *
 20  * This parser is based on SMlite, but is 2-3 times faster than it. Symantically it 
 21  * works in the same way, but 
 22  */
 23
 24class GiTemplate extends AbstractModel {
 25
 26    public $template=array();
 27    // Parsed template consists of String, String, String, String, String.
 28    //   If there is tag on any of those, it will have reference from $tags array
 29    public $tags=array();
 30
 31    public $top_tags=array('_top');
 32
 33    public $default_exception='Exception_Template';
 34
 35    public $template_file=null;
 36
 37    public $source='';
 38
 39    public $template_type='template';
 40
 41    function __clone(){
 42        parent::__clone();
 43
 44        $x=unserialize(serialize($this->template));
 45        unset($this->template);
 46        $this->template=$x;
 47
 48        unset($this->tags);
 49        $this->rebuildTags();
 50    }
 51    function isTopTag($tag){
 52        return in_array($tag,$this->top_tags);
 53    }
 54    function getTagRef($tag,&$template){
 55        if($this->isTopTag($tag)){
 56            $template=&$this->template;
 57            return $this;
 58        }
 59        @list($tag,$ref)=explode('#',$tag);
 60        if(!$ref)$ref=1;
 61        if(!isset($this->tags[$tag][$ref-1])){
 62            throw $this->exception('Tag not found in Template')
 63                ->setTag($tag);
 64        }
 65        $template=$this->tags[$tag][$ref-1];
 66        return $this;
 67    }
 68    function getTagRefList($tag,&$template){
 69        if($this->isTopTag($tag)){
 70            $template=&$this->template;
 71            return false;
 72        }
 73        @list($tag,$ref)=explode('#',$tag);
 74        if(!$ref){
 75            if(!isset($this->tags[$tag])){
 76                throw $this->exception('Tag not found in Template')
 77                    ->setTag($tag);
 78            }
 79            $template=$this->tags[$tag];
 80            return true;
 81        }
 82        if(!isset($this->tags[$tag][$ref-1])){
 83            throw $this->exception('Tag not found in Template')
 84                ->setTag($tag);
 85        }
 86        $template=&$this->tags[$tag][$ref-1];
 87        return false;
 88    }
 89    function is_set($tag){
 90        var_Dump($tag);
 91        if($this->isTopTag($tag))return true;
 92        @list($tag,$ref)=explode('#',$tag);
 93        if(!$ref)$ref=1;
 94        var_Dump(isset($this->tags[$tag][$ref-1]));
 95        return isset($this->tags[$tag][$ref-1]);
 96    }
 97    function cloneRegion($tag){
 98        if($this->isTopTag($tag))return clone $this;
 99
100        $n=$this->owner->add(get_class($this));
101        $n->template=$this->get($tag);
102        $n->rebuildTags();
103        $n->top_tags[]=$tag;
104        $n->source='Clone ('.$tag.') of '.$this->source;
105        return $n;
106    }
107    function dumpTags(){
108        throw $this->exception('Requested to dump tags');
109    }
110    function get($tag){
111        $template=array();
112        $this->getTagRef($tag,$template);
113        return $template;
114    }
115    function append($tag,$value,$delim=false){
116        $this->getTagRef($tag,$template);
117        if($delim)$template[]=$delim;
118        $template[]=$value;
119        return $this;
120    }
121    function set($tag,$value=null){
122        if(is_array($tag)){
123            if(is_null($value)){
124                // USE(2)
125                foreach($tag as $s=>$v){
126                    $this->trySet($s,$v);
127                }
128                return $this;
129            }
130            if(is_array($value)){
131                // USE(2)
132                reset($tag);reset($value);
133                while(list(,$s)=each($tag)){
134                    list(,$v)=each($value);
135                    $this->set($s,$v);
136                }
137                return $this;
138            }
139            throw $this->exception("Incorrect argument types when calling Template->set()");
140        }
141
142        if($this->getTagRefList($tag,$template)){
143            foreach($template as $key=>&$ref){
144                //var_Dump($template[$key]);
145                $ref=array($value);
146            }
147        }else{
148            $template=array($value);
149        }
150        return $this;
151    }
152    function trySet($tag,$value=null){
153        if($this->is_set($tag) || is_array($tag))return $this->set($tag,$value);
154        return $this;
155    }
156    function del($tag){
157        if($this->getTagRefList($tag,$template)){
158            foreach($template as $ref){
159                $ref=array();
160            }
161        }else{
162            $template=array();
163        }
164        return $this;
165    }
166    function tryDel($tag){
167        if($this->is_set($tag))return $this->del($tag);
168        return $this;
169    }
170    function eachTag($tag,$callable){
171        if(!$this->is_set($tag))return $this;
172        if($this->getTagRefList($tag,$template)){
173            foreach($template as $key=>$templ){
174                $ref=$tag.'#'.($key+1);
175                $this->tags[$tag][$key]=array(call_user_func($callable,$this->recursiveRender($templ),$ref));
176            }
177        }else{
178            $this->tags[$tag][0]=array(call_user_func($callable,$this->recursiveRender($template),$tag));
179        }
180        return $this;
181    }
182
183    function findTemplate($template_name){
184        /*
185         * Find template location inside search directory path
186         */
187        $f=$this->api->locatePath($this->template_type,$template_name.$this->settings['extension']);
188        return join('',file($f));
189    }
190    function loadTemplate($template_name,$ext=null){
191        /*
192         * Load template from file
193         */
194        if($ext){
195            $tempext=$this->settings['extension'];
196            $this->settings['extension']=$ext;
197        };
198        $this->tmp_template = $this->findTemplate($template_name);
199        $this->template_file=$template_name;
200
201        if(!isset($this->tmp_template))
202            throw $this->exception("Template not found")
203               ->setTemplate($template_name.$this->settings['extension']);
204
205        $this->loadTemplateFromString($this->tmp_template);
206        $this->source='file '.$template_name;
207        if($ext){ $this->settings['extension']=$tempext; }
208        return $this;
209    }
210    function loadTemplateFromString($str){
211        $this->source='string';
212        $this->template=$this->tags=array();
213        if(!$str){
214            return;
215        }
216
217
218        /* First expand self-closing tags <?$tag?> -> <?tag?><?/tag?> */
219        $str=preg_replace('/<\?\$([\w]+)\?>/s','<?\1?><?/\1?>',$str);
220
221        var_Dump($str);
222        /* Next fix short ending tag <?tag?>  <?/?> -> <?tag?>  <?/?> */
223        $x=preg_replace_callback('/<\?([^\/][^>]*)\?>(?:(?:(?!<\?\/\?>).)++|(?R))*<\?\/\?>/s',function($x){
224                var_Dump($x);
225                /*return preg_replace('/(.*<\?([^\/][\w]+)\?>)(.*?)(<\?\/?\?>)/s','\1\3<?/\2?>',$x[0]); */
226                },$str);
227        var_Dump($str);
228
229        /* Finally recursively build tag structure */
230        $this->recursiveParse($x);
231
232        $this->tags['_top'][]=&$this->template;
233        return $this;
234    }
235    function recursiveParse($x){
236
237        if(is_array($x)){
238            // Called recursively
239            $tmp2=$this->template;$this->template=array();
240        }else{
241            $x=array(4=>$x);
242            $tmp2=null;
243        }
244        $y=preg_replace_callback('/(.*?)(<\?([^\/$][\w]+)\?>)(.*?)(<\?\/(\3)?\?>)(.*?)/s',array($this,'recursiveParse'),$x[4]);
245        $this->template[]=$y;
246        if($tmp2===null)return;
247        $tmp=$this->template;
248        $this->template=$tmp2;
249
250        $this->template[]=$x[1];
251        $this->template[$x[3].'#'.count($this->tags[$x[3]])]=$tmp;
252        $this->tags[$x[3]][]=&$this->template[$x[3].'#'.count($this->tags[$x[3]])];
253        return '';
254    }
255    function rebuildTags(){
256        $this->tags=array();
257        $old=$this->template;
258        $this->template=array();
259        $this->rebuildTagsRegion($old,$this->template);
260        //$this->template=unserialize(serialize($this->template));
261        //$this->rebuildTagsRegion($this->template);
262    }
263    function rebuildTagsRegion(&$old,&$new){
264        //var_dump($old,$new);
265        foreach($old as $tag=>$val){
266            if(is_numeric($tag)){
267                $new[]=$val;
268                continue;
269            }
270            @list($key,$ref)=explode('#',$tag);
271
272            $new[$c=$key.'#'.count($this->tags[$key])]=array();
273            $this->tags[$key][]=&$new[$c];
274            $this->rebuildTagsRegion($old[$tag],$new[$c]);
275        }
276        //echo "------------------------------------------<br/>";
277        //var_dump($old,$new);
278    }
279    function render($region=null){
280        if($region)return $this->recursiveRender($this->get($region));
281        return $this->recursiveRender($this->template);
282    }
283    function recursiveRender(&$template){
284        $s='';
285        foreach($template as $val){
286            if(is_array($val)){
287                $s.=$this->recursiveRender($val);
288            }else{
289                $s.=$val;
290            }
291        }
292        return $s;
293    }
294}
295
296class Exception_Template extends BaseException {
297    function init(){
298        parent::init();
299        if($this->owner->template_file)
300            $this->addMoreInfo('file',$this->owner->template_file);
301
302        $keys=array_keys($this->owner->tags);
303        if($keys)$this->addMoreInfo('keys',implode(', ',$keys));
304
305        if($this->owner->source)$this->addMoreInfo('source',$this->owner->source);
306    }
307    function setTag($t){
308        $this->addMoreInfo('tag',$t);
309        return $this;
310    }
311}