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