Changeset 402 for trunk/include/template.php
- Timestamp:
- Mar 30, 2004, 12:40:21 AM (20 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/template.php
r362 r402 27 27 28 28 /** 29 * Template class. By Nathan Codding of the phpBB group. 30 * The interface was originally inspired by PHPLib templates, 31 * and the template file formats are quite similar. 32 * 29 * Template class. By Nathan Codding of the phpBB group. The interface was 30 * originally inspired by PHPLib templates, and the template file formats 31 * are quite similar. 33 32 */ 34 33 35 34 class Template { 36 var $classname = "Template"; 37 38 // variable that holds all the data we'll be substituting into 39 // the compiled templates. 40 // ... 41 // This will end up being a multi-dimensional array like this: 42 // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value 43 // if it's a root-level variable, it'll be like this: 44 // $this->_tpldata[.][0][varname] == value 45 var $_tpldata = array(); 46 47 // Hash of filenames for each template handle. 48 var $files = array(); 49 50 // Root template directory. 51 var $root = ""; 52 53 // this will hash handle names to the compiled code for that handle. 54 var $compiled_code = array(); 55 56 // This will hold the uncompiled code for that handle. 57 var $uncompiled_code = array(); 58 59 /** 60 * Constructor. Simply sets the root dir. 61 * 62 */ 63 function Template($root = ".") 64 { 65 $this->set_rootdir($root); 66 } 67 68 /** 69 * Destroys this template object. Should be called when you're done with it, in order 70 * to clear out the template data so you can load/parse a new template set. 71 */ 72 function destroy() 73 { 74 $this->_tpldata = array(); 75 } 76 77 /** 78 * Sets the template root directory for this Template object. 79 */ 80 function set_rootdir($dir) 81 { 82 if (!is_dir($dir)) 83 { 84 return false; 85 } 86 87 $this->root = $dir; 88 return true; 89 } 90 91 /** 92 * Sets the template filenames for handles. $filename_array 93 * should be a hash of handle => filename pairs. 94 */ 95 function set_filenames($filename_array) 96 { 97 if (!is_array($filename_array)) 98 { 99 return false; 100 } 101 102 reset($filename_array); 103 while(list($handle, $filename) = each($filename_array)) 104 { 105 $this->files[$handle] = $this->make_filename($filename); 106 } 107 108 return true; 109 } 110 111 112 /** 113 * Load the file for the handle, compile the file, 114 * and run the compiled code. This will print out 115 * the results of executing the template. 116 */ 117 function pparse($handle) 118 { 119 if (!$this->loadfile($handle)) 120 { 121 die("Template->pparse(): Couldn't load template file for handle $handle"); 122 } 123 124 // actually compile the template now. 125 if (!isset($this->compiled_code[$handle]) || empty($this->compiled_code[$handle])) 126 { 127 // Actually compile the code now. 128 $this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]); 129 } 130 131 // Run the compiled code. 132 //echo ("<!-- ".$this->compiled_code[$handle]." -->"); 133 eval($this->compiled_code[$handle]); 134 return true; 135 } 136 137 /** 138 * Inserts the uncompiled code for $handle as the 139 * value of $varname in the root-level. This can be used 140 * to effectively include a template in the middle of another 141 * template. 142 * Note that all desired assignments to the variables in $handle should be done 143 * BEFORE calling this function. 144 */ 145 function assign_var_from_handle($varname, $handle) 146 { 147 if (!$this->loadfile($handle)) 148 { 149 die("Template->assign_var_from_handle(): Couldn't load template file for handle $handle"); 150 } 151 152 // Compile it, with the "no echo statements" option on. 153 $_str = ""; 154 $code = $this->compile($this->uncompiled_code[$handle], true, '_str'); 155 156 // evaluate the variable assignment. 157 eval($code); 158 // assign the value of the generated variable to the given varname. 159 $this->assign_var($varname, $_str); 160 161 return true; 162 } 163 164 /** 165 * Block-level variable assignment. Adds a new block iteration with the given 166 * variable assignments. Note that this should only be called once per block 167 * iteration. 168 */ 169 function assign_block_vars($blockname, $vararray) 170 { 171 if (strstr($blockname, '.')) 172 { 173 // Nested block. 174 $blocks = explode('.', $blockname); 175 $blockcount = sizeof($blocks) - 1; 176 $str = '$this->_tpldata'; 177 for ($i = 0; $i < $blockcount; $i++) 178 { 179 $str .= '[\'' . $blocks[$i] . '.\']'; 180 eval('$lastiteration = sizeof(' . $str . ') - 1;'); 181 $str .= '[' . $lastiteration . ']'; 182 } 183 // Now we add the block that we're actually assigning to. 184 // We're adding a new iteration to this block with the given 185 // variable assignments. 186 $str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;'; 187 188 // Now we evaluate this assignment we've built up. 189 eval($str); 190 } 191 else 192 { 193 // Top-level block. 194 // Add a new iteration to this block with the variable assignments 195 // we were given. 196 $this->_tpldata[$blockname . '.'][] = $vararray; 197 } 198 199 return true; 200 } 201 202 /** 203 * Root-level variable assignment. Adds to current assignments, overriding 204 * any existing variable assignment with the same name. 205 */ 206 function assign_vars($vararray) 207 { 208 reset ($vararray); 209 while (list($key, $val) = each($vararray)) 210 { 211 $this->_tpldata['.'][0][$key] = $val; 212 } 213 214 return true; 215 } 216 217 /** 218 * Root-level variable assignment. Adds to current assignments, overriding 219 * any existing variable assignment with the same name. 220 */ 221 function assign_var($varname, $varval) 222 { 223 $this->_tpldata['.'][0][$varname] = $varval; 224 225 return true; 226 } 227 228 229 /** 230 * Generates a full path+filename for the given filename, which can either 231 * be an absolute name, or a name relative to the rootdir for this Template 232 * object. 233 */ 234 function make_filename($filename) 235 { 236 // Check if it's an absolute or relative path. 237 if (substr($filename, 0, 1) != '/') 238 { 239 $filename = realpath($this->root . '/' . $filename); 240 } 241 242 if (!file_exists($filename)) 243 { 244 die("Template->make_filename(): Error - file $filename does not exist"); 245 } 246 247 return $filename; 248 } 249 250 251 /** 252 * If not already done, load the file for the given handle and populate 253 * the uncompiled_code[] hash with its code. Do not compile. 254 */ 255 function loadfile($handle) 256 { 257 // If the file for this handle is already loaded and compiled, do nothing. 258 if (isset($this->uncompiled_code[$handle]) && !empty($this->uncompiled_code[$handle])) 259 { 260 return true; 261 } 262 263 // If we don't have a file assigned to this handle, die. 264 if (!isset($this->files[$handle])) 265 { 266 die("Template->loadfile(): No file specified for handle $handle"); 267 } 268 269 $filename = $this->files[$handle]; 270 271 $str = implode("", @file($filename)); 272 if (empty($str)) 273 { 274 die("Template->loadfile(): File $filename for handle $handle is empty"); 275 } 276 277 $this->uncompiled_code[$handle] = $str; 278 279 return true; 280 } 281 282 283 284 /** 285 * Compiles the given string of code, and returns 286 * the result in a string. 287 * If "do_not_echo" is true, the returned code will not be directly 288 * executable, but can be used as part of a variable assignment 289 * for use in assign_code_from_handle(). 290 */ 291 function compile($code, $do_not_echo = false, $retvar = '') 292 { 293 // replace \ with \\ and then ' with \'. 294 $code = str_replace('\\', '\\\\', $code); 295 $code = str_replace('\'', '\\\'', $code); 296 297 // change template varrefs into PHP varrefs 298 299 // This one will handle varrefs WITH namespaces 300 $varrefs = array(); 301 preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs); 302 $varcount = sizeof($varrefs[1]); 303 for ($i = 0; $i < $varcount; $i++) 304 { 305 $namespace = $varrefs[1][$i]; 306 $varname = $varrefs[3][$i]; 307 $new = $this->generate_block_varref($namespace, $varname); 308 309 $code = str_replace($varrefs[0][$i], $new, $code); 310 } 311 312 // This will handle the remaining root-level varrefs 313 $code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '\' . ( ( isset($this->_tpldata[\'.\'][0][\'\1\']) ) ? $this->_tpldata[\'.\'][0][\'\1\'] : \'\' ) . \'', $code); 314 315 // Break it up into lines. 316 $code_lines = explode("\n", $code); 317 318 $block_nesting_level = 0; 319 $block_names = array(); 320 $block_names[0] = "."; 321 322 // Second: prepend echo ', append ' . "\n"; to each line. 323 $line_count = sizeof($code_lines); 324 for ($i = 0; $i < $line_count; $i++) 325 { 326 $code_lines[$i] = chop($code_lines[$i]); 327 if (preg_match('#<!-- BEGIN (.*?) -->#', $code_lines[$i], $m)) 328 { 329 $n[0] = $m[0]; 330 $n[1] = $m[1]; 331 332 // Added: dougk_ff7-Keeps templates from bombing if begin is on the same line as end.. I think. :) 333 if ( preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $n) ) 334 { 335 $block_nesting_level++; 336 $block_names[$block_nesting_level] = $m[1]; 337 if ($block_nesting_level < 2) 338 { 339 // Block is not nested. 340 $code_lines[$i] = '$_' . $n[1] . '_count = ( isset($this->_tpldata[\'' . $n[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $n[1] . '.\']) : 0;'; 341 $code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)'; 342 $code_lines[$i] .= "\n" . '{'; 343 } 344 else 345 { 346 // This block is nested. 347 348 // Generate a namespace string for this block. 349 $namespace = implode('.', $block_names); 350 // strip leading period from root level.. 351 $namespace = substr($namespace, 2); 352 // Get a reference to the data array for this block that depends on the 353 // current indices of all parent blocks. 354 $varref = $this->generate_block_data_ref($namespace, false); 355 // Create the for loop code to iterate over this block. 356 $code_lines[$i] = '$_' . $n[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;'; 357 $code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)'; 358 $code_lines[$i] .= "\n" . '{'; 359 } 360 361 // We have the end of a block. 362 unset($block_names[$block_nesting_level]); 363 $block_nesting_level--; 364 $code_lines[$i] .= '} // END ' . $n[1]; 365 $m[0] = $n[0]; 366 $m[1] = $n[1]; 367 } 368 else 369 { 370 // We have the start of a block. 371 $block_nesting_level++; 372 $block_names[$block_nesting_level] = $m[1]; 373 if ($block_nesting_level < 2) 374 { 375 // Block is not nested. 376 $code_lines[$i] = '$_' . $m[1] . '_count = ( isset($this->_tpldata[\'' . $m[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $m[1] . '.\']) : 0;'; 377 $code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)'; 378 $code_lines[$i] .= "\n" . '{'; 379 } 380 else 381 { 382 // This block is nested. 383 384 // Generate a namespace string for this block. 385 $namespace = implode('.', $block_names); 386 // strip leading period from root level.. 387 $namespace = substr($namespace, 2); 388 // Get a reference to the data array for this block that depends on the 389 // current indices of all parent blocks. 390 $varref = $this->generate_block_data_ref($namespace, false); 391 // Create the for loop code to iterate over this block. 392 $code_lines[$i] = '$_' . $m[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;'; 393 $code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)'; 394 $code_lines[$i] .= "\n" . '{'; 395 } 396 } 397 } 398 else if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $m)) 399 { 400 // We have the end of a block. 401 unset($block_names[$block_nesting_level]); 402 $block_nesting_level--; 403 $code_lines[$i] = '} // END ' . $m[1]; 404 } 405 else 406 { 407 // We have an ordinary line of code. 408 if (!$do_not_echo) 409 { 410 $code_lines[$i] = 'echo \'' . $code_lines[$i] . '\' . "\\n";'; 411 } 412 else 413 { 414 $code_lines[$i] = '$' . $retvar . '.= \'' . $code_lines[$i] . '\' . "\\n";'; 415 } 416 } 417 } 418 419 // Bring it back into a single string of lines of code. 420 $code = implode("\n", $code_lines); 421 return $code ; 422 423 } 424 425 426 /** 427 * Generates a reference to the given variable inside the given (possibly nested) 428 * block namespace. This is a string of the form: 429 * ' . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] . ' 430 * It's ready to be inserted into an "echo" line in one of the templates. 431 * NOTE: expects a trailing "." on the namespace. 432 */ 433 function generate_block_varref($namespace, $varname) 434 { 435 // Strip the trailing period. 436 $namespace = substr($namespace, 0, strlen($namespace) - 1); 437 438 // Get a reference to the data block for this namespace. 439 $varref = $this->generate_block_data_ref($namespace, true); 440 // Prepend the necessary code to stick this in an echo line. 441 442 // Append the variable reference. 443 $varref .= '[\'' . $varname . '\']'; 444 445 $varref = '\' . ( ( isset(' . $varref . ') ) ? ' . $varref . ' : \'\' ) . \''; 446 447 return $varref; 448 449 } 450 451 452 /** 453 * Generates a reference to the array of data values for the given 454 * (possibly nested) block namespace. This is a string of the form: 455 * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] 456 * 457 * If $include_last_iterator is true, then [$_childN_i] will be appended to the form shown above. 458 * NOTE: does not expect a trailing "." on the blockname. 459 */ 460 function generate_block_data_ref($blockname, $include_last_iterator) 461 { 462 // Get an array of the blocks involved. 463 $blocks = explode(".", $blockname); 464 $blockcount = sizeof($blocks) - 1; 465 $varref = '$this->_tpldata'; 466 // Build up the string with everything but the last child. 467 for ($i = 0; $i < $blockcount; $i++) 468 { 469 $varref .= '[\'' . $blocks[$i] . '.\'][$_' . $blocks[$i] . '_i]'; 470 } 471 // Add the block reference for the last child. 472 $varref .= '[\'' . $blocks[$blockcount] . '.\']'; 473 // Add the iterator for the last child if requried. 474 if ($include_last_iterator) 475 { 476 $varref .= '[$_' . $blocks[$blockcount] . '_i]'; 477 } 478 479 return $varref; 480 } 481 35 36 var $classname = "Template"; 37 38 // variable that holds all the data we'll be substituting into 39 // the compiled templates. 40 // ... 41 // This will end up being a multi-dimensional array like this : 42 // $this->_tpldata[block.][iteration#][child.][iteration#][child2.][iteration#][variablename] == value 43 // if it's a root-level variable, it'll be like this: 44 // $this->_tpldata[.][0][varname] == value 45 var $_tpldata = array(); 46 47 // Hash of filenames for each template handle. 48 var $files = array(); 49 50 // Root template directory. 51 var $root = ""; 52 53 // this will hash handle names to the compiled code for that handle. 54 var $compiled_code = array(); 55 56 // This will hold the uncompiled code for that handle. 57 var $uncompiled_code = array(); 58 59 /** 60 * Constructor. Simply sets the root dir. 61 * 62 */ 63 function Template($root = ".") 64 { 65 $this->set_rootdir($root); 66 } 67 68 /** 69 * Destroys this template object. Should be called when you're done with 70 * it, in order to clear out the template data so you can load/parse a new 71 * template set. 72 */ 73 function destroy() 74 { 75 $this->_tpldata = array(); 76 } 77 78 /** 79 * Sets the template root directory for this Template object. 80 */ 81 function set_rootdir($dir) 82 { 83 if (!is_dir($dir)) 84 { 85 return false; 86 } 87 88 $this->root = $dir; 89 return true; 90 } 91 92 /** 93 * Sets the template filenames for handles. $filename_array should be a 94 * hash of handle => filename pairs. 95 */ 96 function set_filenames($filename_array) 97 { 98 if (!is_array($filename_array)) 99 { 100 return false; 101 } 102 103 reset($filename_array); 104 while(list($handle, $filename) = each($filename_array)) 105 { 106 $this->files[$handle] = $this->make_filename($filename); 107 } 108 109 return true; 110 } 111 112 113 /** 114 * Load the file for the handle, compile the file, and run the compiled 115 * code. This will print out the results of executing the template. 116 */ 117 function pparse($handle) 118 { 119 if (!$this->loadfile($handle)) 120 { 121 die("Template->pparse(): Couldn't load template file for handle $handle"); 122 } 123 124 // actually compile the template now. 125 if (!isset($this->compiled_code[$handle]) || empty($this->compiled_code[$handle])) 126 { 127 // Actually compile the code now. 128 $this->compiled_code[$handle] = $this->compile($this->uncompiled_code[$handle]); 129 } 130 131 // Run the compiled code. 132 //echo ("<!-- ".$this->compiled_code[$handle]." -->"); 133 eval($this->compiled_code[$handle]); 134 return true; 135 } 136 137 /** 138 * Inserts the uncompiled code for $handle as the value of $varname in the 139 * root-level. This can be used to effectively include a template in the 140 * middle of another template. 141 * 142 * Note that all desired assignments to the variables in $handle should be 143 * done BEFORE calling this function. 144 */ 145 function assign_var_from_handle($varname, $handle) 146 { 147 if (!$this->loadfile($handle)) 148 { 149 die("Template->assign_var_from_handle(): Couldn't load template file for handle $handle"); 150 } 151 152 // Compile it, with the "no echo statements" option on. 153 $_str = ""; 154 $code = $this->compile($this->uncompiled_code[$handle], true, '_str'); 155 156 // evaluate the variable assignment. 157 eval($code); 158 // assign the value of the generated variable to the given varname. 159 $this->assign_var($varname, $_str); 160 161 return true; 162 } 163 164 /** 165 * Block-level variable assignment. Adds a new block iteration with the 166 * given variable assignments. Note that this should only be called once 167 * per block iteration. 168 */ 169 function assign_block_vars($blockname, $vararray) 170 { 171 if (strstr($blockname, '.')) 172 { 173 // Nested block. 174 $blocks = explode('.', $blockname); 175 $blockcount = sizeof($blocks) - 1; 176 $str = '$this->_tpldata'; 177 for ($i = 0; $i < $blockcount; $i++) 178 { 179 $str .= '[\'' . $blocks[$i] . '.\']'; 180 eval('$lastiteration = sizeof(' . $str . ') - 1;'); 181 $str .= '[' . $lastiteration . ']'; 182 } 183 // Now we add the block that we're actually assigning to. 184 // We're adding a new iteration to this block with the given 185 // variable assignments. 186 $str .= '[\'' . $blocks[$blockcount] . '.\'][] = $vararray;'; 187 188 // Now we evaluate this assignment we've built up. 189 eval($str); 190 } 191 else 192 { 193 // Top-level block. Add a new iteration to this block with the 194 // variable assignments we were given. 195 $this->_tpldata[$blockname . '.'][] = $vararray; 196 } 197 198 return true; 199 } 200 201 /** 202 * Root-level variable assignment. Adds to current assignments, overriding 203 * any existing variable assignment with the same name. 204 */ 205 function assign_vars($vararray) 206 { 207 reset ($vararray); 208 while (list($key, $val) = each($vararray)) 209 { 210 $this->_tpldata['.'][0][$key] = $val; 211 } 212 213 return true; 214 } 215 216 /** 217 * Root-level variable assignment. Adds to current assignments, overriding 218 * any existing variable assignment with the same name. 219 */ 220 function assign_var($varname, $varval) 221 { 222 $this->_tpldata['.'][0][$varname] = $varval; 223 224 return true; 225 } 226 227 228 /** 229 * Generates a full path+filename for the given filename, which can either 230 * be an absolute name, or a name relative to the rootdir for this 231 * Template object. 232 */ 233 function make_filename($filename) 234 { 235 // Check if it's an absolute or relative path. 236 if (substr($filename, 0, 1) != '/') 237 { 238 $filename = realpath($this->root . '/' . $filename); 239 } 240 241 if (!file_exists($filename)) 242 { 243 die("Template->make_filename(): Error - file $filename does not exist"); 244 } 245 246 return $filename; 247 } 248 249 250 /** 251 * If not already done, load the file for the given handle and populate 252 * the uncompiled_code[] hash with its code. Do not compile. 253 */ 254 function loadfile($handle) 255 { 256 // If the file for this handle is already loaded and compiled, do 257 // nothing. 258 if (isset($this->uncompiled_code[$handle]) 259 and !empty($this->uncompiled_code[$handle])) 260 { 261 return true; 262 } 263 264 // If we don't have a file assigned to this handle, die. 265 if (!isset($this->files[$handle])) 266 { 267 die("Template->loadfile(): No file specified for handle $handle"); 268 } 269 270 $filename = $this->files[$handle]; 271 272 $str = implode("", @file($filename)); 273 if (empty($str)) 274 { 275 die("Template->loadfile(): File $filename for handle $handle is empty"); 276 } 277 278 $this->uncompiled_code[$handle] = $str; 279 280 return true; 281 } 282 283 284 285 /** 286 * Compiles the given string of code, and returns the result in a string. 287 * 288 * If "do_not_echo" is true, the returned code will not be directly 289 * executable, but can be used as part of a variable assignment for use in 290 * assign_code_from_handle(). 291 */ 292 function compile($code, $do_not_echo = false, $retvar = '') 293 { 294 // replace \ with \\ and then ' with \'. 295 $code = str_replace('\\', '\\\\', $code); 296 $code = str_replace('\'', '\\\'', $code); 297 298 // change template varrefs into PHP varrefs 299 300 // This one will handle varrefs WITH namespaces 301 $varrefs = array(); 302 preg_match_all('#\{(([a-z0-9\-_]+?\.)+?)([a-z0-9\-_]+?)\}#is', $code, $varrefs); 303 $varcount = sizeof($varrefs[1]); 304 for ($i = 0; $i < $varcount; $i++) 305 { 306 $namespace = $varrefs[1][$i]; 307 $varname = $varrefs[3][$i]; 308 $new = $this->generate_block_varref($namespace, $varname); 309 310 $code = str_replace($varrefs[0][$i], $new, $code); 311 } 312 313 // This will handle the remaining root-level varrefs 314 $code = preg_replace('#\{([a-z0-9\-_]*?)\}#is', '\' . ( ( isset($this->_tpldata[\'.\'][0][\'\1\']) ) ? $this->_tpldata[\'.\'][0][\'\1\'] : \'\' ) . \'', $code); 315 316 // Break it up into lines. 317 $code_lines = explode("\n", $code); 318 319 $block_nesting_level = 0; 320 $block_names = array(); 321 $block_names[0] = "."; 322 323 // Second: prepend echo ', append ' . "\n"; to each line. 324 $line_count = sizeof($code_lines); 325 for ($i = 0; $i < $line_count; $i++) 326 { 327 $code_lines[$i] = chop($code_lines[$i]); 328 if (preg_match('#<!-- BEGIN (.*?) -->#', $code_lines[$i], $m)) 329 { 330 $n[0] = $m[0]; 331 $n[1] = $m[1]; 332 333 // Added: dougk_ff7-Keeps templates from bombing if begin is on 334 // the same line as end.. I think. :) 335 if ( preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $n) ) 336 { 337 $block_nesting_level++; 338 $block_names[$block_nesting_level] = $m[1]; 339 if ($block_nesting_level < 2) 340 { 341 // Block is not nested. 342 $code_lines[$i] = '$_' . $n[1] . '_count = ( isset($this->_tpldata[\'' . $n[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $n[1] . '.\']) : 0;'; 343 $code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)'; 344 $code_lines[$i] .= "\n" . '{'; 345 } 346 else 347 { 348 // This block is nested. 349 350 // Generate a namespace string for this block. 351 $namespace = implode('.', $block_names); 352 // strip leading period from root level.. 353 $namespace = substr($namespace, 2); 354 // Get a reference to the data array for this block that depends on the 355 // current indices of all parent blocks. 356 $varref = $this->generate_block_data_ref($namespace, false); 357 // Create the for loop code to iterate over this block. 358 $code_lines[$i] = '$_' . $n[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;'; 359 $code_lines[$i] .= "\n" . 'for ($_' . $n[1] . '_i = 0; $_' . $n[1] . '_i < $_' . $n[1] . '_count; $_' . $n[1] . '_i++)'; 360 $code_lines[$i] .= "\n" . '{'; 361 } 362 363 // We have the end of a block. 364 unset($block_names[$block_nesting_level]); 365 $block_nesting_level--; 366 $code_lines[$i] .= '} // END ' . $n[1]; 367 $m[0] = $n[0]; 368 $m[1] = $n[1]; 369 } 370 else 371 { 372 // We have the start of a block. 373 $block_nesting_level++; 374 $block_names[$block_nesting_level] = $m[1]; 375 if ($block_nesting_level < 2) 376 { 377 // Block is not nested. 378 $code_lines[$i] = '$_' . $m[1] . '_count = ( isset($this->_tpldata[\'' . $m[1] . '.\']) ) ? sizeof($this->_tpldata[\'' . $m[1] . '.\']) : 0;'; 379 $code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)'; 380 $code_lines[$i] .= "\n" . '{'; 381 } 382 else 383 { 384 // This block is nested. 385 386 // Generate a namespace string for this block. 387 $namespace = implode('.', $block_names); 388 // strip leading period from root level.. 389 $namespace = substr($namespace, 2); 390 // Get a reference to the data array for this block that 391 // depends on the current indices of all parent blocks. 392 $varref = $this->generate_block_data_ref($namespace, false); 393 // Create the for loop code to iterate over this block. 394 $code_lines[$i] = '$_' . $m[1] . '_count = ( isset(' . $varref . ') ) ? sizeof(' . $varref . ') : 0;'; 395 $code_lines[$i] .= "\n" . 'for ($_' . $m[1] . '_i = 0; $_' . $m[1] . '_i < $_' . $m[1] . '_count; $_' . $m[1] . '_i++)'; 396 $code_lines[$i] .= "\n" . '{'; 397 } 398 } 399 } 400 else if (preg_match('#<!-- END (.*?) -->#', $code_lines[$i], $m)) 401 { 402 // We have the end of a block. 403 unset($block_names[$block_nesting_level]); 404 $block_nesting_level--; 405 $code_lines[$i] = '} // END ' . $m[1]; 406 } 407 else 408 { 409 // We have an ordinary line of code. 410 if (!$do_not_echo) 411 { 412 $code_lines[$i] = 'echo \'' . $code_lines[$i] . '\' . "\\n";'; 413 } 414 else 415 { 416 $code_lines[$i] = '$' . $retvar . '.= \'' . $code_lines[$i] . '\' . "\\n";'; 417 } 418 } 419 } 420 421 // Bring it back into a single string of lines of code. 422 $code = implode("\n", $code_lines); 423 return $code ; 424 425 } 426 427 428 /** 429 * Generates a reference to the given variable inside the given (possibly 430 * nested) block namespace. This is a string of the form: ' 431 * . $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['varname'] 432 * . ' It's ready to be inserted into an "echo" line in one of the 433 * templates. NOTE: expects a trailing "." on the namespace. 434 */ 435 function generate_block_varref($namespace, $varname) 436 { 437 // Strip the trailing period. 438 $namespace = substr($namespace, 0, strlen($namespace) - 1); 439 440 // Get a reference to the data block for this namespace. 441 $varref = $this->generate_block_data_ref($namespace, true); 442 // Prepend the necessary code to stick this in an echo line. 443 444 // Append the variable reference. 445 $varref .= '[\'' . $varname . '\']'; 446 447 $varref = '\' . ( ( isset(' . $varref . ') ) ? ' . $varref . ' : \'\' ) . \''; 448 449 return $varref; 450 451 } 452 453 454 /** 455 * Generates a reference to the array of data values for the given 456 * (possibly nested) block namespace. This is a string of the form: 457 * $this->_tpldata['parent'][$_parent_i]['$child1'][$_child1_i]['$child2'][$_child2_i]...['$childN'] 458 * 459 * If $include_last_iterator is true, then [$_childN_i] will be appended 460 * to the form shown above. NOTE: does not expect a trailing "." on the 461 * blockname. 462 */ 463 function generate_block_data_ref($blockname, $include_last_iterator) 464 { 465 // Get an array of the blocks involved. 466 $blocks = explode(".", $blockname); 467 $blockcount = sizeof($blocks) - 1; 468 $varref = '$this->_tpldata'; 469 // Build up the string with everything but the last child. 470 for ($i = 0; $i < $blockcount; $i++) 471 { 472 $varref .= '[\'' . $blocks[$i] . '.\'][$_' . $blocks[$i] . '_i]'; 473 } 474 // Add the block reference for the last child. 475 $varref .= '[\'' . $blocks[$blockcount] . '.\']'; 476 // Add the iterator for the last child if requried. 477 if ($include_last_iterator) 478 { 479 $varref .= '[$_' . $blocks[$blockcount] . '_i]'; 480 } 481 482 return $varref; 483 } 484 482 485 } 483 486
Note: See TracChangeset
for help on using the changeset viewer.