[ Index ]

PHP Cross Reference of Web Application Component Toolkit

title

Body

[close]

/framework/template/compiler/ -> treebuilder.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: treebuilder.inc.php,v 1.51 2004/11/18 05:05:25 jeffmoore Exp $
   9  */
  10  //------------------------------------------------------------------------------
  11  
  12  /**#@+
  13   *      ExpresionParser capture constants
  14   */
  15  define('WACT_EXPPARSER_BEFORE_CONTENT', 1);
  16  define('WACT_EXPPARSER_EXPRESSION', 2);
  17  define('WACT_EXPPARSER_AFTER_CONTENT',  5);
  18  /**#@-*/
  19  
  20  //------------------------------------------------------------------------------
  21  /**
  22  * Acts on the ComponentTree in response to events within
  23  * the SourceFileParser
  24  * @todo get rid of reference to SourceFileParser
  25  * @see http://wact.sourceforge.net/index.php/TreeBuilder
  26  * @access public
  27  * @package WACT_TEMPLATE
  28  */
  29  class TreeBuilder {
  30      /**
  31      * Parent Component
  32      * @var CompilerComponent subclass of
  33      * @access public
  34      */
  35      var $ParentComponent;
  36      /**
  37      * Current Component
  38      * @var CompilerComponent subclass of
  39      * @access public
  40      */
  41      var $Component;
  42  
  43      var $variableReferencePattern;
  44      
  45      /**
  46      * Constructs TreeBuilder, setting up expression parsers
  47      * @access public
  48      */
  49  	function TreeBuilder(&$ComponentRoot) {
  50          $this->Component =& $ComponentRoot;
  51          $this->ParentComponent = NULL;
  52  
  53          $this->variableReferencePattern =
  54              // start at the beginning
  55              '/^' . 
  56              // Pick up the portion of the string before the variable reference
  57              '((?s).*?)' .
  58              // Beginning of a variable reference
  59              preg_quote('{$', '/') .
  60              // Collect the entire variable reference into one subexpression
  61              '(' . 
  62                  // capture the contents of one or more fragments.
  63                  '(' . 
  64                      // Anything thats not a quote or the end of the variable
  65                      // reference can be in a fragment
  66                      '[^"\'}]+' .
  67                      // OR
  68                      '|' .
  69                      // A string inside quotes is also a fragment
  70                      '(\'|").*?\4' .
  71                  ')+' . 
  72              ')' .
  73              // end of a variable reference
  74              preg_quote('}', '/') .
  75              // Pick up the portion of the string after the variable reference
  76              // This portion may contain additional references; we only match
  77              // one at a time.
  78              '((?s).*)' .
  79              // Match until the end of the string
  80              '$/';
  81      }
  82  
  83      /**
  84      * Prepares the tree to accept a new tag component
  85      * @param string class name to create component with
  86      * @param string XML tag name of component
  87      * @param array attributes for tag
  88      * @param boolean whether the tag has contents
  89      * @return void
  90      * @access public
  91      */
  92  	function openBranch(&$TagInfo, $tag, $attrs, $isEmpty, &$Locator) {
  93          $this->ParentComponent =& $this->Component;
  94          
  95          $this->Component =& $this->createComponent($TagInfo, $tag, $Locator);
  96             $this->Component->emptyClosedTag = $isEmpty;
  97          $this->buildAttributes($attrs);
  98          
  99          $this->checkServerId($this->Component);
 100          $this->ParentComponent->addChild($this->Component);
 101          $this->Component->CheckNestingLevel();
 102      }
 103  
 104      /**
 105      * Create a new tag component
 106      * @param string class name to create component with
 107      * @param string XML tag name of component
 108      * @return void
 109      * @access private
 110      */
 111      function &createComponent(&$TagInfo, $tag, &$Locator) {
 112          $class = $TagInfo->TagClass;
 113          $component =& new $class();
 114          $component->SourceFile = $Locator->getPublicId();
 115          $component->StartingLineNo = $Locator->getLineNumber(); 
 116          $component->tag = $tag;
 117          $component->TagInfo =& $TagInfo;
 118          $properties = $GLOBALS['PropertyDictionary']->getPropertyList($tag);
 119          foreach ($properties as $property) {
 120              $property->load();
 121              $PropertyClass = $property->PropertyClass;
 122              $component->registerProperty(
 123                  $property->Property, new $PropertyClass($component));
 124  
 125          }
 126          return $component;
 127      }
 128  
 129      function &createAttributeExpression($name, $expression) {
 130          if (strcasecmp($name, 'id') == 0 ) {
 131              RaiseError('compiler', 'ILLEGALVARREFINATTR', array(
 132                  'tag' => $this->Component->tag,
 133                  'attribute' => $name,     
 134                  'file' => $this->Component->SourceFile, 
 135                  'line' => $this->Component->StartingLineNo));
 136          }
 137  
 138          return new AttributeExpression($name, $expression, $this->Component);
 139      }
 140  
 141      function &createCompoundAttribute($name, $value) {
 142          if (strcasecmp($name, 'id') == 0 ) {
 143              RaiseError('compiler', 'ILLEGALVARREFINATTR', array(
 144                  'tag' => $this->Component->tag,
 145                  'attribute' => $name,     
 146                  'file' => $this->Component->SourceFile, 
 147                  'line' => $this->Component->StartingLineNo));
 148          }
 149  
 150          $attribute =& new CompoundAttribute($name);
 151          
 152          while (preg_match($this->variableReferencePattern, $value, $match)) {
 153              if (strlen($match[WACT_EXPPARSER_BEFORE_CONTENT]) > 0) {
 154                  $attribute->addAttributeFragment(
 155                      new AttributeNode($name, $match[WACT_EXPPARSER_BEFORE_CONTENT]));
 156              }
 157              
 158              $attribute->addAttributeFragment(new AttributeExpression($name,
 159                  $match[WACT_EXPPARSER_EXPRESSION], $this->Component));
 160              
 161              $value = $match[WACT_EXPPARSER_AFTER_CONTENT];
 162          }
 163          if (strlen($value) > 0) {
 164              $attribute->addAttributeFragment(new AttributeNode($name, $value));
 165          }
 166          
 167          return $attribute;
 168      }
 169  
 170      /**
 171      * Create AttributeNodes or ArtributeVariableReferences
 172      * @param array attributes found in tag
 173      * @return void
 174      * @access private
 175      */
 176  	function buildAttributes($Attributes) {
 177          foreach ( $Attributes as $name => $value ) {
 178              // if there is no expression (common case), shortcut this process
 179              if (strpos($value, '{$') === FALSE) {
 180                  $attribute =& new AttributeNode($name, $value);
 181              } else {
 182                  if (preg_match($this->variableReferencePattern, $value, $match)) {
 183                      if (strlen($match[WACT_EXPPARSER_AFTER_CONTENT]) == 0 && 
 184                          strlen($match[WACT_EXPPARSER_BEFORE_CONTENT]) == 0) {
 185                          $attribute =& $this->createAttributeExpression($name, 
 186                              $match[WACT_EXPPARSER_EXPRESSION]);
 187                      } else {
 188                          $attribute =& $this->createCompoundAttribute($name, $value);
 189                      }
 190                  } else {
 191                      $attribute =& new AttributeNode($name, $value);
 192                  }
 193              }
 194  
 195              $this->Component->addChildAttribute($attribute);
 196          }
 197      }
 198  
 199      /**
 200      * Make sure we never have a duplicate Server Id in the component tree we build.
 201      * Uses GetComponentTree() to fetch current instance of ComponentTree, where list
 202      * of used tag ids are stored
 203      * @param object current component
 204      * @return void
 205      * @access private
 206      */
 207  	function checkServerId(&$Component) {
 208          $Tree = & GetComponentTree();
 209          $ServerId = $Component->getServerId();
 210          if (in_array($ServerId,$Tree->tagIds) ) {
 211              RaiseError('compiler', 'DUPLICATEID', array(
 212                  'ServerId' => $ServerId,
 213                  'tag' => $Component->tag,
 214                  'file' => $Component->SourceFile, 
 215                  'line' => $Component->StartingLineNo));
 216          } else {
 217              $Tree->tagIds[]=$ServerId;
 218          }
 219      }
 220  
 221      /**
 222      * Handles the CDATA content within any tag
 223      * @param string content of tag
 224      * @param boolean whether parsing of text is currently forbidden
 225      * @return void
 226      * @access public
 227      */
 228  	function addContent(&$Locator, $text) {
 229          // if there is no expression (common case), shortcut this process
 230          if (strpos($text, '{$') === FALSE) {
 231              $this->addTextNode($text);
 232              return;
 233          }
 234  
 235          while (preg_match($this->variableReferencePattern, $text, $match)) {
 236              if (strlen($match[WACT_EXPPARSER_BEFORE_CONTENT]) > 0) {
 237                  $this->addTextNode($match[WACT_EXPPARSER_BEFORE_CONTENT]);
 238              }
 239  
 240              $expression =& new OutputExpression($match[WACT_EXPPARSER_EXPRESSION]);
 241              $expression->SourceFile = $Locator->getPublicId();
 242              $expression->StartingLineNo = $Locator->getLineNumber(); 
 243              $this->Component->addChild($expression);
 244          
 245              $text = $match[WACT_EXPPARSER_AFTER_CONTENT];
 246          }
 247          if (strlen($text) > 0) {
 248              $this->addTextNode($text);
 249          }
 250      }
 251  
 252      /**
 253      * Creates TextNodes for plain text
 254      * @param string text to create node for
 255      * @return void
 256      * @access public
 257      */
 258  	function addTextNode($text) {
 259          $LastChild = & $this->Component->getLastChild();
 260          if ( is_a($LastChild, 'TextNode') ) {
 261              $LastChild->append($text);
 262          } else {
 263              $TextNode =& new TextNode($text);
 264              $this->Component->addChild($TextNode);
 265          }
 266      }
 267  
 268      /**
 269      * Deals with XML processing instructions. PHP instructions are ignored.
 270      * @param string target processor
 271      * @param string instruction
 272      * @return void
 273      * @access public
 274      */
 275  	function addProcessingInstructionNode($target, $instruction) {
 276          // we can optimize here by not loading PHP node until we need it
 277          // It will probably be rarely used in templates.
 278          require_once WACT_ROOT . 'template/compiler/phpnode.inc.php';
 279      
 280          // Pass through any PI's except PHP PI's
 281          $invalid_targets = array('php','PHP','=','');
 282          if ( !in_array($target, $invalid_targets) ) {
 283              $php = 'echo "<?'.$target.' '; // Whitespace assumption
 284              $php.= str_replace('"','\"',$instruction);
 285              $php.= '?>\n";'; // Newline assumption
 286              $this->Component->addChild(new PHPNode($php));
 287          }
 288      }
 289  
 290      /**
 291      * Finishes a branch in the component tree, restoring control
 292      * to the ParentComponent
 293      * @param boolean whether current component has a closing tag
 294      * @return void
 295      * @access public
 296      */
 297  	function closeBranch($hasClosingTag) {
 298          $this->Component->hasClosingTag = $hasClosingTag;
 299          $this->Component = & $this->ParentComponent;
 300          $this->ParentComponent = & $this->Component->parent;    
 301      }
 302  }
 303  ?>


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