5 Modification information for LGPL compliance
7 r56990 - 2010-06-16 13:05:36 -0700 (Wed, 16 Jun 2010) - kjing - snapshot "Mango" svn branch to a new one for GitHub sync
9 r56989 - 2010-06-16 13:01:33 -0700 (Wed, 16 Jun 2010) - kjing - defunt "Mango" svn dev branch before github cutover
11 r55980 - 2010-04-19 13:31:28 -0700 (Mon, 19 Apr 2010) - kjing - create Mango (6.1) based on windex
13 r51719 - 2009-10-22 10:18:00 -0700 (Thu, 22 Oct 2009) - mitani - Converted to Build 3 tags and updated the build system
15 r51634 - 2009-10-19 13:32:22 -0700 (Mon, 19 Oct 2009) - mitani - Windex is the branch for Sugar Sales 1.0 development
17 r50375 - 2009-08-24 18:07:43 -0700 (Mon, 24 Aug 2009) - dwong - branch kobe2 from tokyo r50372
19 r42807 - 2008-12-29 11:16:59 -0800 (Mon, 29 Dec 2008) - dwong - Branch from trunk/sugarcrm r42806 to branches/tokyo/sugarcrm
21 r36874 - 2008-06-19 12:09:05 -0700 (Thu, 19 Jun 2008) - roger - bug 22568: use md5 of unique key and version for js key.
23 r32524 - 2008-03-06 15:51:02 -0800 (Thu, 06 Mar 2008) - dwong - Fix incorrect encoding on source code caused by IDE, e.g.
25 InboundEmail.php r17199
28 r30876 - 2008-01-09 19:01:57 -0800 (Wed, 09 Jan 2008) - majed - initial check in for instances
30 r29571 - 2007-11-13 10:49:09 -0800 (Tue, 13 Nov 2007) - eddy - Bug 17113
31 Added check for array element prior to accessing it.
34 r26822 - 2007-09-18 10:20:27 -0700 (Tue, 18 Sep 2007) - tswicegood - Refactor a bunch of the loops and such.
35 This code doesn't have a future in Sugar, but there are some legacy
36 areas that still rely on it. Refactoring these few areas cuts its impact
37 on Sugar's main page by 40% (6.14% to 3.72%).
39 r26819 - 2007-09-18 10:07:01 -0700 (Tue, 18 Sep 2007) - tswicegood - Reduces this execution time relatively by 25%
41 r25238 - 2007-08-07 15:40:32 -0700 (Tue, 07 Aug 2007) - dwheeler - Bug 14129. Removed field from vardefs as it is no longer used, and should not be visible from mass update.
43 r18355 - 2006-12-05 17:00:55 -0800 (Tue, 05 Dec 2006) - jenny - Bug 10292 - checking to see if we actually have an array before setting the array values.
45 r13627 - 2006-05-31 11:01:53 -0700 (Wed, 31 May 2006) - majed - name change
47 r12024 - 2006-03-09 23:42:27 -0800 (Thu, 09 Mar 2006) - majed - fixes bugs 4449 5050 4063 4976 4770
49 r11291 - 2006-01-22 10:41:45 -0800 (Sun, 22 Jan 2006) - andrew - Removed the 'Log' CVS keyword.
51 r10797 - 2005-12-21 18:10:38 -0800 (Wed, 21 Dec 2005) - wayne - sugar_version and js_custom_version xtpl assignment now in xtpl.php
53 r9351 - 2005-11-15 15:39:37 -0800 (Tue, 15 Nov 2005) - andrew - Added another check for the $focus that needs to be in for PHP 5.0.3.
55 r9270 - 2005-11-11 15:08:19 -0800 (Fri, 11 Nov 2005) - majed - Adds support for emails email marketing and email templates
57 r8555 - 2005-10-19 12:26:13 -0700 (Wed, 19 Oct 2005) - majed - adds initial acl support
59 r8508 - 2005-10-17 17:23:04 -0700 (Mon, 17 Oct 2005) - majed - adds initial acl support
61 r5820 - 2005-06-21 14:22:24 -0700 (Tue, 21 Jun 2005) - majed - fixes issues with nusoap and with custom fields
63 r4920 - 2005-04-29 00:38:19 -0700 (Fri, 29 Apr 2005) - jacob - Preventing conversion of array to string.
65 r4743 - 2005-04-27 00:57:27 -0700 (Wed, 27 Apr 2005) - jacob - Adding support for "parsing" sections that do not exist in HTML. This provides backwards compatibility for old HTML files with new PHP files.
67 r2016 - 2004-12-28 15:19:29 -0800 (Tue, 28 Dec 2004) - majed - added a function to scan through a block checking for a given variable
69 r1228 - 2004-10-20 02:09:09 -0700 (Wed, 20 Oct 2004) - lam - update
71 r1211 - 2004-10-19 21:55:03 -0700 (Tue, 19 Oct 2004) - lam - update
73 r730 - 2004-09-09 20:14:02 -0700 (Thu, 09 Sep 2004) - sugarjacob - Cleaning up blanks
75 r462 - 2004-08-25 17:43:37 -0700 (Wed, 25 Aug 2004) - sugarmsi - added an exists method to check if a block exists in a template
77 r397 - 2004-08-08 02:28:36 -0700 (Sun, 08 Aug 2004) - sugarjacob - Fix: XTemplate changed to use <?php script declarations
79 r297 - 2004-07-31 15:13:23 -0700 (Sat, 31 Jul 2004) - sugarjacob - Removing default setting of template language arrays.
81 r295 - 2004-07-31 14:37:38 -0700 (Sat, 31 Jul 2004) - sugarjacob - Adding code to automatically assign the language strings to every template created.
83 r268 - 2004-07-16 01:21:57 -0700 (Fri, 16 Jul 2004) - sugarjacob - Changing the XTemplate replacement mechanism to allow for '$' in the text being substituted.
85 r80 - 2004-06-11 16:39:47 -0700 (Fri, 11 Jun 2004) - sugarjacob - Fixing issue with a variable not being an array in some cases.
87 r78 - 2004-06-11 16:34:17 -0700 (Fri, 11 Jun 2004) - sugarjacob - Removing errors or notices about invalid indexs.
89 r3 - 2004-05-26 22:30:56 -0700 (Wed, 26 May 2004) - sugarjacob - Moving project to SourceForge.
99 xtemplate class 0.2.4-3
100 html generation with templates - fast & easy
101 copyright (c) 2000 barnabás debreceni [cranx@users.sourceforge.net]
102 code optimization by Ivar Smolin <okul@linux.ee> 14-march-2001
103 latest stable & CVS version always available @ http://sourceforge.net/projects/xtpl
105 tested with php 3.0.11 and 4.0.4pl1
107 This program is free software; you can redistribute it and/or
108 modify it under the terms of the GNU Lesser General Public License
109 version 2.1 as published by the Free Software Foundation.
111 This library is distributed in the hope that it will be useful,
112 but WITHOUT ANY WARRANTY; without even the implied warranty of
113 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
114 GNU Lesser General Public License for more details at
115 http://www.gnu.org/copyleft/lgpl.html
117 You should have received a copy of the GNU General Public License
118 along with this program; if not, write to the Free Software
119 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
124 /***[ variables ]***********************************************************/
126 var $filecontents=""; /* raw contents of template file */
127 var $blocks=array(); /* unparsed blocks */
128 var $parsed_blocks=array(); /* parsed blocks */
129 var $block_parse_order=array(); /* block parsing order for recursive parsing (sometimes reverse:) */
130 var $sub_blocks=array(); /* store sub-block names for fast resetting */
131 var $VARS=array(); /* variables array */
132 var $alternate_include_directory = "";
134 var $file_delim="/\{FILE\s*\"([^\"]+)\"\s*\}/m"; /* regexp for file includes */
135 var $block_start_delim="<!-- "; /* block start delimiter */
136 var $block_end_delim="-->"; /* block end delimiter */
137 var $block_start_word="BEGIN:"; /* block start word */
138 var $block_end_word="END:"; /* block end word */
140 /* this makes the delimiters look like: <!-- BEGIN: block_name --> if you use my syntax. */
142 var $NULL_STRING=array(""=>""); /* null string for unassigned vars */
143 var $NULL_BLOCK=array(""=>""); /* null string for unassigned blocks */
146 var $AUTORESET=1; /* auto-reset sub blocks */
148 /***[ constructor ]*********************************************************/
150 function XTemplate ($file, $alt_include = "", $mainblock="main") {
151 $this->alternate_include_directory = $alt_include;
152 $this->mainblock=$mainblock;
153 $this->filecontents=$this->r_getfile($file); /* read in template file */
154 //if(substr_count($file, 'backup') == 1)_ppd($this->filecontents);
155 $this->blocks=$this->maketree($this->filecontents,$mainblock); /* preprocess some stuff */
156 //$this->scan_globals();
160 /***************************************************************************/
161 /***[ public stuff ]********************************************************/
162 /***************************************************************************/
165 /***[ assign ]**************************************************************/
170 function assign ($name,$val="") {
171 if (is_array($name)) {
172 foreach ($name as $k => $v) {
173 $this->VARS[$k] = $v;
176 $this->VARS[$name]=$val;
180 function append ($varname, $name,$val="") {
181 if(!isset($this->VARS[$varname])){
182 $this->VARS[$varname] = array();
184 if(is_array($this->VARS[$varname])){
185 $this->VARS[$varname][$name] = $val;
189 /***[ parse ]***************************************************************/
194 function parse ($bname) {
195 global $sugar_version, $sugar_config;
197 $this->assign('SUGAR_VERSION', $GLOBALS['js_version_key']);
198 $this->assign('JS_CUSTOM_VERSION', $sugar_config['js_custom_version']);
200 if(empty($this->blocks[$bname]))
203 $copy=$this->blocks[$bname];
204 if (!isset($this->blocks[$bname]))
205 $this->set_error ("parse: blockname [$bname] does not exist");
206 preg_match_all("/\{([A-Za-z0-9\._]+?)}/",$this->blocks[$bname],$var_array);
207 $var_array=$var_array[1];
208 foreach ($var_array as $k => $v) {
209 $sub=explode(".",$v);
210 if ($sub[0]=="_BLOCK_") {
212 $bname2=implode(".",$sub);
214 if(isset($this->parsed_blocks[$bname2]))
216 $var=$this->parsed_blocks[$bname2];
223 $nul=(!isset($this->NULL_BLOCK[$bname2])) ? $this->NULL_BLOCK[""] : $this->NULL_BLOCK[$bname2];
224 $var=(empty($var))?$nul:trim($var);
225 // Commented out due to regular expression issue with '$' in replacement string.
226 //$copy=preg_replace("/\{".$v."\}/","$var",$copy);
227 // This should be faster and work better for '$'
228 $copy=str_replace("{".$v."}",$var,$copy);
232 foreach ($sub as $k1 => $v1)
234 if(is_array($var) && isset($var[$v1]))
244 $nul=(!isset($this->NULL_STRING[$v])) ? ($this->NULL_STRING[""]) : ($this->NULL_STRING[$v]);
245 $var=(!isset($var))?$nul:$var;
246 // Commented out due to regular expression issue with '$' in replacement string.
247 //$copy=preg_replace("/\{$v\}/","$var",$copy);
248 // This should be faster and work better for '$'
250 // this was periodically returning an array to string conversion error....
253 $copy=str_replace("{".$v."}",$var,$copy);
258 if(isset($this->parsed_blocks[$bname]))
260 $this->parsed_blocks[$bname].=$copy;
264 $this->parsed_blocks[$bname]=$copy;
268 if ($this->AUTORESET && (!empty($this->sub_blocks[$bname]))) {
269 reset($this->sub_blocks[$bname]);
270 foreach ($this->sub_blocks[$bname] as $v)
275 /***[ exists ]**************************************************************/
277 returns true if a block exists otherwise returns false.
279 function exists($bname){
280 return (!empty($this->parsed_blocks[$bname])) || (!empty($this->blocks[$bname]));
284 /***[ var_exists ]**************************************************************/
286 returns true if a block exists otherwise returns false.
288 function var_exists($bname,$vname){
289 if(!empty($this->blocks[$bname])){
290 return substr_count($this->blocks[$bname], '{'. $vname . '}') >0;
296 /***[ rparse ]**************************************************************/
298 returns the parsed text for a block, including all sub-blocks.
301 function rparse($bname) {
302 if (!empty($this->sub_blocks[$bname])) {
303 reset($this->sub_blocks[$bname]);
304 while (list($k,$v)=each($this->sub_blocks[$bname]))
306 $this->rparse($v,$indent."\t");
308 $this->parse($bname);
311 /***[ insert_loop ]*********************************************************/
313 inserts a loop ( call assign & parse )
316 function insert_loop($bname,$var,$value="") {
317 $this->assign($var,$value);
318 $this->parse($bname);
321 /***[ text ]****************************************************************/
323 returns the parsed text for a block
326 function text($bname) {
328 if(!empty($this->parsed_blocks)){
329 return $this->parsed_blocks[isset($bname) ? $bname :$this->mainblock];
335 /***[ out ]*****************************************************************/
337 prints the parsed text
340 function out ($bname) {
346 if($focus && is_subclass_of($focus, 'SugarBean') && !$focus->ACLAccess($action)){
348 ACLController::displayNoAccess(true);
354 echo $this->text($bname);
357 /***[ reset ]***************************************************************/
359 resets the parsed text
362 function reset ($bname) {
363 $this->parsed_blocks[$bname]="";
366 /***[ parsed ]**************************************************************/
368 returns true if block was parsed, false if not
371 function parsed ($bname) {
372 return (!empty($this->parsed_blocks[$bname]));
375 /***[ SetNullString ]*******************************************************/
377 sets the string to replace in case the var was not assigned
380 function SetNullString($str,$varname="") {
381 $this->NULL_STRING[$varname]=$str;
384 /***[ SetNullBlock ]********************************************************/
386 sets the string to replace in case the block was not parsed
389 function SetNullBlock($str,$bname="") {
390 $this->NULL_BLOCK[$bname]=$str;
393 /***[ set_autoreset ]*******************************************************/
395 sets AUTORESET to 1. (default is 1)
396 if set to 1, parse() automatically resets the parsed blocks' sub blocks
397 (for multiple level blocks)
400 function set_autoreset() {
404 /***[ clear_autoreset ]*****************************************************/
406 sets AUTORESET to 0. (default is 1)
407 if set to 1, parse() automatically resets the parsed blocks' sub blocks
408 (for multiple level blocks)
411 function clear_autoreset() {
415 /***[ scan_globals ]********************************************************/
417 scans global variables
420 function scan_globals() {
422 while (list($k,$v)=each($GLOBALS))
424 $this->assign("PHP",$GLOB); /* access global variables as {PHP.HTTP_HOST} in your template! */
430 PUBLIC FUNCTIONS BELOW THIS LINE DIDN'T GET TESTED
435 /***************************************************************************/
436 /***[ private stuff ]*******************************************************/
437 /***************************************************************************/
439 /***[ maketree ]************************************************************/
441 generates the array containing to-be-parsed stuff:
442 $blocks["main"],$blocks["main.table"],$blocks["main.table.row"], etc.
443 also builds the reverse parse order.
447 function maketree($con,$block) {
448 $con2=explode($this->block_start_delim,$con);
450 $block_names=array();
453 while(list($k,$v)=each($con2)) {
454 $patt="($this->block_start_word|$this->block_end_word)\s*(\w+)\s*$this->block_end_delim(.*)";
455 if (preg_match_all("/$patt/ims",$v,$res, PREG_SET_ORDER)) {
456 // $res[0][1] = BEGIN or END
457 // $res[0][2] = block name
458 // $res[0][3] = kinda content
459 if ($res[0][1]==$this->block_start_word) {
460 $parent_name=implode(".",$block_names);
461 $block_names[++$level]=$res[0][2]; /* add one level - array("main","table","row")*/
462 $cur_block_name=implode(".",$block_names); /* make block name (main.table.row) */
463 $this->block_parse_order[]=$cur_block_name; /* build block parsing order (reverse) */
465 if(array_key_exists($cur_block_name, $blocks))
467 $blocks[$cur_block_name].=$res[0][3]; /* add contents */
471 $blocks[$cur_block_name]=$res[0][3]; /* add contents */
474 /* add {_BLOCK_.blockname} string to parent block */
475 if(array_key_exists($parent_name, $blocks))
477 $blocks[$parent_name].="{_BLOCK_.$cur_block_name}";
481 $blocks[$parent_name]="{_BLOCK_.$cur_block_name}";
484 $this->sub_blocks[$parent_name][]=$cur_block_name; /* store sub block names for autoresetting and recursive parsing */
485 $this->sub_blocks[$cur_block_name][]=""; /* store sub block names for autoresetting */
486 } else if ($res[0][1]==$this->block_end_word) {
487 unset($block_names[$level--]);
488 $parent_name=implode(".",$block_names);
489 $blocks[$parent_name].=$res[0][3]; /* add rest of block to parent block */
491 } else { /* no block delimiters found */
492 $index = implode(".",$block_names);
493 if(array_key_exists($index, $blocks))
495 $blocks[].=$this->block_start_delim.$v;
499 $blocks[]=$this->block_start_delim.$v;
508 /***[ error stuff ]*********************************************************/
513 function get_error() {
514 return ($this->ERROR=="")?0:$this->ERROR;
518 function set_error($str) {
522 /***[ getfile ]*************************************************************/
524 returns the contents of a file
527 function getfile($file) {
529 $this->set_error("!isset file name!");
533 // Pick which folder we should include from
534 // Prefer the local directory, then try the theme directory.
536 $file = $this->alternate_include_directory.$file;
540 $file_text=file_get_contents($file);
543 $this->set_error("[$file] does not exist");
544 $file_text="<b>__XTemplate fatal error: file [$file] does not exist__</b>";
550 /***[ r_getfile ]***********************************************************/
552 recursively gets the content of a file with {FILE "filename.tpl"} directives
556 function r_getfile($file) {
557 $text=$this->getfile($file);
558 while (preg_match($this->file_delim,$text,$res)) {
559 $text2=$this->getfile($res[1]);
560 $text=preg_replace("'".preg_quote($res[0])."'",$text2,$text);
565 } /* end of XTemplate class. */