| [ Index ] |
PHP Cross Reference of Web Application Component Toolkit |
[Summary view] [Print] [Text view]
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 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Sun Nov 28 19:36:09 2004 | Cross-referenced by PHPXref 0.5 |