[ Index ]
 

Code source de Horde 3.1.3

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/lib/Horde/ -> Template.php (source)

   1  <?php
   2  /**
   3   * Horde Template system. Adapted from bTemplate by Brian Lozier
   4   * <brian@massassi.net>.
   5   *
   6   * $Horde: framework/Template/Template.php,v 1.38.10.10 2006/06/13 03:54:03 chuck Exp $
   7   *
   8   * Copyright 2002-2006 Chuck Hagenbuch <chuck@horde.org>
   9   *
  10   * See the enclosed file COPYING for license information (LGPL). If you
  11   * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html.
  12   *
  13   * @author  Chuck Hagenbuch <chuck@horde.org>
  14   * @since   Horde 3.0
  15   * @package Horde_Template
  16   */
  17  class Horde_Template {
  18  
  19      /**
  20       * Option values.
  21       *
  22       * @var array
  23       */
  24      var $_options = array();
  25  
  26      /**
  27       * Directory that templates should be read from.
  28       *
  29       * @var string
  30       */
  31      var $_basepath = '';
  32  
  33      /**
  34       * Reset template variables after parsing?
  35       *
  36       * @var boolean
  37       */
  38      var $_resetVars = true;
  39  
  40      /**
  41       * Tag (scalar) values.
  42       *
  43       * @var array
  44       */
  45      var $_scalars = array();
  46  
  47      /**
  48       * Loop tag values.
  49       *
  50       * @var array
  51       */
  52      var $_arrays = array();
  53  
  54      /**
  55       * Cloop tag values.
  56       *
  57       * @var array
  58       */
  59      var $_carrays = array();
  60  
  61      /**
  62       * If tag values.
  63       *
  64       * @var array
  65       */
  66      var $_ifs = array();
  67  
  68      /**
  69       * Name of cached template file.
  70       *
  71       * @var string
  72       */
  73      var $_templateFile = null;
  74  
  75      /**
  76       * Cached source of template file.
  77       *
  78       * @var string
  79       */
  80      var $_template = null;
  81  
  82      /**
  83       * Constructor. Can set the template base path and whether or not
  84       * to drop template variables after a parsing a template.
  85       *
  86       * @param string  $basepath   The directory where templates are read from.
  87       * @param boolean $resetVars  Drop template vars after parsing a template?
  88       */
  89      function Horde_Template($basepath = null, $resetVars = true)
  90      {
  91          if (!is_null($basepath)) {
  92              $this->_basepath = $basepath;
  93          }
  94          $this->_resetVars = (bool)$resetVars;
  95      }
  96  
  97      /**
  98       * Sets an option.
  99       *
 100       * @param string $option  The option name.
 101       * @param mixed  $val     The option's value.
 102       */
 103      function setOption($option, $val)
 104      {
 105          $this->_options[$option] = $val;
 106      }
 107  
 108      /**
 109       * Set the template contents to a string.
 110       *
 111       * @param string $template  The template text.
 112       */
 113      function setTemplate($template)
 114      {
 115          $this->_template = $template;
 116          $this->_templateFile = 'string';
 117      }
 118  
 119      /**
 120       * Returns an option's value.
 121       *
 122       * @param string $option  The option name.
 123       *
 124       * @return mixed  The option's value.
 125       */
 126      function getOption($option)
 127      {
 128          return isset($this->_options[$option]) ? $this->_options[$option] : null;
 129      }
 130  
 131      /**
 132       * Sets a tag, loop, or if variable.
 133       *
 134       * @param string|array $tag   Either the tag name or a hash with tag names
 135       *                            as keys and tag values as values.
 136       * @param mixed        $var   The value to replace the tag with.
 137       * @param boolean      $isIf  Is this for an <if:> tag? (Default: no).
 138       */
 139      function set($tag, $var, $isIf = false)
 140      {
 141          if (is_array($tag)) {
 142              foreach ($tag as $tTag => $tVar) {
 143                  $this->set($tTag, $tVar, $isIf);
 144              }
 145          } elseif (is_array($var) || is_object($var)) {
 146              $this->_arrays[$tag] = $var;
 147              if ($isIf) {
 148                  // Just store the same variable that we stored in
 149                  // $this->_arrays - if we don't modify it, PHP's
 150                  // reference counting ensures we're not using any
 151                  // additional memory here.
 152                  $this->_ifs[$tag] = $var;
 153              }
 154          } else {
 155              $this->_scalars[$tag] = $var;
 156              if ($isIf) {
 157                  // Just store the same variable that we stored in
 158                  // $this->_scalars - if we don't modify it, PHP's
 159                  // reference counting ensures we're not using any
 160                  // additional memory here.
 161                  $this->_ifs[$tag] = $var;
 162              }
 163          }
 164      }
 165  
 166      /**
 167       * Returns the value of a tag or loop.
 168       *
 169       * @param string $tag  The tag name.
 170       *
 171       * @return mixed  The tag value or null if the tag hasn't been set yet.
 172       */
 173      function get($tag)
 174      {
 175          if (isset($this->_arrays[$tag])) {
 176              return $this->_arrays[$tag];
 177          }
 178          if (isset($this->_scalars[$tag])) {
 179              return $this->_scalars[$tag];
 180          }
 181          return null;
 182      }
 183  
 184      /**
 185       * Sets values for a cloop.
 186       *
 187       * @param string $tag   The name of the cloop.
 188       * @param array $array  The values for the cloop.
 189       * @param array $cases  The cases (test values) for the cloops.
 190       */
 191      function setCloop($tag, $array, $cases)
 192      {
 193          $this->_carrays[$tag] = array(
 194              'array' => $array,
 195              'cases' => $cases
 196          );
 197      }
 198  
 199      /**
 200       * Resets the template variables.
 201       *
 202       * @param boolean $scalars  Reset scalar (basic tag) variables?
 203       * @param boolean $arrays   Reset loop variables?
 204       * @param boolean $carrays  Reset cloop variables?
 205       * @param boolean $ifs      Reset if variables?
 206       */
 207      function resetVars($scalars, $arrays, $carrays, $ifs)
 208      {
 209          if ($scalars === true) {
 210              $this->_scalars = array();
 211          }
 212          if ($arrays === true) {
 213              $this->_arrays = array();
 214          }
 215          if ($carrays === true) {
 216              $this->_carrays = array();
 217          }
 218          if ($ifs === true) {
 219              $this->_ifs = array();
 220          }
 221      }
 222  
 223      /**
 224       * Retrieve list of blocks present in the template source.
 225       *
 226       * @param string $filename  The file to fetch the template from.
 227       * @return mixed  An array of applications, or PEAR_Error on failure.
 228       */
 229      function listBlocks()
 230      {
 231          $blocks = array();
 232          if (preg_match_all('<block:([a-zA-Z0-9_]+:[a-zA-Z0-9_]+)>',
 233                             $this->_template, $matches, PREG_SET_ORDER)) {
 234              foreach ($matches as $match) {
 235                  $blocks[] = $match[1];
 236              }
 237          }
 238  
 239          return $blocks;
 240      }
 241  
 242      /**
 243       * Fetches a template from the specified file and return the parsed
 244       * contents.
 245       *
 246       * @param string $filename  The file to fetch the template from.
 247       *
 248       * @return string  The parsed template.
 249       */
 250      function fetch($filename)
 251      {
 252          $contents = $this->_getTemplate($filename);
 253          if (is_a($contents, 'PEAR_Error')) {
 254              return $contents;
 255          }
 256  
 257          // Parse and return the contents.
 258          return $this->parse($contents);
 259      }
 260  
 261      /**
 262       * Parses all variables/tags in the template.
 263       *
 264       * @param string $contents  The unparsed template.
 265       *
 266       * @return string  The parsed template.
 267       */
 268      function parse($contents = null)
 269      {
 270          if (!$contents) {
 271              $contents = $this->_template;
 272          }
 273  
 274          // Process ifs.
 275          if (!empty($this->_ifs)) {
 276              foreach ($this->_ifs as $tag => $value) {
 277                  $contents = $this->_parseIf($tag, $contents);
 278              }
 279          }
 280  
 281          // Process tags.
 282          $search = array();
 283          $replace = array();
 284          foreach ($this->_scalars as $key => $value) {
 285              $search[] = $this->_getTag($key);
 286              $replace[] = $value;
 287          }
 288          if (count($search)) {
 289              $contents = str_replace($search, $replace, $contents);
 290          }
 291  
 292          // Process loops and arrays.
 293          foreach ($this->_arrays as $key => $array) {
 294              $contents = $this->_parseLoop($key, $array, $contents);
 295          }
 296  
 297          // Process cloops.
 298          foreach ($this->_carrays as $key => $array) {
 299              $contents = $this->_parseCloop($key, $array, $contents);
 300          }
 301  
 302          // Parse gettext tags, if the option is enabled.
 303          if ($this->getOption('gettext')) {
 304              $contents = $this->_parseGettext($contents);
 305          }
 306  
 307          // Parse embedded blocks
 308          if ($this->getOption('blocks')) {
 309              $contents = $this->_parseBlocks($contents);
 310          }
 311  
 312          // Reset template data unless we're supposed to keep it
 313          // around.
 314          if ($this->_resetVars) {
 315              $this->resetVars(false, true, true, false);
 316          }
 317  
 318          // Return parsed template.
 319          return $contents;
 320      }
 321  
 322      /**
 323       * Returns full start and end tags for a named tag.
 324       *
 325       * @access private
 326       *
 327       * @param string $tag
 328       * @param string $directive  The kind of tag - tag, if, loop, cloop.
 329       *
 330       * @return array  'b' => Start tag.
 331       *                'e' => End tag.
 332       */
 333      function _getTags($tag, $directive)
 334      {
 335          return array('b' => '<' . $directive . ':' . $tag . '>',
 336                       'e' => '</' . $directive . ':' . $tag . '>');
 337      }
 338  
 339      /**
 340       * Formats a scalar tag (default format is <tag:name>).
 341       *
 342       * @access private
 343       *
 344       * @param string $tag  The name of the tag.
 345       *
 346       * @return string  The full tag with the current start/end delimiters.
 347       */
 348      function _getTag($tag)
 349      {
 350          return '<tag:' . $tag . ' />';
 351      }
 352  
 353      /**
 354       * Extracts a portion of a template.
 355       *
 356       * @access private
 357       *
 358       * @param array $t           The tag to extract. Hash format is:
 359       *                             $t['b'] - The start tag
 360       *                             $t['e'] - The end tag
 361       * @param string &$contents  The template to extract from.
 362       */
 363      function _getStatement($t, &$contents)
 364      {
 365          // Locate the statement.
 366          $pos = strpos($contents, $t['b']);
 367          if ($pos === false) {
 368              return false;
 369          }
 370  
 371          $tag_length = strlen($t['b']);
 372          $fpos = $pos + $tag_length;
 373          $lpos = strpos($contents, $t['e']);
 374          $length = $lpos - $fpos;
 375  
 376          // Extract & return the statement.
 377          return substr($contents, $fpos, $length);
 378      }
 379  
 380      /**
 381       * Parses gettext tags.
 382       *
 383       * @param string $contents  The unparsed content of the file.
 384       *
 385       * @return string  The parsed contents of the gettext blocks.
 386       */
 387      function _parseGettext($contents)
 388      {
 389          // Get the tags & loop.
 390          $t = array('b' => '<gettext>',
 391                     'e' => '</gettext>');
 392          while ($text = $this->_getStatement($t, $contents)) {
 393              $contents = str_replace($t['b'] . $text . $t['e'], _($text), $contents);
 394          }
 395          return $contents;
 396      }
 397  
 398      /**
 399       * Parses block tags.
 400       *
 401       * Here we parse block tags in the form:
 402       *
 403       *  <block:app:name>
 404       *   <param:foo>foo parameter's value</param:foo>
 405       *   <param:bar>bar parameter's value</param:bar>
 406       *   <serial:baz>s:21:"baz parameter's value";</serial:baz>
 407       *  </block:app:name>
 408       *
 409       * ... and replace them with rendered application blocks.
 410       *
 411       * Block parameters are provided with the nested "param:foo" and
 412       * "serial:foo" tags.  The serial-style tags take a serialized PHP
 413       * value, so you can use it to provide array, boolean, and complex
 414       * type parameters.  The param-style tags provide string parameters.
 415       *
 416       * @access private
 417       *
 418       * @param string $contents  The unparsed contents of the file.
 419       *
 420       * @return string  The parsed contents of the file.
 421       */
 422      function _parseBlocks($contents)
 423      {
 424          return preg_replace('!<block:([a-zA-Z_0-9]+):([a-zA-Z_0-9]+)>(.*?)' .
 425                              '</block:([a-zA-Z_0-9]+):([a-zA-Z_0-9]+)>!se',
 426                              "\$this->_parseBlock('\\1', '\\2', '\\3')",
 427                              $contents);
 428      }
 429  
 430      /**
 431       * Handle the contents of one block tag.
 432       *
 433       * @access private
 434       */
 435      function _parseBlock($app, $name, $contents)
 436      {
 437          require_once  'Horde/Block.php';
 438          require_once  'Horde/Block/Collection.php';
 439  
 440          // Undo preg_replace() encoding strangeness.
 441          $contents = str_replace('\\"', '"', $contents);
 442  
 443          // Find block's parameters.
 444          $params = array();
 445          if (preg_match_all('!<param:([a-zA-Z_0-9]+)>(.*?)' .
 446                             '</param:([a-zA-Z_0-9]+)>!s', $contents, $matches,
 447                             PREG_SET_ORDER)) {
 448              foreach ($matches as $match) {
 449                  $params[$match[1]] = html_entity_decode($match[2]);
 450              }
 451          }
 452          if (preg_match_all('!<serial:([a-zA-Z_0-9]+)>(.*?)' .
 453                             '</serial:([a-zA-Z_0-9]+)>!s', $contents, $matches,
 454                             PREG_SET_ORDER)) {
 455              foreach ($matches as $match) {
 456                  $params[$match[1]] = unserialize(html_entity_decode($match[2]));
 457              }
 458          }
 459  
 460          // Construct the block.
 461          $block = &Horde_Block_Collection::getBlock($app, $name, $params);
 462          if (is_a($block, 'PEAR_Error')) {
 463              $result = '<strong>' . sprintf(_("Error creating block: %s"),
 464                                        $block->getMessage()) . '</strong>';
 465          } else {
 466              $result = $block->getContent();
 467              if (is_a($result, 'PEAR_Error')) {
 468                  $result = '<strong>' . sprintf(_("Error getting content: %s"),
 469                                            $result->getMessage()) . '</strong>';
 470              }
 471          }
 472  
 473          return $result;
 474      }
 475  
 476      /**
 477       * Parses a given if statement.
 478       *
 479       * @access private
 480       *
 481       * @param string $tag       The name of the if block to parse.
 482       * @param string $contents  The unparsed contents of the if block.
 483       *
 484       * @return string  The parsed contents of the if block.
 485       */
 486      function _parseIf($tag, $contents, $key = null)
 487      {
 488          // Get the tags & if statement.
 489          $t = $this->_getTags($tag, 'if');
 490          $et = $this->_getTags($tag, 'else');
 491  
 492          // explode the tag, so we have the correct keys for the array
 493          if (isset($key)) {
 494              list($tg, $k) = explode('.', $tag);
 495          }
 496          while (($if = $this->_getStatement($t, $contents)) !== false) {
 497              // Check for else statement.
 498              if ($else = $this->_getStatement($et, $if)) {
 499                  // Process the if statement.
 500                  if ((isset($key) && $this->_ifs[$tg][$key][$k]) ||
 501                      (isset($this->_ifs[$tag]) && $this->_ifs[$tag])) {
 502                      $replace = str_replace($et['b'] . $else . $et['e'], '', $if);
 503                  } else {
 504                      $replace = $else;
 505                  }
 506              } else {
 507                  // Process the if statement.
 508                  if (isset($key)) {
 509                      $replace = $this->_ifs[$tg][$key][$k] ? $if : null;
 510                  } else {
 511                      $replace = $this->_ifs[$tag] ? $if : null;
 512                  }
 513              }
 514  
 515              // Parse the template.
 516              $contents = str_replace($t['b'] . $if . $t['e'], $replace,
 517                                      $contents);
 518          }
 519  
 520          // Return parsed template.
 521          return $contents;
 522      }
 523  
 524      /**
 525       * Parses the given array for any loops or other uses of the array.
 526       *
 527       * @access private
 528       *
 529       * @param string $tag       The name of the loop to parse.
 530       * @param array  $array     The values for the loop.
 531       * @param string $contents  The unparsed contents of the loop.
 532       *
 533       * @return string  The parsed contents of the loop.
 534       */
 535      function _parseLoop($tag, $array, $contents)
 536      {
 537          // Get the tags & loop.
 538          $t = $this->_getTags($tag, 'loop');
 539          $loop = $this->_getStatement($t, $contents);
 540  
 541          // See if we have a divider.
 542          $l = $this->_getTags($tag, 'divider');
 543          $divider = $this->_getStatement($l, $loop);
 544          $contents = str_replace($l['b'] . $divider . $l['e'], '', $contents);
 545  
 546          // Process the array.
 547          do {
 548              $parsed = '';
 549              $first = true;
 550              foreach ($array as $key => $value) {
 551                  if (is_array($value) || is_object($value)) {
 552                      $i = $loop;
 553                      if (is_numeric($key)) {
 554                          foreach ($value as $key2 => $value2) {
 555                              if (!is_array($value2) && !is_object($value2)) {
 556                                  // Replace associative array tags.
 557                                  $aa_tag = $tag . '.' . $key2;
 558                                  $i = str_replace($this->_getTag($aa_tag), $value2, $i);
 559                                  $pos = strpos($tag, '.');
 560                                  if (($pos !== false) &&
 561                                      !empty($this->_ifs[substr($tag, 0, $pos)])) {
 562                                      $this->_ifs[$aa_tag] = $value2;
 563                                      $i = $this->_parseIf($aa_tag, $i);
 564                                      unset($this->_ifs[$aa_tag]);
 565                                  }
 566                              } else {
 567                                  // Check to see if it's a nested loop.
 568                                  $i = $this->_parseLoop($tag . '.' . $key2, $value2, $i);
 569                              }
 570                          }
 571                      }
 572                      $i = str_replace($this->_getTag($tag), $key, $i);
 573                  } elseif (is_string($key) && !is_array($value) && !is_object($value)) {
 574                      $contents = str_replace($this->_getTag($tag . '.' . $key), $value, $contents);
 575                  } elseif (!is_array($value) && !is_object($value)) {
 576                      $i = str_replace($this->_getTag($tag . ''), $value, $loop);
 577                  } else {
 578                      $i = null;
 579                  }
 580  
 581                  // Parse conditions in the array.
 582                  if (!empty($this->_ifs[$tag][$key]) && is_array($this->_ifs[$tag][$key]) && $this->_ifs[$tag][$key]) {
 583                      foreach ($this->_ifs[$tag][$key] as $cTag => $cValue) {
 584                          $i = $this->_parseIf($tag . '.' . $cTag, $i, $key);
 585                      }
 586                  }
 587  
 588                  // Add the parsed iteration.
 589                  if (isset($i)) {
 590                      // If it's not the first time through, prefix the
 591                      // loop divider, if there is one.
 592                      if (!$first) {
 593                          $i = $divider . $i;
 594                      }
 595                      $parsed .= rtrim($i);
 596                  }
 597  
 598                  // No longer the first time through.
 599                  $first = false;
 600              }
 601  
 602              // Replace the parsed pieces of the template.
 603              $contents = str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
 604          } while ($loop = $this->_getStatement($t, $contents));
 605  
 606          return $contents;
 607      }
 608  
 609      /**
 610       * Parses the given case loop (cloop).
 611       *
 612       * @access private
 613       *
 614       * @param string $tag       The name of the cloop to parse.
 615       * @param array  $array     The values for the cloop.
 616       * @param string $contents  The unparsed contents of the cloop.
 617       *
 618       * @return string  The parsed contents of the cloop.
 619       */
 620      function _parseCloop($tag, $array, $contents)
 621      {
 622          // Get the tags & cloop.
 623          $t = $this->_getTags($tag, 'cloop');
 624  
 625          while ($loop = $this->_getStatement($t, $contents)) {
 626              // Set up the cases.
 627              $array['cases'][] = 'default';
 628              $case_content = array();
 629  
 630              // Get the case strings.
 631              foreach ($array['cases'] as $case) {
 632                  $ctags[$case] = $this->_getTags($case, 'case');
 633                  $case_content[$case] = $this->_getStatement($ctags[$case], $loop);
 634              }
 635  
 636              // Process the cloop.
 637              $parsed = '';
 638              foreach ($array['array'] as $key => $value) {
 639                  if (is_numeric($key) && (is_array($value) || is_object($value))) {
 640                      // Set up the cases.
 641                      if (isset($value['case'])) {
 642                          $current_case = $value['case'];
 643                      } else {
 644                          $current_case = 'default';
 645                      }
 646                      unset($value['case']);
 647                      $i = $case_content[$current_case];
 648  
 649                      // Loop through each value.
 650                      foreach ($value as $key2 => $value2) {
 651                          if (is_array($value2) || is_object($value2)) {
 652                              $i = $this->_parseLoop($tag . '.' . $key2, $value2, $i);
 653                          } else {
 654                              $i = str_replace($this->_getTag($tag . '.' . $key2), $value2, $i);
 655                          }
 656                      }
 657                  }
 658  
 659                  // Add the parsed iteration.
 660                  $parsed .= rtrim($i);
 661              }
 662  
 663              // Parse the cloop.
 664              $contents = str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
 665          }
 666  
 667          return $contents;
 668      }
 669  
 670      /**
 671       * Fetch the contents of a template into $this->_template; cache
 672       * the filename in $this->_templateFile.
 673       *
 674       * @access private
 675       *
 676       * @param string $filename  Location of template file on disk.
 677       *
 678       * @return string  The loaded template content.
 679       */
 680      function _getTemplate($filename = null)
 681      {
 682          if (!is_null($filename) && ($filename != $this->_templateFile)) {
 683              $this->_template = null;
 684          }
 685  
 686          if (!is_null($this->_template)) {
 687              return $this->_template;
 688          }
 689  
 690          // Get the contents of the file.
 691          $file = $this->_basepath . $filename;
 692          $contents = @file_get_contents($file);
 693          if ($contents === false) {
 694              require_once 'PEAR.php';
 695              return PEAR::raiseError(sprintf(_("Template \"%s\" not found."), $file));
 696          }
 697  
 698          $this->_template = $contents;
 699          $this->_templateFile = $filename;
 700  
 701          return $this->_template;
 702      }
 703  
 704  }


Généré le : Sun Feb 25 18:01:28 2007 par Balluche grâce à PHPXref 0.7