| [ Index ] |
PHP Cross Reference of Akelos Framework |
[Summary view] [Print] [Text view]
1 <?php 2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ 3 4 // +----------------------------------------------------------------------+ 5 // | Akelos Framework - http://www.akelos.org | 6 // +----------------------------------------------------------------------+ 7 // | Copyright (c) 2002-2007, Akelos Media, S.L. & Bermi Ferrer Martinez | 8 // | Released under the GNU Lesser General Public License, see LICENSE.txt| 9 // +----------------------------------------------------------------------+ 10 11 /** 12 * @package ActionView 13 * @subpackage Sintags 14 * @author Bermi Ferrer <bermi a.t akelos c.om> 15 * @copyright Copyright (c) 2002-2006, Akelos Media, S.L. http://www.akelos.org 16 * @license GNU Lesser General Public License <http://www.gnu.org/copyleft/lesser.html> 17 */ 18 19 class AkSintagsParser 20 { 21 22 var $_SINTAGS_OPEN_HELPER_TAG = AK_SINTAGS_OPEN_HELPER_TAG; 23 var $_SINTAGS_CLOSE_HELPER_TAG = AK_SINTAGS_CLOSE_HELPER_TAG; 24 var $_SINTAGS_HASH_KEY_VALUE_DELIMITER = AK_SINTAGS_HASH_KEY_VALUE_DELIMITER; 25 26 var $_Lexer; 27 var $_lexer_name = 'AkSintagsLexer'; 28 var $_mode; 29 var $_last_match; 30 var $_matches; 31 var $_current_match; 32 var $_block_vars = array(); 33 var $output; 34 var $escape_chars = array( 35 '\{' => '____AKST_OT____', 36 '\}' => '____AKST_CT____', 37 '\"' => '____AKST_DQ____', 38 "\'" => '____AKST_SQ____' 39 ); 40 41 function AkSintagsParser($mode = 'Text') 42 { 43 $this->_Lexer =& new $this->_lexer_name($this); 44 $this->_mode = $mode; 45 $this->_matches = array(); 46 $this->_last_match = ''; 47 $this->_current_match = ''; 48 } 49 50 function parse($raw) 51 { 52 $this->_Lexer->parse($this->beforeParsing($this->_escapeChars($raw))); 53 return $this->afterParsing($this->getResults()); 54 } 55 56 function beforeParsing($raw) 57 { 58 return $raw; 59 } 60 61 function afterParsing($parsed) 62 { 63 return $parsed; 64 } 65 66 function ignore($match, $state) 67 { 68 return true; 69 } 70 71 //------------------------------------ 72 // PHP CODE 73 //------------------------------------ 74 function PhpCode($match, $state) 75 { 76 if(!AK_SINTAGS_REPLACE_SHORTHAND_PHP_TAGS){ 77 $this->output .= $match; 78 return true; 79 } 80 switch ($state){ 81 case AK_LEXER_ENTER: 82 $this->output .= '<?php '; 83 break; 84 case AK_LEXER_UNMATCHED: 85 $match = ltrim($match); 86 if(!empty($match)){ 87 if(substr($match,0,3) == 'php'){ 88 $match = substr($match,3); 89 }elseif($match[0] == '='){ 90 $match = 'echo '.substr($match,1); 91 } 92 $this->output.= $match; 93 } 94 break; 95 case AK_LEXER_EXIT: 96 $this->output .= '?>'; 97 } 98 return true; 99 } 100 101 //---------------------------------------------------- 102 // XML OPENING COMPATIBILITY WHITH SHORTAGS SETTINGS 103 //---------------------------------------------------- 104 function XmlOpening($match, $state) 105 { 106 if(AK_LEXER_SPECIAL === $state){ 107 $this->output .= '<?php echo \'<?xml\'; ?>'; 108 } 109 return true; 110 } 111 112 //------------------------------------ 113 // PLAIN TEXT 114 //------------------------------------ 115 116 function Text($text) 117 { 118 $this->output .= $text; 119 return true; 120 } 121 122 // UTILS 123 function getResults() 124 { 125 return $this->_unescapeChars($this->output); 126 } 127 function _escapeChars($string) 128 { 129 return str_replace(array_keys($this->escape_chars),array_values($this->escape_chars),$string); 130 } 131 function _unescapeChars($string, $strip_slashes_from_tokens = false) 132 { 133 $escape_chars = array_merge(array('{' => '____AKST_OT____','}' => '____AKST_CT____'), $this->escape_chars); 134 $replacements = $strip_slashes_from_tokens ? array_map('stripcslashes',array_keys($escape_chars)) : array_keys($escape_chars); 135 return str_replace(array_values($escape_chars),$replacements,$string); 136 } 137 138 //------------------------------------ 139 // ESCAPED TEXT 140 //------------------------------------ 141 142 function EscapedText($match, $state) 143 { 144 $this->output .= ltrim($match,'\\'); 145 return true; 146 } 147 148 //------------------------------------ 149 // TRANSLATIONS 150 //------------------------------------ 151 152 function Translation($match, $state) 153 { 154 switch ($state){ 155 case AK_LEXER_ENTER: 156 $this->_translation_tokens = array(); 157 $this->output .= '<?php echo $text_helper->translate(\''; 158 break; 159 case AK_LEXER_UNMATCHED: 160 $this->output.= $this->_unescapeChars(str_replace("'","\'",$match), true); 161 break; 162 case AK_LEXER_EXIT: 163 $this->output .= '\', array('.(empty($this->_translation_tokens)?'':join(', ',$this->_translation_tokens)).')); ?>'; 164 } 165 return true; 166 } 167 168 169 //------------------------------------ 170 // TRANSLATIONS TOKEN 171 //------------------------------------ 172 173 function TranslationToken($match) 174 { 175 $this->output.= ltrim($match,'\\'); 176 $php_variable = $this->_convertSintagsVarToPhp(trim($match,'%')); 177 if($match[0] != '\\' && $php_variable){ 178 $this->_translation_tokens[] = '\''.$match.'\' => @'.$php_variable; 179 } 180 return true; 181 } 182 183 184 185 //------------------------------------ 186 // VARIABLE TRANSLATIONS 187 //------------------------------------ 188 189 function VariableTranslation($match, $state) 190 { 191 $php_variable = $this->_convertSintagsVarToPhp(trim($match,'{_}?')); 192 if($php_variable){ 193 $this->output .= '<?php echo empty('.$php_variable.') || is_object('.$php_variable.') ? \'\' : $text_helper->translate('.$php_variable.'); ?>'; 194 }else{ 195 $this->output .= $match; 196 } 197 return true; 198 } 199 200 201 //------------------------------------ 202 // SINTAGS CONDITIONAL VARIABLES 203 //------------------------------------ 204 205 function ConditionalVariable($match, $state) 206 { 207 $php_variable = $this->_convertSintagsVarToPhp(trim($match,'{}?')); 208 if($php_variable){ 209 $this->output .= '<?php echo empty('.$php_variable.') ? \'\' : '.$php_variable.'; ?>'; 210 }else{ 211 $this->output .= $match; 212 } 213 return true; 214 } 215 216 217 218 //------------------------------------ 219 // SINTAGS VARIABLES 220 //------------------------------------ 221 222 function Variable($match, $state) 223 { 224 $php_variable = $this->_convertSintagsVarToPhp($match); 225 if($php_variable){ 226 $this->output .= '<?php echo '.$php_variable.'; ?>'; 227 }else{ 228 $this->output .= $match; 229 } 230 return true; 231 } 232 233 234 function _convertSintagsVarToPhp($var) 235 { 236 if(preg_match('/[\.-]_/',$var)){ 237 return false; 238 } 239 $var = str_replace(array('-','.'),array('~','->'),trim($var,'-_.{}@')); 240 if(strstr($var,'~')){ 241 $pieces = explode('~',$var); 242 $var = array_shift($pieces); 243 if(!empty($pieces)){ 244 foreach ($pieces as $piece){ 245 $array_start = strpos($piece,'-'); 246 $array_key = $array_start ? substr($piece,0,$array_start) : substr($piece,0); 247 $var .= str_replace($array_key, (is_numeric($array_key) ? '['.$array_key.']' : '[\''.$array_key.'\']'),$piece); 248 } 249 } 250 } 251 return '$'.$var; 252 } 253 254 //------------------------------------ 255 // SINTAGS CONDITIONS 256 //------------------------------------ 257 258 function ConditionStart($match, $state) 259 { 260 if(AK_LEXER_SPECIAL === $state){ 261 $match = trim($match,'{}'); 262 $assert_simbol = substr($match,0,1) == '?' ? '!' : ''; 263 $php_variable = $this->_convertSintagsVarToPhp(trim($match,'?!')); 264 if($php_variable){ 265 $this->output .= '<?php if('.$assert_simbol.'empty('.$php_variable.')) { ?>'; 266 }else{ 267 $this->output .= $match; 268 } 269 } 270 return true; 271 } 272 273 //------------------------------------ 274 // SINTAGS END TAG 275 //------------------------------------ 276 277 function EndTag($match, $state) 278 { 279 if(AK_LEXER_SPECIAL === $state){ 280 $this->output .= '<?php } ?>'; 281 } 282 return true; 283 } 284 285 //------------------------------------ 286 // SINTAGS ELSE TAG 287 //------------------------------------ 288 289 function ElseTag($match, $state) 290 { 291 if(AK_LEXER_SPECIAL === $state){ 292 $this->output .= '<?php } else { ?>'; 293 } 294 return true; 295 } 296 297 298 //------------------------------------ 299 // SINTAGS LOOP 300 //------------------------------------ 301 302 function Loop($match, $state) 303 { 304 if(AK_LEXER_SPECIAL === $state){ 305 $sintags_var = trim(preg_replace('/[\s|?]+/',' ', substr($match, 6,-1))); 306 if(strstr($sintags_var,' as ')){ 307 $new_sintags_var = substr($sintags_var,0, strpos($sintags_var,' ')); 308 $termination = $this->_getTerminationName(AkInflector::pluralize(str_replace($new_sintags_var.' as ','', $sintags_var))); 309 $sintags_var = $new_sintags_var; 310 } 311 $php_variable = $this->_convertSintagsVarToPhp($sintags_var); 312 if($php_variable){ 313 $php_variable = $php_variable; 314 $termination = empty($termination) ? $this->_getTerminationName($sintags_var) : $termination; 315 $singular_variable = '$'.AkInflector::singularize($termination); 316 $plural_variable = '$'.$termination; 317 318 $this->output .= 319 "<?php ". 320 "\n empty({$php_variable}) ? null : {$singular_variable}_loop_counter = 0;". 321 "\n empty({$php_variable}) ? null : {$plural_variable}_available = count({$php_variable});". 322 "\n if(!empty({$php_variable}))". 323 "\n foreach ({$php_variable} as {$singular_variable}_loop_key=>{$singular_variable}){". 324 "\n {$singular_variable}_loop_counter++;". 325 "\n {$singular_variable}_is_first = {$singular_variable}_loop_counter === 1;". 326 "\n {$singular_variable}_is_last = {$singular_variable}_loop_counter === {$plural_variable}_available;". 327 "\n {$singular_variable}_odd_position = {$singular_variable}_loop_counter%2;". 328 "\n?>"; 329 }else{ 330 $this->output .= $match; 331 } 332 } 333 return true; 334 } 335 336 function _getTerminationName($plural) 337 { 338 $plural = str_replace('-','.', $plural); 339 $pos = strrpos($plural, '.'); 340 return substr($plural, $pos > 0 ? $pos+1 : 0); 341 } 342 343 344 //------------------------------------ 345 // SINTAGS HELPER MODE 346 //------------------------------------ 347 348 function Helper($match, $state, $position = null, $is_inline_function = false) 349 { 350 switch ($state){ 351 case AK_LEXER_ENTER: 352 if(preg_match('/=+$/', trim($match))){ 353 $this->avoid_php_tags = $this->_current_function_opening = false; 354 $this->output .= '<?php '.$this->_convertSintagsVarToPhp(trim($match,' =('.$this->_SINTAGS_OPEN_HELPER_TAG)).' = ('; 355 return true; 356 } 357 $method_name = trim($match,' =('.$this->_SINTAGS_OPEN_HELPER_TAG); 358 if($helper = $this->_getHelperNameForMethod($method_name)){ 359 $this->avoid_php_tags = !$is_inline_function && !strstr($match,'='); 360 $this->_current_function_opening = strlen($this->output); 361 if(!$this->avoid_php_tags){ 362 $this->output .= $is_inline_function ? '' : '<?php echo '; 363 } 364 if(!strpos($helper, 'helper')){ 365 $method_name = AkInflector::variablize($method_name); 366 } 367 $this->output .= "\${$helper}->$method_name("; 368 return true; 369 }else{ 370 $this->raiseError(Ak::t('Could not find a helper to handle the method "%method" you called in your view', array('%method'=>$method_name)), E_USER_NOTICE); 371 } 372 return false; 373 break; 374 375 case AK_LEXER_UNMATCHED: 376 $match = trim($match); 377 if($match == ','){ 378 $this->output .= $match.' '; 379 }elseif ($match == $this->_SINTAGS_HASH_KEY_VALUE_DELIMITER){ 380 if(empty($this->_inside_array) && empty($this->_has_last_argument_params)){ 381 $current_function = substr($this->output,$this->_current_function_opening); 382 383 $function_opening = strrpos($current_function,'(')+1; 384 $last_comma = strrpos($current_function,',')+1; 385 $insert_point = $function_opening > $last_comma && $last_comma === 1 ? $function_opening : $last_comma; 386 387 $this->output = substr($this->output,0,$this->_current_function_opening+$insert_point).' array('.ltrim(substr($this->output,$this->_current_function_opening+$insert_point)); 388 $this->_has_last_argument_params = true; 389 } 390 391 $this->output .= ' => '; 392 } 393 break; 394 395 case AK_LEXER_EXIT: 396 $this->output .= (!empty($this->_has_last_argument_params) ? ')':'').')'. 397 ($this->avoid_php_tags ? '' : ($is_inline_function?'':'; ?>')); 398 $this->_has_last_argument_params = false; 399 break; 400 } 401 402 return true; 403 } 404 405 406 //------------------------------------ 407 // SINTAGS HELPER FUNCTION MODE 408 //------------------------------------ 409 410 function HelperFunction($match, $state, $position = null) 411 { 412 return $this->Helper($match, $state, $position, true); 413 } 414 415 //------------------------------------ 416 // SINTAGS INLINE HELPER MODE 417 //------------------------------------ 418 419 function InlineHelper($match, $state, $position = null) 420 { 421 $success = true; 422 if(AK_LEXER_ENTER === $state){ 423 $this->output .= '".'; 424 $success = $this->Helper(ltrim($match,'{#'), $state, $position, true); 425 }elseif(AK_LEXER_EXIT === $state){ 426 $success = $this->Helper($match, $state, $position, true); 427 $this->output .= '."'; 428 }else{ 429 $success = $this->Helper($match, $state, $position, true); 430 } 431 return $success; 432 } 433 434 //------------------------------------ 435 // SINTAGS INLINE VARIABLE MODE 436 //------------------------------------ 437 438 function InlineVariable($match, $state, $position = null) 439 { 440 $php_variable = $this->_convertSintagsVarToPhp(trim($match,'#{}')); 441 if($php_variable){ 442 $this->output .= '".'.$php_variable.'."'; 443 } 444 return true; 445 } 446 447 //------------------------------------ 448 // SINTAGS VARIABLES 449 //------------------------------------ 450 451 function HelperVariable($match, $state, $position = null, $inline = false) 452 { 453 $php_variable = $this->_convertSintagsVarToPhp(trim($match)); 454 if($php_variable){ 455 $this->output .= $inline ? '".'.$php_variable.'."' : $php_variable; 456 return true; 457 }else{ 458 return false; 459 } 460 } 461 462 //----------------------------------------- 463 // SINTAGS HELPER SINGLE QUOTES PARAMETER 464 //----------------------------------------- 465 function SingleQuote($match, $state) 466 { 467 return $this->_handleQuotedParam($match, $state, "'"); 468 } 469 470 //----------------------------------------- 471 // SINTAGS HELPER DOUBLE QUOTES PARAMETER 472 //----------------------------------------- 473 function DoubleQuote($match, $state) 474 { 475 return $this->_handleQuotedParam($match, $state, '"'); 476 } 477 478 function _handleQuotedParam($match, $state, $quote_using) 479 { 480 if(AK_LEXER_ENTER === $state){ 481 $this->output .= $quote_using; 482 } 483 if(AK_LEXER_UNMATCHED === $state){ 484 $this->output .= $match; 485 } 486 if(AK_LEXER_EXIT === $state){ 487 $this->output .= $quote_using; 488 } 489 return true; 490 } 491 492 //----------------------------------------- 493 // SINTAGS HELPER NUMBER PARAMETER 494 //----------------------------------------- 495 function Numbers($match, $state) 496 { 497 if(AK_LEXER_SPECIAL === $state){ 498 $this->output .= $match; 499 } 500 return true; 501 } 502 503 //----------------------------------------- 504 // SINTAGS HELPER RUBY STYLE SYMBOLS 505 //----------------------------------------- 506 function Symbol($match, $state) 507 { 508 if(AK_LEXER_SPECIAL === $state){ 509 $this->output .= "'".ltrim($match,': ')."'"; 510 } 511 return true; 512 } 513 514 //----------------------------------------- 515 // SINTAGS HELPER RUBY STYLE STRUCTS 516 //----------------------------------------- 517 function Struct($match, $state) 518 { 519 if(AK_LEXER_SPECIAL === $state){ 520 $this->output .= $match == '[' ? 'array(' : ')'; 521 } 522 return true; 523 } 524 525 526 //----------------------------------------- 527 // SINTAGS HELPER RUBY HASHES 528 //----------------------------------------- 529 function Hash($match, $state) 530 { 531 switch ($state){ 532 case AK_LEXER_ENTER: 533 $this->_inside_array = true; 534 $this->output .= 'array('; 535 break; 536 case AK_LEXER_UNMATCHED: 537 $match = trim($match); 538 if($match == $this->_SINTAGS_HASH_KEY_VALUE_DELIMITER){ 539 $this->output .= ' => '; 540 }elseif($match == ','){ 541 $this->output .= ', '; 542 } 543 break; 544 case AK_LEXER_EXIT: 545 $this->_inside_array = false; 546 $this->output .= ')'; 547 break; 548 } 549 return true; 550 } 551 552 553 //----------------------------------------- 554 // SINTAGS BLOCKS 555 //----------------------------------------- 556 function Block($match, $state) 557 { 558 switch ($state){ 559 case AK_LEXER_ENTER: 560 $this->_block = ''; 561 $this->_block_params = array(); 562 $this->_block_data = array(); 563 if(strstr($match, '=')){ 564 list($parameters, $match) = explode('=', $match); 565 $parameters = array_diff(array_map('trim', Ak::toArray(trim($parameters,' (){|'.$this->_SINTAGS_OPEN_HELPER_TAG))), array('')); 566 foreach ($parameters as $parameter){ 567 if($parameter = $this->_convertSintagsVarToPhp($parameter)){ 568 $this->_block_params[] = $parameter; 569 }else{ 570 return false; 571 } 572 } 573 } 574 $method_or_var_names = array_diff(array_map('trim', Ak::toArray(trim($match,' (){|'.$this->_SINTAGS_OPEN_HELPER_TAG))), array('')); 575 foreach ($method_or_var_names as $method_or_var_name){ 576 if($helper = $this->_getHelperNameForMethod($method_or_var_name)){ 577 if(!strpos($helper, 'helper')){ 578 $method_or_var_name = AkInflector::variablize($method_or_var_name); 579 } 580 $this->_block_data[] = "\${$helper}->$method_or_var_name()"; 581 return true; 582 }elseif(!strstr($match,'(') && $php_variable = $this->_convertSintagsVarToPhp($method_or_var_name)){ 583 $this->_block_data[] = $php_variable; 584 }else{ 585 $this->raiseError(Ak::t('Could not find a helper to handle the method "%method" you called in your view', array('%method'=>$method_or_var_name)), E_USER_NOTICE); 586 } 587 } 588 589 break; 590 case AK_LEXER_MATCHED: 591 $this->_block_keys = array(); 592 $parameters = Ak::toArray($match); 593 foreach ($parameters as $parameter){ 594 if($parameter = $this->_convertSintagsVarToPhp($parameter)){ 595 $this->_block_keys[] = $parameter; 596 }else{ 597 return false; 598 } 599 } 600 break; 601 case AK_LEXER_UNMATCHED: 602 $this->_block .= $match; 603 break; 604 case AK_LEXER_EXIT: 605 606 $this->output .= "<?php \n"; 607 foreach ($this->_block_data as $k=>$block_data){ 608 if(strstr($block_data,'->')){ 609 /** 610 * @todo Implement helper calls on blocks 611 */ 612 }else{ 613 $this->output .= "if(!empty($block_data)){\n"; 614 if(!empty($this->_block_params[$k])){ 615 $this->output .= " {$this->_block_params[$k]} = array();\n"; 616 } 617 $this->output .= " foreach (array_keys((array)$block_data) as \$ak_sintags_key){\n"; 618 if(count($this->_block_keys) == 1){ 619 $this->output .= " {$this->_block_keys[0]} =& {$block_data}[\$ak_sintags_key];\n"; 620 } 621 $this->output .= " $this->_block;\n"; 622 if(!empty($this->_block_params[$k])){ 623 $this->output .= " {$this->_block_params[$k]}[\$ak_sintags_key] = {$block_data}[\$ak_sintags_key];\n"; 624 } 625 $this->output .= " }\n"; 626 $this->output .= "}"; 627 } 628 } 629 $this->output .= "?>"; 630 631 return true; 632 } 633 634 return true; 635 } 636 637 638 function raiseError($error, $type = E_USER_NOTICE) 639 { 640 trigger_error($error, $type); 641 } 642 643 function _tokenizeHelperStructures($raw_structures) 644 { 645 $i = 1; 646 $arrays = array(); 647 while(preg_match('/\x5B(?!.*\x5B+.*)[^\x5D]+\x5D/',$raw_structures,$match)){ 648 $token = '___SINTAGS_TOKEN_POS___'.$i; 649 $raw_structures = str_replace($match[0],$token,$raw_structures); 650 $arrays[$token] = 'array('.trim($match[0],'[]').')'; 651 $i++; 652 } 653 if(!empty($arrays)){ 654 krsort($arrays); 655 return str_replace(array_keys($arrays), array_values($arrays), $raw_structures); 656 }else{ 657 return $raw_structures; 658 } 659 } 660 661 662 function _getAvailableHelpers() 663 { 664 $helpers = array(); 665 if(empty($this->available_helpers)){ 666 if(defined('AK_SINTAGS_AVALABLE_HELPERS')){ 667 $helpers = unserialize(AK_SINTAGS_AVALABLE_HELPERS); 668 }else{ 669 require_once (AK_LIB_DIR.DS.'AkActionView'.DS.'AkHelperLoader.php'); 670 if($underscored_helper_names = AkHelperLoader::getInstantiatedHelperNames()){ 671 foreach ($underscored_helper_names as $underscored_helper_name){ 672 $helper_class_name = AkInflector::camelize($underscored_helper_name); 673 if(class_exists($helper_class_name)){ 674 foreach (get_class_methods($helper_class_name) as $method_name){ 675 if($method_name[0] != '_'){ 676 $helpers[$method_name] = $underscored_helper_name; 677 } 678 } 679 } 680 } 681 $helpers['render'] = 'controller'; 682 $helpers['render_partial'] = 'controller'; 683 } 684 } 685 $this->available_helpers = $helpers; 686 } 687 return $this->available_helpers; 688 689 } 690 691 function _getHelperNameForMethod(&$method_name) 692 { 693 if($method_name == '_'){ 694 $method_name = 'translate'; 695 } 696 $this->_getAvailableHelpers(); 697 return empty($this->available_helpers[$method_name]) ? false : $this->available_helpers[$method_name]; 698 } 699 700 } 701 702 ?>
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Mon Oct 27 12:43:49 2008 | Cross-referenced by PHPXref 0.6 |