| [ 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: expression.inc.php,v 1.29 2004/11/18 04:22:46 jeffmoore Exp $ 9 */ 10 11 require_once WACT_ROOT . 'template/compiler/expressionlexer.inc.php'; 12 13 //-------------------------------------------------------------------------------- 14 /** 15 * Represents a single Expression found in the template. Responsibly for parsing 16 * the expression and building a filter chain for the expression (if expression 17 * contained filter syntax) 18 * @access protected 19 * @package WACT_TEMPLATE 20 */ 21 class Expression { 22 23 /** 24 * Tree of compiler filters 25 * @var object subclass of CompileFilter 26 * @access private 27 */ 28 var $filterChain; 29 30 /** 31 * used for error messages 32 * @var string 33 * @access private 34 */ 35 var $expression; 36 37 /** 38 * @param string expression 39 * @param object Compiler Component that attribute was found in 40 * @param string (optional) default filter to apply 41 * @access protected 42 */ 43 function Expression($expression, &$ComponentContext, $DefaultFilter = 'raw') { 44 $this->expression = $expression; 45 $ApplyDefaultFilter = TRUE; 46 if (preg_match('/^(.*)\s*\|\s*raw$/is', $expression, $match)) { 47 $ApplyDefaultFilter = FALSE; 48 $expression = $match[1]; 49 } 50 if ($DefaultFilter == 'raw') { 51 $ApplyDefaultFilter = FALSE; 52 } 53 54 $pos = strpos($expression, "|"); 55 if ($pos === FALSE) { 56 $base =& $this->createValue($expression, $ComponentContext); 57 } else { 58 $dbe = trim(substr($expression, 0, $pos)); 59 $filters = trim(substr($expression, $pos + 1)); 60 $base =& $this->createFilterChain( 61 $filters, 62 $this->createValue($dbe, $ComponentContext), 63 $ComponentContext); 64 } 65 66 if ($ApplyDefaultFilter) { 67 $fd =& FilterDictionary::getInstance(); 68 $filterInfo =& $fd->getFilterInfo($DefaultFilter); 69 if (is_object($filterInfo)) { 70 $filterInfo->load(); 71 $filter_class = $filterInfo->FilterClass; 72 73 // Don't apply the default filter if the last filter in the 74 // chain is already that filter. 75 if (strcasecmp(get_class($base), $filter_class) == 0) { 76 $this->filterChain =& $base; 77 } else { 78 $filter =& new $filter_class(); 79 $filter->registerBase($base); 80 $this->filterChain =& $filter; 81 } 82 } else { 83 RaiseError('compiler', 'MISSING_FILTER', array( 84 'filter' => $DefaultFilter, 85 'file' => $ComponentContext->SourceFile, 86 'line' => $ComponentContext->StartingLineNo)); 87 } 88 } else { 89 $this->filterChain =& $base; 90 } 91 } 92 93 /** 94 * Parses an expression and returns an object representing the expression 95 * @param string expression 96 * @param object Compiler Component that attribute was found in 97 * @return object ConstantProperty or DataBindingExpression 98 * @access private 99 */ 100 function &createValue($expression, &$ComponentContext) { 101 $Parser = & new ExpressionValueParser($expression); 102 103 switch ( $Parser->ValueType ) { 104 // NULL and BOOLEAN values left out on purpose 105 case EXPRESSION_VALUE_INT: 106 case EXPRESSION_VALUE_FLOAT: 107 case EXPRESSION_VALUE_STRING: 108 return new ConstantProperty($Parser->Value); 109 break; 110 111 case EXPRESSION_VALUE_DATABINDING: 112 default: 113 return new DataBindingExpression($expression, $ComponentContext); 114 break; 115 116 } 117 118 } 119 120 /** 121 * Parses an expression, building a chain of filters for it 122 * @param string expression 123 * @param object base filter to start with (CompilerFilter) 124 * @param object Compiler Component that attribute was found in 125 * @return object filter with chain of filters attached 126 * @access private 127 */ 128 function &createFilterChain($expr, $Value, &$ComponentContext) { 129 130 $Fd =& FilterDictionary::getInstance(); 131 132 $FFp = & new ExpressionFilterFindingParser($expr); 133 134 $Base = & $Value; 135 136 if ( count($FFp->Filters) == 0 ) { 137 return $Value; 138 } 139 140 foreach ( $FFp->Filters as $filter_expr ) { 141 142 $Fp = & new ExpressionFilterParser($filter_expr); 143 144 if ( is_null($Fp->Name) ) { 145 RaiseError('compiler', 'INVALID_FILTER_SPEC', array( 146 'file' => $ComponentContext->SourceFile, 147 'line' => $ComponentContext->StartingLineNo)); 148 return $Value; 149 } 150 151 $FilterInfo =& $Fd->getFilterInfo($Fp->Name); 152 153 if (!is_object($FilterInfo)) { 154 RaiseError('compiler', 'MISSING_FILTER', array( 155 'filter' => $Fp->Name, 156 'file' => $ComponentContext->SourceFile, 157 'line' => $ComponentContext->StartingLineNo)); 158 return $Value; 159 } 160 161 $FilterInfo->load(); 162 $filter_class = $FilterInfo->FilterClass; 163 $Filter =& new $filter_class(); 164 165 if ( !is_null($Fp->Args) ) { 166 167 $numArgs = count($Fp->Args); 168 169 if ( $numArgs < $FilterInfo->MinParameterCount ) { 170 RaiseError('compiler', 'MISSING_FILTER_PARAMETER', array( 171 'filter' => $Fp->Name, 172 'file' => $ComponentContext->SourceFile, 173 'line' => $ComponentContext->StartingLineNo)); 174 return $Value; 175 } 176 177 if ($numArgs > $FilterInfo->MaxParameterCount) { 178 RaiseError('compiler', 'TOO_MANY_PARAMETERS', array( 179 'filter' => $Fp->Name, 180 'file' => $ComponentContext->SourceFile, 181 'line' => $ComponentContext->StartingLineNo)); 182 return $Value; 183 } 184 185 foreach ( $Fp->Args as $value_expr ) { 186 187 $Filter->registerParameter($this->createValue($value_expr, $ComponentContext)); 188 189 } 190 } 191 192 $Filter->registerBase($Base); 193 194 $Base = & $Filter; 195 196 } 197 198 return $Base; 199 200 } 201 202 /** 203 * Does this expression refer to a constant value (at compile time)? 204 * @return Boolean 205 * @access public 206 */ 207 function isConstant() { 208 return $this->filterChain->isConstant(); 209 } 210 211 /** 212 * Return the value of this expression 213 * @return String 214 * @access public 215 */ 216 function getValue() { 217 return $this->filterChain->getValue(); 218 } 219 220 /** 221 * Generate setup code for an expression reference 222 * @param CodeWriter 223 * @return void 224 * @access protected 225 */ 226 function generatePreStatement(&$code) { 227 $this->filterChain->generatePreStatement($code); 228 } 229 230 /** 231 * Generate the code to read the data value at run time 232 * Must generate only a valid PHP Expression. 233 * @param CodeWriter 234 * @return void 235 * @access protected 236 */ 237 function generateExpression(&$code) { 238 $this->filterChain->generateExpression($code); 239 } 240 241 /** 242 * Generate tear down code for an expression reference 243 * @param CodeWriter 244 * @return void 245 * @access protected 246 */ 247 function generatePostStatement(&$code) { 248 $this->filterChain->generatePostStatement($code); 249 } 250 251 /** 252 * Calls the prepare method on the root of the filter chain 253 * @return void 254 * @access protected 255 */ 256 function prepare() { 257 return $this->filterChain->prepare(); 258 } 259 260 } 261 262 //-------------------------------------------------------------------------------- 263 /**#@+ 264 * Value parser constants 265 */ 266 define ('EXPRESSION_VALUE_DATABINDING',0); 267 define ('EXPRESSION_VALUE_INT',1); 268 define ('EXPRESSION_VALUE_FLOAT',2); 269 define ('EXPRESSION_VALUE_STRING',3); 270 //-------------------------------------------------------------------------------- 271 /** 272 * Searches expression strings for constant values 273 * WARNING: this parser defaults to data binding expressions. That means if it 274 * doest recognise a integer, float or string constant, what it calls a data binding 275 * expression may not in fact be a data binding expression. It assumes that 276 * Expression::createValue asks it a parse a valid value string 277 * @package WACT_TEMPLATE 278 * @access protected 279 */ 280 class ExpressionValueParser { 281 /** 282 * @var int constant identifying type of value 283 * @access protected 284 */ 285 var $ValueType = EXPRESSION_VALUE_DATABINDING; 286 287 /** 288 * @var mixed constant value (string/int/float) 289 * @access protected 290 */ 291 var $Value; 292 293 /** 294 * Invokes the Lexer to parse the expression 295 * @param string expression to parse 296 */ 297 function ExpressionValueParser($expression) { 298 $Lexer = & ExpressionValueParser::getLexer(); 299 $Lexer->parse($expression); 300 } 301 302 /** 303 * Lexer callback - accepts the default data binding 304 * expression - called if no constants found 305 * @param string parsed expression 306 * @param int expression lexer state 307 * @access private 308 * @return boolean TRUE 309 */ 310 function acceptDatabinding($expression,$state) { 311 switch ( $state ) { 312 case EXPRESSION_LEXER_UNMATCHED: 313 // This doesnt actually get used in Expression::getValue 314 $this->Value = $expression; 315 break; 316 } 317 return TRUE; 318 } 319 320 /** 321 * Lexer callback - called for integer constants 322 * @param string matched integer 323 * @param int expression lexer state 324 * @access private 325 * @return boolean TRUE 326 */ 327 function acceptInteger($int,$state) { 328 switch ( $state ) { 329 case EXPRESSION_LEXER_SPECIAL: 330 $this->ValueType = EXPRESSION_VALUE_INT; 331 $this->Value = intval($int); 332 break; 333 } 334 335 return TRUE; 336 } 337 338 /** 339 * Lexer callback - called for float constants 340 * @param string matched float 341 * @param int expression lexer state 342 * @access private 343 * @return boolean TRUE 344 */ 345 function acceptFloat($float,$state) { 346 switch ( $state ) { 347 case EXPRESSION_LEXER_SPECIAL: 348 $this->ValueType = EXPRESSION_VALUE_FLOAT; 349 if (!function_exists('floatval')) { 350 require_once WACT_ROOT . 'util/phpcompat/floatval.php'; 351 } 352 $this->Value = floatval($float); 353 break; 354 } 355 return TRUE; 356 } 357 358 /** 359 * Lexer callback - called for string constants 360 * @param string matched string 361 * @param int expression lexer state 362 * @access private 363 * @return boolean TRUE 364 */ 365 function acceptString($string,$state) { 366 switch ( $state ) { 367 case EXPRESSION_LEXER_SPECIAL: 368 $this->ValueType = EXPRESSION_VALUE_STRING; 369 370 // Strip the quotes 371 // hack but saves introducing further Lexer complexity 372 $string = substr($string,1,strlen($string)-2); 373 374 $this->Value = $string; 375 break; 376 } 377 return TRUE; 378 } 379 380 /** 381 * Creates the Lexer. Ideally this should be a static instance for 382 * performance but Lexer left in strange state after parsing if 383 * static 384 * @return ExpressionLexer 385 * @access private 386 */ 387 function & getLexer() { 388 $Lexer = new ExpressionLexer($this,'databinding'); 389 390 $Lexer->addSpecialPattern('^-?\d+$','databinding','integer'); 391 $Lexer->addSpecialPattern('^-?\d+\.\d+$','databinding','float'); 392 $Lexer->addSpecialPattern('^".*"$','databinding','doublequote'); 393 $Lexer->addSpecialPattern('^\'.*\'$','databinding','singlequote'); 394 395 $Lexer->mapHandler('databinding','acceptDatabinding'); 396 $Lexer->mapHandler('integer','acceptInteger'); 397 $Lexer->mapHandler('float','acceptFloat'); 398 $Lexer->mapHandler('doublequote','acceptString'); 399 $Lexer->mapHandler('singlequote','acceptString'); 400 401 return $Lexer; 402 } 403 } 404 405 //-------------------------------------------------------------------------------- 406 /** 407 * Searches expression strings for filters 408 * WARNING: this parser expects the initial variable / value to have been stripped 409 * as happens in the Expression constructor 410 * @package WACT_TEMPLATE 411 * @access protected 412 */ 413 class ExpressionFilterFindingParser { 414 415 /** 416 * List of values found in expression, marked by filter delimiter 417 * @var array 418 * @access protected 419 */ 420 var $Filters = array(); 421 422 /** 423 * Current value 424 * @var mixed NULL when no value or string as value is built 425 * @access private 426 */ 427 var $filter = NULL; 428 429 /** 430 * Invokes the Lexer to parse the expression 431 * @param string expression to parse 432 */ 433 function ExpressionFilterFindingParser($expression) { 434 $Lexer = & ExpressionFilterFindingParser::getLexer(); 435 $Lexer->parse($expression); 436 437 // Make sure final value added to values 438 if ( !is_null($this->filter) ) { 439 $this->Filters[] = $this->filter; 440 } 441 } 442 443 /** 444 * Lexer callback - called for value strings 445 * @param string 446 * @param int expression lexer state 447 * @access private 448 * @return boolean TRUE 449 */ 450 function acceptFilter($filter,$state) { 451 switch ( $state ) { 452 case EXPRESSION_LEXER_UNMATCHED: 453 if ( is_null($this->filter) ) { 454 $this->filter = $filter; 455 } else { 456 $this->filter .= $filter; 457 } 458 break; 459 case EXPRESSION_LEXER_SPECIAL: 460 if ( is_null($this->filter) ) { 461 $this->filter = $filter; 462 } else { 463 $this->filter .= $filter; 464 } 465 break; 466 } 467 return TRUE; 468 } 469 470 /** 471 * Lexer callback - called every time a filter delimiter 472 * is found. Populates the Values array with the current 473 * value 474 * @access private 475 * @return boolean TRUE 476 */ 477 function addFilter() { 478 if ( !is_null ($this->filter) ) { 479 $this->Filters[] = $this->filter; 480 $this->filter = NULL; 481 } 482 return TRUE; 483 } 484 485 /** 486 * Creates the Lexer. 487 * @return ExpressionLexer 488 * @access private 489 */ 490 function & getLexer() { 491 $Lexer = new ExpressionLexer($this,'filter'); 492 493 $Lexer->addSpecialPattern('\|','filter','add'); 494 // $Lexer->addSpecialPattern('".*"','filter','doublequote'); 495 // $Lexer->addSpecialPattern('\'.*\'','filter','singlequote'); 496 $Lexer->addSpecialPattern('"[^"]*"','filter','doublequote'); 497 $Lexer->addSpecialPattern("'[^']*'",'filter','singlequote'); 498 499 $Lexer->mapHandler('filter','acceptFilter'); 500 $Lexer->mapHandler('doublequote','acceptFilter'); 501 $Lexer->mapHandler('singlequote','acceptFilter'); 502 $Lexer->mapHandler('add','addFilter'); 503 504 return $Lexer; 505 } 506 } 507 508 /** 509 * Parses a single filter expression 510 * WARNING: this parser expects strings parsed by ExpressionFilterFindingParser 511 * @package WACT_TEMPLATE 512 * @access protected 513 */ 514 class ExpressionFilterParser { 515 516 /** 517 * Name of the filter 518 * @var string 519 * @access protected 520 */ 521 var $Name = NULL; 522 523 /** 524 * List of arguments 525 * @var array 526 * @access protected 527 */ 528 var $Args = NULL; 529 530 /** 531 * Current argument 532 * @var string 533 * @access private 534 */ 535 var $arg = NULL; 536 537 /** 538 * Invokes the Lexer to parse the expression 539 * @param string expression to parse 540 */ 541 function ExpressionFilterParser($expression) { 542 $Lexer = & ExpressionFilterParser::getLexer(); 543 $Lexer->parse($expression); 544 545 // Make sure remaining argument added 546 if ( !is_null ($this->Args) && !is_null($this->arg) ) { 547 $this->Args[] = $this->arg; 548 } 549 } 550 551 /** 552 * Lexer callback - if the : delimiter is found, prepares the Args array 553 * @access private 554 * @return boolean TRUE 555 */ 556 function initArgs() { 557 $this->Args = array(); 558 return TRUE; 559 } 560 561 /** 562 * Lexer callback - if the , delimiter is found, adds the current arg 563 * to the Args array 564 * @access private 565 * @return boolean TRUE 566 */ 567 function addArg() { 568 if ( !is_null($this->Args) && !is_null($this->arg) ) { 569 $this->Args[] = $this->arg; 570 $this->arg = NULL; 571 } 572 return TRUE; 573 } 574 575 /** 576 * Lexer callback - accepts a single argument 577 * @param string 578 * @param int expression lexer state 579 * @access private 580 * @return boolean TRUE 581 */ 582 function accept($expression,$state) { 583 584 switch ( $state ) { 585 586 case EXPRESSION_LEXER_UNMATCHED: 587 if ( !is_null($this->Args) ) { 588 if ( is_null($this->arg) ) { 589 $this->arg = $expression; 590 } else { 591 $this->arg .= $expression; 592 } 593 } else { 594 if ( is_null($this->Name) ) { 595 $this->Name = $expression; 596 } 597 } 598 break; 599 600 case EXPRESSION_LEXER_SPECIAL: 601 if ( !is_null($this->Args) ) { 602 if ( is_null($this->arg) ) { 603 $this->arg = $expression; 604 } else { 605 $this->arg .= $expression; 606 } 607 } 608 break; 609 } 610 611 return TRUE; 612 } 613 614 /** 615 * Creates the Lexer. 616 * @return ExpressionLexer 617 * @access private 618 */ 619 function & getLexer() { 620 $Lexer = new ExpressionLexer($this,'value'); 621 622 $Lexer->addSpecialPattern(':','value','args'); 623 $Lexer->addSpecialPattern(',','value','arg'); 624 625 $Lexer->addSpecialPattern('"[^"]*"','value','doublequote'); 626 $Lexer->addSpecialPattern("'[^']*'",'value','singlequote'); 627 628 $Lexer->addPattern('\s','value'); 629 630 $Lexer->mapHandler('value','accept'); 631 $Lexer->mapHandler('args','initArgs'); 632 $Lexer->mapHandler('arg','addArg'); 633 $Lexer->mapHandler('doublequote','accept'); 634 $Lexer->mapHandler('singlequote','accept'); 635 636 637 return $Lexer; 638 } 639 640 } 641 ?>
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 |