[ Index ]

PHP Cross Reference of Web Application Component Toolkit

title

Body

[close]

/framework/template/compiler/ -> compilercomponent.inc.php (source)

   1  <?php
   2  //--------------------------------------------------------------------------------
   3  // Copyright 2003 Procata, Inc.
   4  // Released under the LGPL license (http://www.gnu.org/copyleft/lesser.html)
   5  //--------------------------------------------------------------------------------
   6  /**
   7  * @package WACT_TEMPLATE
   8  * @version $Id: compilercomponent.inc.php,v 1.45 2004/11/15 21:51:45 jeffmoore Exp $
   9  */
  10  //--------------------------------------------------------------------------------
  11  /**
  12  * Base class for compile time components. Compile time component methods are
  13  * called by the template parser SourceFileParser.<br />
  14  * Note this in the comments for this class, parent and child refer to the XML
  15  * heirarchy in the template, as opposed to the PHP class tree.
  16  * @see SourceFileParser
  17  * @see http://wact.sourceforge.net/index.php/CompilerComponent
  18  * @access public
  19  * @abstract
  20  * @package WACT_TEMPLATE
  21  */
  22  class CompilerComponent {
  23      /**
  24      * XML attributes of the tag
  25      * @var array
  26      * @access private
  27      */
  28      var $attributeNodes = array();
  29      
  30      /**
  31      * Child compile-time components
  32      * @var array of compile time component objects
  33      * @access private
  34      */
  35      var $children = array();
  36      
  37      /**
  38      * A list of properties for this component
  39      * @var array
  40      * @access private
  41      */
  42      var $properties = array();
  43      
  44      /**
  45      * Parent compile-time component
  46      * @var object subclass of CompilerComponent
  47      * @access private
  48      */
  49      var $parent = NULL;
  50      
  51      /**
  52      * Stores the identifying component ID
  53      * @var string value of id attribute
  54      * @access private
  55      */
  56      var $ServerId;
  57      
  58      /**
  59      * Name of the XML tag as it appears in the template. This would include
  60      * the namespace prefix, if applicable.
  61      * @var string tag name
  62      * @access private
  63      */
  64      var $tag = '';
  65      
  66      /**
  67      * Used to identify the source template file, when generating compile time
  68      * error messages.
  69      * @var string source template filename
  70      * @access private
  71      */
  72      var $SourceFile;
  73      
  74      /**
  75      * Used to indentify the line number where a compile time error occurred.
  76      * @var int line number
  77      * @access private
  78      */
  79      var $StartingLineNo;
  80  
  81      /**
  82      * Defines whether the tag is allowed to have a closing tag
  83      * @var boolean
  84      * @access private
  85      */
  86      var $hasClosingTag = TRUE;
  87  
  88      /**
  89      * Whether the was empty and closed such as <br />
  90      * @var boolean
  91      * @access private
  92      */
  93      var $emptyClosedTag = FALSE;
  94  
  95      /**
  96      * Counter for plain text tags matching the current tag component
  97      * name. Used to prevent premature closing. See bug 906138
  98      * @var int
  99      * @access private
 100      */
 101      var $plainTagCount = 0;
 102  
 103      /**
 104      * TagInfo metadata for this component
 105      * @var TagInfo
 106      */
 107      var $TagInfo;
 108  
 109      /**
 110      * Instance of a CoreWrapTag
 111      * @see CoreWrapTag
 112      * @var CoreWrapTag
 113      * @access private
 114      */
 115      var $WrappingComponents = array();
 116  
 117      /**
 118      * Set a wrapping component for this component
 119      * @param object 
 120      * @return void
 121      * @access protected
 122      */
 123      function registerWrapper(&$wrapper) {
 124          $this->WrappingComponents[] =& $wrapper;
 125      }
 126  
 127      /**
 128      * Sets the XML attributes for this component (as extracted from the
 129      * template)
 130      * @param object XML attributes
 131      * @return void
 132      * @access protected
 133      */
 134  	function addChildAttribute(&$child) {
 135          $attrib = strtolower($child->name);
 136          if (isset($this->attributeNodes[$attrib])) {
 137              RaiseError('compiler', 'DUPLICATEATTRIBUTE', array(
 138                  'attribute' => $attrib,
 139                  'tag' => $this->tag,
 140                  'file' => $this->SourceFile,
 141                  'line' => $this->StartingLineNo));
 142          }
 143          $this->attributeNodes[$attrib] =& $child;
 144      }
 145  
 146      /**
 147      * Sets an attribute
 148      * @param string name of attribute
 149      * @param string value of attribute
 150      * @return void
 151      * @access public
 152      */
 153  	function setAttribute($attrib, $value) {
 154          $Component =& new AttributeNode($attrib, $value);
 155          $this->addChildAttribute($Component);
 156      }
 157  
 158      /**
 159      * Returns the value of an XML attribute (as extracted from template) or
 160      * NULL if attribute not found
 161      * @param string attribute name
 162      * @return mixed string attribute value or null
 163      * @access public
 164      */
 165  	function getAttribute($attrib) {
 166          if ( isset($this->attributeNodes[strtolower($attrib)]) ) {
 167              return $this->attributeNodes[strtolower($attrib)]->getValue();
 168          }
 169      }
 170      
 171      /**
 172      * Check to see whether a named attribute exists
 173      * @param string name of attribute
 174      * @return boolean
 175      * @access public
 176      */
 177  	function hasAttribute($attrib) {
 178          return isset($this->attributeNodes[strtolower($attrib)]);
 179      }
 180  
 181      /**
 182      * Return the value of a boolean attribute as a boolean.
 183      * ATTRIBUTE=ANYTHING  (true)
 184      * ATTRIBUTE=(FALSE|N|NA|NO|NONE|0) (false)
 185      * ATTRIBUTE (true)
 186      * (attribute unspecified) (default)
 187      * @param string attribute name
 188      * @param boolean value to return if attribute is not found
 189      * @return boolean
 190      * @access public
 191      */
 192      function getBoolAttribute($attrib, $default = FALSE) {
 193          if ( isset($this->attributeNodes[strtolower($attrib)]) ) {
 194              switch (strtoupper($this->attributeNodes[strtolower($attrib)]->getValue())) {
 195              case 'FALSE':
 196              case 'N':
 197              case 'NO':
 198              case 'NONE':
 199              case 'NA':
 200              case '0':
 201                  return false;
 202              default:
 203                  return true;
 204              }
 205          } else {
 206              return $default;
 207          }
 208      }
 209      
 210      /**
 211      * Remove an attribute from the list
 212      * @param string name of attribute
 213      * @return void
 214      * @access public
 215      */
 216  	function removeAttribute($attrib) {
 217          unset($this->attributeNodes[strtolower($attrib)]);
 218      }
 219  
 220      /**
 221      * Returns an array containing the attributes of this component that
 222      * can be resolved at compile time.
 223      * @return array representation of attributes
 224      * @access protected
 225      */
 226  	function getAttributesAsArray($suppress = array()) {
 227          $suppress = array_map('strtolower', $suppress);
 228          $attributes = array();
 229          foreach( array_keys($this->attributeNodes) as $key) {
 230              if (!in_array($key, $suppress) && $this->attributeNodes[$key]->isConstant()) {
 231                  $attributes[$this->attributeNodes[$key]->name] = 
 232                      $this->attributeNodes[$key]->getValue();
 233                  $this->getAttribute($key);
 234              }
 235          }
 236          return $attributes;
 237      }
 238  
 239      function generateAttributeList(&$code, $suppress = array()) {
 240          $suppress = array_map('strtolower', $suppress);
 241          foreach( array_keys($this->attributeNodes) as $key) {
 242              if (!in_array($key, $suppress)) {
 243                  $this->attributeNodes[$key]->generate($code);
 244              }
 245          }
 246      }
 247  
 248      function generateDynamicAttributeList(&$code, $suppress = array()) {
 249          $suppress = array_map('strtolower', $suppress);
 250          foreach( array_keys($this->attributeNodes) as $key) {
 251              if (!in_array($key, $suppress) && !$this->attributeNodes[$key]->isConstant()) {
 252                  $this->attributeNodes[$key]->generate($code);
 253              }
 254          }
 255      }
 256      
 257      /**
 258      * register a property with this component.  Currently, this
 259      * component must be a database to support properties.  This may
 260      * change.
 261      * @access public
 262      */
 263      function registerProperty($name, &$property) {
 264          $this->properties[$name] =& $property;
 265      }
 266  
 267      /**
 268      * @return CompilerProperty returns the named property or NULL if it doesn't exist
 269      * @access public
 270      */
 271      function &getProperty($name) {
 272          if (array_key_exists($name, $this->properties)) {
 273              return $this->properties[$name];
 274          } else {
 275              if ($this->isDataSource()) {
 276                  return NULL;
 277              } else {
 278                  return $this->parent->getProperty($name);
 279              }
 280          }
 281      }
 282  
 283      /**
 284      * Get the value of the XML id attribute
 285      * @return string value of id attribute
 286      * @access protected
 287      */
 288  	function getClientId() {
 289          if ( $this->hasAttribute('id') ) {
 290              return $this->getAttribute('id');
 291          }
 292      }
 293  
 294      /**
 295      * Returns the identifying server ID. It's value it determined in the
 296      * following order;
 297      * <ol>
 298      * <li>The XML id attribute in the template if it exists</li>
 299      * <li>The value of $this->ServerId</li>
 300      * <li>An ID generated by the getNewServerId() function</li>
 301      * </ol>
 302      * @see getNewServerId
 303      * @return string value identifying this component
 304      * @access protected
 305      */
 306  	function getServerId() {
 307          if ($this->hasAttribute('id')) {
 308              return $this->getAttribute('id');
 309          } else if (!empty($this->ServerId)) {
 310              return $this->ServerId;
 311          } else {
 312              $this->ServerId = getNewServerId();
 313              return $this->ServerId;
 314          }
 315      }
 316  
 317      /**
 318      * Adds a child component, by reference, to the array of children
 319      * @param object instance of a compile time component
 320      * @return void
 321      * @access protected
 322      */
 323  	function addChild(&$child) {
 324          $child->parent =& $this;
 325          $this->children[] =& $child;
 326      }
 327  
 328      /**
 329      * Removes a child component, given it's ServerID
 330      * @param string server id
 331      * @return mixed if child is found, returns a reference to it or void
 332      * @access protected
 333      */
 334      function &removeChild($ServerId) {
 335          foreach( array_keys($this->children) as $key) {
 336              $child =& $this->children[$key];
 337              if ($child->getServerid() == $ServerId) {
 338                  unset($this->children[$key]);
 339                  return $child;
 340              }
 341          }
 342      }
 343  
 344      /**
 345      * Returns the last child added to a component
 346      * @return mixed last child instance or false if no children
 347      * @access protected
 348      */
 349      function &getLastChild() {
 350          // end() doesn't return a reference!
 351          $end = count($this->children)-1;
 352          if ( $end >= 0 ) {
 353              return $this->children[$end];
 354          }
 355          return FALSE;
 356      }
 357  
 358      /**
 359      * Returns a child component, given it's ServerID
 360      * @param string server id
 361      * @return mixed if child is found, returns a reference of false
 362      * @access protected
 363      */
 364      function &findChild($ServerId) {
 365          foreach( array_keys($this->children) as $key) {
 366              if ($this->children[$key]->getServerid() == $ServerId) {
 367                  return $this->children[$key];
 368              } else {
 369                  $result =& $this->children[$key]->findChild($ServerId);
 370                  if ($result) {
 371                      return $result;
 372                  }
 373              }
 374          }
 375          return FALSE;
 376      }
 377  
 378      /**
 379      * Returns a child component, given it's compile time component class
 380      * @param string PHP class name
 381      * @return mixed if child is found, returns a reference of false
 382      * @access protected
 383      */
 384      function &findChildByClass($class) {
 385          foreach( array_keys($this->children) as $key) {
 386              if (is_a($this->children[$key], $class)) {
 387                  return $this->children[$key];
 388              } else {
 389                  $result =& $this->children[$key]->findChildByClass($class);
 390                  if ($result) {
 391                      return $result;
 392                  }
 393              }
 394          }
 395          return FALSE;
 396      }
 397  
 398      /**
 399      * Returns an array of child components, given it's compile time component class
 400      * @param string PHP class name
 401      * @return array
 402      * @access protected
 403      */
 404  	function findChildrenByClass($class) {
 405          $ret = array();
 406          foreach( array_keys($this->children) as $key) {
 407              if (is_a($this->children[$key], $class)) {
 408                  $ret[] =& $this->children[$key];
 409              } else {
 410                  $more_children = $this->children[$key]->findChildrenByClass($class);
 411                  if (count($more_children)) {
 412                      $ret = array_merge($ret, $more_children);
 413                  }
 414              }
 415          }
 416          return $ret;
 417      }
 418  
 419      /**
 420      * Returns a child component, given it's compile time component class
 421      * @param string PHP class name
 422      * @return mixed if child is found, returns a reference of false
 423      * @access protected
 424      */
 425      function &findImmediateChildByClass($class) {
 426          foreach( array_keys($this->children) as $key) {
 427              if (is_a($this->children[$key], $class)) {
 428                  return $this->children[$key];
 429              }
 430          }
 431          return FALSE;
 432      }
 433  
 434      /**
 435      * Returns a parent component, recursively searching parents by their
 436      * compile time component class name
 437      * @param string PHP class name
 438      * @return mixed if parent is found, returns a reference of void
 439      * @access protected
 440      */
 441      function &findParentByClass($class) {
 442          $Parent =& $this->parent;
 443          while ($Parent && !is_a($Parent, $class)) {
 444              $Parent =& $Parent->parent;
 445          }
 446          return $Parent;
 447      }
 448  
 449      /**
 450      * Extends findParentByClass to begin search at the <i>current</i> component
 451      * <i>then</i> moving on to its parent, if there's no match. This is called
 452      * from TagJudge to determine known children.
 453      * @param string class name
 454      * @return mixed if parent is found, returns a reference of void
 455      * @access protected
 456      */
 457      function & findSelfOrParentByClass($class) {
 458          if (is_a($this, $class)) {
 459              return $this;
 460          } else {
 461              return $this->findParentByClass($class);
 462          }
 463      }
 464  
 465      /**
 466      * Calls the prepare method for each child component, which will override
 467      * this method it it's concrete implementation. In the subclasses, prepare
 468      * will set up compile time variables. For example the CoreWrapTag uses
 469      * the prepare method to assign itself as the wrapping component.
 470      * @see CoreWrapTag
 471      * @return void
 472      * @access protected
 473      */
 474  	function prepare() {
 475          foreach( array_keys($this->attributeNodes) as $key) {
 476              $this->attributeNodes[$key]->prepare();
 477          }
 478          foreach( array_keys($this->children) as $key) {
 479              $this->children[$key]->prepare();
 480          }
 481      }
 482  
 483      /**
 484      * Used to perform some error checking on the source template, such as
 485      * examining the tag hierarchy and triggering an error if a tag is
 486      * incorrectly nested. Concrete implementation is in subclasses
 487      * @return void
 488      * @access protected
 489      */
 490  	function CheckNestingLevel() {
 491      }
 492  
 493      /**
 494      * Provides instruction to the template parser, while parsing is in
 495      * progress, telling it how it should handle the tag. Subclasses of
 496      * CompilerComponent will return different instructions.<br />
 497      * Available instructions are;
 498      * <ul>
 499      * <li>PARSER_REQUIRE_PARSING - default in this class. Tag must be parsed</li>
 500      * <li>PARSER_FORBID_PARSING - Tag may not be parsed</li>
 501      * <li>PARSER_ALLOW_PARSING - Tag may can be parsed</li>
 502      * </ul>
 503      * In practice, the parser currently only pays attention to the 
 504      * PARSER_FORBID_PARSING instruction.<br />
 505      * Also used to perform error checking on template related to the syntax of
 506      * the concrete tag implementing this method.
 507      * @see SourceFileParser
 508      * @return int PARSER_REQUIRE_PARSING
 509      * @access protected
 510      */
 511  	function preParse() {
 512          return PARSER_REQUIRE_PARSING;
 513      }
 514  
 515      /**
 516      * @return Boolean Indicating whether or not this component is a DataSource
 517      */
 518  	function isDataSource() {
 519          return FALSE;
 520      }
 521  
 522      /**
 523      * If a parent compile time component exists, returns the value of the
 524      * parent's getDataSource() method, which will be a concrete implementation
 525      * @return mixed object compile time component if parent exists or void
 526      * @access protected
 527      */
 528      function &getDataSource() {
 529          if (!$this->isDataSource()) {
 530              if (isset($this->parent)) {
 531                  return $this->parent->getDataSource();
 532              }
 533          }
 534      }
 535  
 536      /**
 537      * Gets the parent in the DataSource, if one exists
 538      * @return mixed object compile time data component if exists or void
 539      * @access protected
 540      */
 541      function &getParentDataSource() {
 542          $DataSource =& $this->getDataSource();
 543          if (isset($DataSource->parent)) {
 544              return $DataSource->parent->getDataSource();
 545          }
 546      }
 547  
 548      /**
 549      * Gets a root DataSource
 550      * @return mixed object compile time data component if exists or void
 551      * @access protected
 552      */
 553      function &getRootDataSource() {
 554          $root =& $this;
 555          while ($root->parent != NULL) {
 556              $root =& $root->parent;
 557          }
 558          return $root;
 559      }
 560  
 561      /**
 562      * Gets the DataSource reference code of the parent
 563      * @return string
 564      * @access protected
 565      */
 566  	function getDataSourceRefCode() {
 567          return $this->parent->getDataSourceRefCode();
 568      }
 569  
 570      /**
 571      * Gets the component reference code of the parent. This is a PHP string
 572      * which is used in the compiled template to reference the component in
 573      * the hierarchy at runtime
 574      * @return string
 575      * @access protected
 576      */
 577  	function getComponentRefCode() {
 578          return $this->parent->getComponentRefCode();
 579      }
 580  
 581      /**
 582      * Calls the generateConstructor() method of each child component
 583      * @param CodeWriter
 584      * @return void
 585      * @access protected
 586      */
 587  	function generateConstructor(&$code) {
 588          foreach( array_keys($this->children) as $key) {
 589              $this->children[$key]->generateConstructor($code);
 590          }
 591      }
 592  
 593      /**
 594      * Calls the generate() method of each child component
 595      * @param CodeWriter
 596      * @return void
 597      * @access protected
 598      */
 599  	function generateContents(&$code) {
 600          foreach( array_keys($this->children) as $key) {
 601              $this->children[$key]->generate($code);
 602          }
 603      }
 604  
 605      /**
 606      * Pre generation method, calls the WrappingComponents
 607      * generateWrapperPrefix() method if the component exists
 608      * @see CoreWrapTag
 609      * @param CodeWriter
 610      * @return void
 611      * @access protected
 612      */
 613  	function preGenerate(&$code) {
 614          foreach( array_keys($this->WrappingComponents) as $key) {
 615              $this->WrappingComponents[$key]->generateWrapperPrefix($code);
 616          }
 617          foreach( array_keys($this->properties) as $key) {
 618              if ($this->properties[$key]->isActive()) {
 619                  $this->properties[$key]->generateScopeEntry($code);
 620              }
 621          }
 622      }
 623  
 624      /**
 625      * Post generation method, calls the WrappingComponents
 626      * generateWrapperPostfix() method if the component exists
 627      * @see CoreWrapTag
 628      * @param CodeWriter
 629      * @return void
 630      * @access protected
 631      */
 632  	function postGenerate(&$code) {
 633          foreach( array_keys($this->properties) as $key) {
 634              if ($this->properties[$key]->isActive()) {
 635                  $this->properties[$key]->generateScopeExit($code);
 636              }
 637          }
 638          foreach( array_reverse(array_keys($this->WrappingComponents)) as $key) {
 639              $this->WrappingComponents[$key]->generateWrapperPostfix($code);
 640          }
 641      }
 642  
 643      /**
 644      * Calls the local preGenerate(), generateContents() and postGenerate()
 645      * methods.
 646      * @param CodeWriter
 647      * @return void
 648      * @access protected
 649      */
 650  	function generate(&$code) {
 651          $this->preGenerate($code);
 652          $this->generateContents($code);
 653          $this->postGenerate($code);
 654      }
 655  }
 656  ?>


Generated: Sun Nov 28 19:36:09 2004 Cross-referenced by PHPXref 0.5