[ Index ] |
|
Code source de PHPonTrax 2.6.6-svn |
1 <?php 2 /** 3 * File containing ActionController class 4 * 5 * (PHP 5) 6 * 7 * @package PHPonTrax 8 * @version $Id: action_controller.php 229 2006-07-18 11:20:04Z john $ 9 * @copyright (c) 2005 John Peterson 10 * 11 * Permission is hereby granted, free of charge, to any person obtaining 12 * a copy of this software and associated documentation files (the 13 * "Software"), to deal in the Software without restriction, including 14 * without limitation the rights to use, copy, modify, merge, publish, 15 * distribute, sublicense, and/or sell copies of the Software, and to 16 * permit persons to whom the Software is furnished to do so, subject to 17 * the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be 20 * included in all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 23 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 24 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 25 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 26 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 27 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 28 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 29 */ 30 31 /** 32 * Action controller 33 * 34 * <p>The ActionController base class operates as follows:</p> 35 * <ol> 36 * <li>Accept a URL as input</li> 37 * <li>Translate the URL into a controller and action</li> 38 * <li>Create the indicated controller object (which is a subclass 39 * of ActionController) and call its action method</li> 40 * <li>Render the output of the action method</li> 41 * <li>Redirect to the next URL</li> 42 * </ol> 43 * 44 * For details see the 45 * {@tutorial PHPonTrax/ActionController.cls class tutorial} 46 */ 47 class ActionController { 48 49 /** 50 * Name of the controller (without the _controller.php) 51 * 52 * Set by {@link recognize_route()} by parsing the URL and the 53 * routes in {@link routes.php}. The value of this string is set 54 * before any attempt is made to find the file containing the 55 * controller. 56 * @var string 57 */ 58 private $controller; 59 60 /** 61 * Name of the action method in the controller class 62 * 63 * Set by {@link recognize_route()} 64 * @var string 65 */ 66 private $action; 67 68 /** 69 * Value of :id parsed from URL then forced to lower case 70 * 71 * Set by {@link recognize_route()} 72 * @var string 73 */ 74 private $id; 75 76 /** 77 * Path to add to other filesystem paths 78 * 79 * Set by {@link recognize_route()} 80 * @var string 81 */ 82 private $added_path = ''; 83 84 /** 85 * Parameters for the action routine 86 * 87 * Set by {@link recognize_route()}, passed as arguments to the 88 * controller's action routine. 89 * @var string[] 90 */ 91 private $action_params = array(); 92 93 /** 94 * Filesystem path to ../app/controllers/ directory 95 * 96 * Set by {@link recognize_route()} 97 * @var string 98 */ 99 private $controllers_path; 100 101 /** 102 * Filesystem path to ../app/helpers/<i>extras</i> directory 103 * 104 * Set by {@link recognize_route()}, {@link set_paths()} 105 * @var string 106 */ 107 private $helpers_path; 108 109 /** 110 * Filesystem path to ../app/helpers/ directory 111 * 112 * Set by {@link recognize_route()} 113 * @var string 114 */ 115 private $helpers_base_path; 116 117 /** 118 * Filesystem path to ../app/views/layouts/<i>extras</i> directory 119 * 120 * Set by {@link recognize_route()}, {@link set_paths()} 121 * @var string 122 */ 123 private $layouts_path; 124 125 /** 126 * Filesystem path to ../app/views/layouts/ directory 127 * 128 * Set by {@link recognize_route()} 129 * @var string 130 */ 131 private $layouts_base_path; 132 133 /** 134 * User's URL in components 135 * 136 * Contains user's URL stripped of TRAX_URL_PREFIX and leading 137 * and trailing slashes, then exploded into an array on slash 138 * boundaries. 139 * @var string[] 140 */ 141 private $url_path; 142 143 /** 144 * Filesystem path to the controllername_helper.php file 145 * 146 * Set by {@link recognize_route()} 147 * @var string 148 */ 149 private $helper_file; 150 151 /** 152 * Filesystem path to application.php file 153 * 154 * Set by {@link recognize_route()} 155 * @see $controller_file 156 * @var string 157 */ 158 private $application_controller_file; 159 160 /** 161 * Filesystem path to application_helper.php file 162 * 163 * Set by {@link recognize_route()} 164 * @var string 165 */ 166 private $application_helper_file; 167 168 /** 169 * URL recognized, paths resoved, controller file found 170 * 171 * Set by {@link recognize_route()} 172 * @var boolean 173 */ 174 private $loaded = false; 175 176 /** 177 * Whether a Router object was loaded 178 * 179 * @var boolean 180 * <ul> 181 * <li>true => $router points to the Router object</li> 182 * <li>false => no Router object exists</li> 183 * </ul> 184 * @todo <b>FIXME:</b> No declaration of $router so no place to hang 185 * its documentation. 186 */ 187 private $router_loaded = false; 188 189 /** 190 * List of additional helper files for this controller object 191 * 192 * Set by {@link add_helper()} 193 * @var string[] 194 */ 195 private $helpers = array(); 196 197 /** 198 * List of filters to execute before calling action method 199 * 200 * Set by {@link add_before_filters() 201 * @var string[] 202 */ 203 private $before_filters = array(); 204 205 /** 206 * List of filters to execute after calling action method 207 * 208 * Set by {@link add_after_filters() 209 * @var string[] 210 */ 211 private $after_filters = array(); 212 213 /** 214 * @todo Document this attribute 215 */ 216 private $render_performed = false; 217 218 /** 219 * @todo Document this attribute 220 */ 221 private $action_called = false; 222 223 /** 224 * @todo Document this attribute 225 */ 226 protected $before_filter = null; 227 228 /** 229 * @todo Document this attribute 230 */ 231 protected $after_filter = null; 232 233 /** 234 * Filesystem path to the PHP program file for this controller 235 * 236 * Set by {@link recognize_route()} 237 * @see $application_controller_file 238 * @var string 239 */ 240 public $controller_file; 241 242 /** 243 * Filesystem path to the view file selected for this action 244 * 245 * Set by {@link process_route() 246 * @var string 247 */ 248 public $view_file; 249 250 /** 251 * Filesystem path to the ../app/views/ directory 252 * 253 * Set by {@link recognize_route()} 254 * @var string 255 */ 256 public $views_path; 257 258 /** 259 * Class name of the controller 260 * 261 * Set by {@link recognize_route()}. 262 * Derived from contents of {@link $controller}. 263 * @var string 264 */ 265 public $controller_class; 266 267 /** 268 * Instance of the controller class 269 * 270 * Set by {@link process_route()} 271 * @var object 272 */ 273 public $controller_object; 274 275 /** 276 * @todo Document this attribute 277 * @todo <b>FIXME:</b> Not referenced in this class - is it used 278 * by subclasses? If so, for what? 279 * @var string 280 */ 281 public $asset_host = null; 282 283 /** 284 * Render controllers layout 285 * 286 * Can be overridden in the child controller to false 287 * @var boolean 288 */ 289 public $render_layout = true; 290 291 /** 292 * Whether to keep flash message after displaying it 293 * @var boolean 294 */ 295 public $keep_flash = false; 296 297 /** 298 * Build a Router object and load routes from config/route.php 299 * @uses load_router() 300 */ 301 function __construct() { 302 if(!isset($this->router) || !is_object($this->router)) { 303 $this->load_router(); 304 } 305 } 306 307 /** 308 * @todo Document this method 309 * @uses add_after_filter() 310 * @uses add_before_filter() 311 * @uses add_helper() 312 */ 313 function __set($key, $value) { 314 //error_log("__set($key, $value)"); 315 if($key == "before_filter") { 316 $this->add_before_filter($value); 317 } elseif($key == "after_filter") { 318 $this->add_after_filter($value); 319 } elseif($key == "helper") { 320 $this->add_helper($value); 321 } elseif($key == "render_text") { 322 $this->render_text($value); 323 } elseif($key == "redirect_to") { 324 $this->redirect_to($value); 325 } else { 326 $this->$key = $value; 327 } 328 } 329 330 /** 331 * @todo Document this method 332 * Implement before_filter(), after_filter(), helper() 333 */ 334 function __call($method_name, $parameters) { 335 if(method_exists($this, $method_name)) { 336 # If the method exists, just call it 337 $result = call_user_func(array($this, $method_name), $parameters); 338 } else { 339 if($method_name == "before_filter") { 340 $result = call_user_func(array($this, 'add_before_filter'), $parameters); 341 } elseif($method_name == "after_filter") { 342 $result = call_user_func(array($this, 'add_after_filter'), $parameters); 343 } elseif($method_name == "helper") { 344 $result = call_user_func(array($this, 'add_helper'), $parameters); 345 } 346 } 347 return $result; 348 } 349 350 /** 351 * Load routes from configuration file config/routes.php 352 * 353 * Routes are loaded by requiring {@link routes.php} from the 354 * configuration directory. The file routes.php contains 355 * statements of the form "$router->connect(path,params);" where 356 * (path,params) describes the route being added by the 357 * statement. Route syntax is described in 358 * {@tutorial PHPonTrax/Router.cls the Router class tutorial}. 359 * 360 * @uses Router 361 * @uses $router 362 * @uses $router_loaded 363 */ 364 function load_router() { 365 $this->router_loaded = false; 366 $router = new Router(); 367 368 // Load the routes. 369 require(Trax::$config_path."/routes.php"); 370 $this->router = $router; 371 if(is_object($this->router)) { 372 $this->router_loaded = true; 373 } 374 } 375 376 /** 377 * Convert URL to controller, action and id 378 * 379 * Parse the URL in 380 * {@link 381 * http://www.php.net/manual/en/reserved.variables.php#reserved.variables.server $_SERVER}['REDIRECT_URL'] 382 * into elements. 383 * Compute filesystem paths to the various components used by the 384 * URL and store the paths in object private variables. 385 * Verify that the controller exists. 386 * 387 * @uses load_router() 388 * @uses $action 389 * @uses $action_params 390 * @uses $application_controller_file 391 * @uses $controller 392 * @uses $controller_class 393 * @uses $controller_file 394 * @uses $controllers_path 395 * @uses $helper_file 396 * @uses $helpers_path 397 * @uses $id 398 * @uses $layouts_path 399 * @uses $loaded 400 * @uses $router 401 * @uses $router_loaded 402 * @uses set_paths() 403 * @uses $url_path 404 * @uses $views_path 405 * @return boolean 406 * <ul> 407 * <li>true => route recognized, controller found.</li> 408 * <li>false => failed, route not recognized.</li> 409 * </ul> 410 */ 411 function recognize_route() { 412 if(!$this->router_loaded) { 413 $this->load_router(); 414 } 415 416 # current url 417 if(isset($_SERVER['REDIRECT_URL'])) { 418 $browser_url = $_SERVER['REDIRECT_URL']; 419 } else { 420 $browser_url = $_SERVER['REQUEST_URI']; 421 } 422 #if(strstr($_SERVER['REQUEST_URI'], "?")) 423 # $browser_url = substr($_SERVER['REQUEST_URI'], 0, strpos($_SERVER['REQUEST_URI'], "?")); 424 #else 425 # $browser_url = $_SERVER['REQUEST_URI']; 426 427 //error_log('browser url='.$browser_url); 428 # strip off url prefix, if any 429 if(!is_null(Trax::$url_prefix)) { 430 $browser_url = str_replace(Trax::$url_prefix, "", $browser_url); 431 } 432 433 # strip leading slash 434 // FIXME: Do we know for sure that the 435 // initial '/' will be there? 436 $browser_url = substr($browser_url,1); 437 438 # strip trailing slash (if any) 439 if(substr($browser_url, -1) == "/") { 440 $browser_url = substr($browser_url, 0, -1); 441 } 442 443 if($browser_url) { 444 $this->url_path = explode("/", $browser_url); 445 } else { 446 $this->url_path = array(); 447 } 448 449 if($this->router->routes_count > 0) { 450 $this->controllers_path = Trax::$controllers_path; 451 $this->helpers_path = $this->helpers_base_path = Trax::$helpers_path; 452 $this->application_controller_file = $this->controllers_path . "/application.php"; 453 $this->application_helper_file = $this->helpers_path . "/application_helper.php"; 454 $this->layouts_path = Trax::$layouts_path; 455 $this->views_path = Trax::$views_path; 456 457 $route = $this->router->find_route($browser_url); 458 459 // find_route() returns an array if it finds a path that 460 // matches the URL, null if no match found 461 if(is_array($route)) { 462 463 // Matching route found. Try to get 464 // controller and action from route and URL 465 $this->set_paths(); 466 $route_path = explode("/",$route['path']); 467 $route_params = $route['params']; 468 469 // Find the controller from the route and URL 470 if(is_array($route_params) 471 && array_key_exists(":controller",$route_params)) { 472 473 // ':controller' in route params overrides URL 474 $this->controller = $route_params[":controller"]; 475 } elseif(is_array($route_path) 476 && in_array(":controller",$route_path) 477 && (count($this->url_path)>0)) { 478 479 // Set controller from URL if that field exists 480 $this->controller = strtolower($this->url_path[array_search(":controller", $route_path)]); 481 } 482 //error_log('controller='.$this->controller); 483 484 // Find the action from the route and URL 485 if(is_array($route_params) 486 && array_key_exists(":action",$route_params)) { 487 488 // ':action' in route params overrides URL 489 $this->action = $route_params[':action']; 490 } elseif(is_array($route_path) 491 && in_array(":action",$route_path) 492 && array_key_exists(@array_search(":action", 493 $route_path), 494 $this->url_path)) { 495 496 // Get action from URL if that field exists 497 $this->action = strtolower($this->url_path[@array_search(":action", $route_path)]); 498 } 499 //error_log('action='.$this->action); 500 // FIXME: RoR uses :name as a keyword parameter, id 501 // is not treated as a special case. 502 // Do we want to do the same? 503 if(@in_array(":id",$route_path) 504 && array_key_exists(@array_search(":id", $route_path), 505 $this->url_path)) { 506 $this->id = strtolower($this->url_path[@array_search(":id", $route_path)]); 507 // Parameters for the action routine. 508 // FIXME: make more general than just id 509 if($this->id != "") { 510 $this->action_params['id'] = $this->id; 511 } 512 // For historical reasons, continue to pass id 513 // in $_REQUEST 514 if($this->id != "") { 515 $_REQUEST['id'] = $this->id; 516 } 517 } 518 $this->views_path .= "/" . $this->controller; 519 $this->controller_file = $this->controllers_path . "/" . $this->controller . "_controller.php"; 520 $this->controller_class = Inflector::camelize($this->controller) . "Controller"; 521 $this->helper_file = $this->helpers_path . "/" . $this->controller . "_helper.php"; 522 } 523 } 524 525 if(file_exists($this->controller_file)) { 526 $this->loaded = true; 527 return true; 528 } else { 529 $this->loaded = false; 530 return false; 531 } 532 } 533 534 /** 535 * Parse URL, extract controller and action and execute them 536 * 537 * @uses $action 538 * @uses $action_params 539 * @uses $application_controller_file 540 * @uses $application_helper_file 541 * @uses $controller 542 * @uses $controller_class 543 * @uses $controller_file 544 * @uses $controller_object 545 * @uses determine_layout() 546 * @uses execute_after_filters() 547 * @uses $helpers 548 * @uses $helper_file 549 * @uses $helpers_base_path 550 * @uses $keep_flash 551 * @uses $loaded 552 * @uses recognize_route() 553 * @uses raise() 554 * @uses ScaffoldController 555 * @uses Session::unset_var() 556 * @uses $view_file 557 * @uses $views_path 558 * @return boolean true 559 */ 560 function process_route() { 561 562 # First try to load the routes and setup the paths to everything 563 if(!$this->loaded) { 564 if(!$this->recognize_route()) { 565 $this->raise("Failed to load any defined routes", 566 "Controller ".$this->controller." not found", 567 "404"); 568 } 569 } 570 //error_log('process_route(): controller="'.$this->controller 571 // .'" action="'.$this->action.'" id="'.$this->id.'"'); 572 573 # Include main application controller file 574 if(file_exists($this->application_controller_file)) { 575 include_once($this->application_controller_file); 576 } 577 578 # If controller is loaded then start processing 579 if($this->loaded) { 580 581 include_once($this->controller_file); 582 if(class_exists($this->controller_class, false)) { 583 584 $class = $this->controller_class; 585 $this->controller_object = new $class(); 586 587 if(is_object($this->controller_object)) { 588 589 $this->controller_object->controller = $this->controller; 590 $this->controller_object->action = $this->action; 591 $this->controller_object->controller_path = "$this->added_path/$this->controller"; 592 $this->controller_object->views_path = $this->views_path; 593 $this->controller_object->layouts_path = $this->layouts_path; 594 Trax::$current_controller_path = "$this->added_path/$this->controller"; 595 Trax::$current_controller_name = $this->controller; 596 Trax::$current_action_name = $this->action; 597 Trax::$current_controller_object =& $this->controller_object; 598 # Which layout should we use? 599 $layout_file = $this->controller_object->determine_layout(); 600 //error_log('using layout_file "'.$layout_file.'"'); 601 # Check if there is any defined scaffolding to load 602 if(isset($this->controller_object->scaffold)) { 603 $scaffold = $this->controller_object->scaffold; 604 if(file_exists(TRAX_LIB_ROOT."/scaffold_controller.php")) { 605 include_once (TRAX_LIB_ROOT."/scaffold_controller.php"); 606 $this->controller_object = new ScaffoldController($scaffold); 607 Trax::$current_controller_object =& $this->controller_object; 608 $render_options['scaffold'] = true; 609 if(!file_exists($layout_file)) { 610 # the generic scaffold layout 611 $layout_file = TRAX_LIB_ROOT . "/templates/scaffolds/layout.phtml"; 612 } 613 } 614 } 615 } 616 } 617 618 # Include main application helper file 619 if(file_exists($this->application_helper_file)) { 620 include_once($this->application_helper_file); 621 } 622 623 # Include helper file for this controller 624 if(file_exists($this->helper_file)) { 625 include_once($this->helper_file); 626 } 627 628 if(is_object($this->controller_object)) { 629 630 # Include any extra helper files defined in this controller 631 if(count($this->controller_object->helpers) > 0) { 632 foreach($this->controller_object->helpers as $helper) { 633 if(strstr($helper, "/")) { 634 $file = substr(strrchr($helper, "/"), 1); 635 $path = substr($helper, 0, strripos($helper, "/")); 636 $helper_path_with_file = $this->helpers_base_path."/".$path."/".$file."_helper.php"; 637 } else { 638 $helper_path_with_file = $this->helpers_base_path."/".$helper."_helper.php"; 639 } 640 641 if(file_exists($helper_path_with_file)) { 642 # Include the helper file 643 include($helper_path_with_file); 644 } 645 } 646 } 647 648 # Suppress output 649 ob_start(); 650 //error_log('started capturing HTML'); 651 652 # Call the controller method based on the URL 653 if($this->controller_object->execute_before_filters()) { 654 655 if(method_exists($this->controller_object, $this->action)) { 656 //error_log('method '.$this->action.' exists, calling it'); 657 $action = $this->action; 658 //error_log('calling action routine ' 659 // . get_class($this->controller_object) 660 // .'::'.$action.'() with params ' 661 // .var_export($this->action_params,true)); 662 $this->controller_object->$action($this->action_params); 663 } elseif(file_exists($this->views_path . "/" . $this->action . "." . Trax::$views_extension)) { 664 //error_log('views file "'.$this->action.'"'); 665 $action = $this->action; 666 } elseif(method_exists($this->controller_object, "index")) { 667 //error_log('calling action routine ' 668 // . get_class($this->controller_object) 669 // .'::index() with params ' 670 // .var_export($this->action_params,true)); 671 $action = "index"; 672 $this->controller_object->index($this->action_params); 673 } else { 674 //error_log('no action'); 675 $this->raise("No action responded to ".$this->action, "Unknown action", "404"); 676 } 677 $this->controller_object->execute_after_filters(); 678 679 $this->controller_object->action_called = true; 680 681 # Find out if there was a redirect to some other page 682 if(isset($this->controller_object->redirect_to) 683 && $this->controller_object->redirect_to != '') { 684 $this->redirect_to($this->controller_object->redirect_to); 685 # execution will end here redirecting to new page 686 } 687 688 # If render_text was defined as a string render it 689 if(isset($this->controller_object->render_text) 690 && $this->controller_object->render_text != "") { 691 $this->render_text($this->controller_object->render_text); 692 # execution will end here rendering only the text no layout 693 } 694 695 # If defined string render_action use that instead 696 if(isset($this->controller_object->render_action) 697 && $this->controller_object->render_action != '') { 698 $action = $this->controller_object->render_action; 699 } 700 701 # Render the action / view 702 if(!$this->controller_object->render_action($action, 703 isset($render_options) ? $render_options : null )) { 704 $this->raise("No view file found $action ($this->view_file).", "Unknown view", "404"); 705 } 706 # Grab all the html from the view to put into the layout 707 $content_for_layout = ob_get_contents(); 708 ob_end_clean(); 709 //error_log("captured ".strlen($content_for_layout)." bytes\n"); 710 if(isset($this->controller_object->render_layout) 711 && ($this->controller_object->render_layout !== false) 712 && $layout_file) { 713 $locals['content_for_layout'] = $content_for_layout; 714 # render the layout 715 //error_log("rendering layout: $layout_file"); 716 if(!$this->controller_object->render_file($layout_file, false, $locals)) { 717 # No layout template so just echo out whatever is in $content_for_layout 718 //echo "HERE"; 719 echo $content_for_layout; 720 } 721 } else { 722 # Can't find any layout so throw an exception 723 # $this->raise("No layout file found.", "Unknown layout", "404"); 724 # No layout template so just echo out whatever is in $content_for_layout 725 echo $content_for_layout; 726 } 727 } 728 } else { 729 $this->raise("Failed to instantiate controller object \"".$this->controller."\".", "ActionController Error", "500"); 730 } 731 } else { 732 $this->raise("No controller found.", "Unknown controller", "404"); 733 } 734 735 // error_log('keep flash='.var_export($this->keep_flash,true)); 736 if(!$this->keep_flash) { 737 # Nuke the flash 738 Session::unset_var('flash'); 739 } 740 741 return true; 742 } // function process_route() 743 744 /** 745 * Extend the search path for components 746 * 747 * On entry, $url_path is set according to the browser's URL and 748 * $controllers_path has been set according to the configuration 749 * in {@link environment.php config/environment.php} . Examine 750 * the $controllers_path directory for files or directories that 751 * match any component of the URL. If one is found, add that 752 * component to all paths. Replace the contents of $url_path 753 * with the list of URL components that did NOT match any files 754 * or directories. 755 * @uses $added_path 756 * @uses $controllers_path 757 * @uses $helpers_path 758 * @uses $layouts_path 759 * @uses $views_path 760 * @uses $url_path 761 * @todo <b>FIXME:</b> Creating a file or directory in 762 * app/controllers with the same name as a controller, action or 763 * other URL element will hijack the browser! 764 */ 765 function set_paths() { 766 if(is_array($this->url_path)) { 767 foreach($this->url_path as $path) { 768 if(file_exists($this->controllers_path . "/$path")) { 769 $extra_path[] = $path; 770 } else { 771 $new_path[] = $path; 772 } 773 } 774 if(isset($extra_path) && is_array($extra_path)) { 775 $extra_path = implode("/", $extra_path); 776 $this->added_path = $extra_path; 777 $this->controllers_path .= "/$extra_path"; 778 $this->helpers_path .= "/$extra_path"; 779 $this->views_path .= "/$extra_path"; 780 $this->layouts_path .= "/$extra_path"; 781 } 782 if(isset($new_path) 783 && is_array($new_path)) { 784 $this->url_path = $new_path; 785 } 786 } 787 } 788 789 /** 790 * Execute the before filters 791 * @uses $before_filters 792 */ 793 function execute_before_filters() { 794 $return = true; 795 if(count($this->before_filters) > 0) { 796 foreach($this->before_filters as $filter_function) { 797 if(method_exists($this, $filter_function)) { 798 if(false === $this->$filter_function()) { 799 //error_log("execute_before_filters(): returning false"); 800 $return = false; 801 } 802 } 803 } 804 } 805 return $return; 806 } 807 808 /** 809 * Append a before filter to the filter chain 810 * 811 * @param mixed $filter_function_name String with the name of 812 * one filter function, or array of strings with the names of 813 * several filter functions. 814 * @uses $before_filters 815 */ 816 function add_before_filter($filter_function_name) { 817 //error_log("adding before filter: $filter_function_name"); 818 if(is_string($filter_function_name) && !empty($filter_function_name)) { 819 if(!in_array($filter_function_name, $this->before_filters)) { 820 $this->before_filters[] = $filter_function_name; 821 } 822 } elseif(is_array($filter_function_name)) { 823 if(count($this->before_filters) > 0) { 824 $this->before_filters = array_merge($this->before_filters, $filter_function_name); 825 } else { 826 $this->before_filters = $filter_function_name; 827 } 828 } 829 } 830 831 /** 832 * Execute the after filters 833 * @uses $after_filters 834 */ 835 function execute_after_filters() { 836 if(count($this->after_filters) > 0) { 837 foreach($this->after_filters as $filter_function) { 838 if(method_exists($this, $filter_function)) { 839 $this->$filter_function(); 840 } 841 } 842 } 843 } 844 845 846 /** 847 * Append an after filter to the filter chain 848 * 849 * @param mixed $filter_function_name String with the name of 850 * one filter function, or array of strings with the names of 851 * several filter functions. 852 * @uses $after_filters 853 */ 854 function add_after_filter($filter_function_name) { 855 if(is_string($filter_function_name) && !empty($filter_function_name)) { 856 if(!in_array($filter_function_name, $this->after_filters)) { 857 $this->after_filters[] = $filter_function_name; 858 } 859 } elseif(is_array($filter_function_name)) { 860 if(count($this->after_filters) > 0) { 861 $this->after_filters = array_merge($this->after_filters, $filter_function_name); 862 } else { 863 $this->after_filters = $filter_function_name; 864 } 865 } 866 } 867 868 /** 869 * Add a helper to the list of helpers used by a controller 870 * object 871 * 872 * @param $helper_name string Name of a helper to add to the list 873 * @uses $helpers 874 * @uses $controller_object 875 */ 876 function add_helper($helper_name) { 877 if(!in_array($helper_name, $this->helpers)) { 878 $this->helpers[] = $helper_name; 879 } 880 } 881 882 /** 883 * 884 * Renders the content that will be returned to the browser as the response body. 885 * 886 */ 887 function render($options = array(), $locals = array(), $return_as_string = false) { 888 889 if($this->render_performed && !$this->action_called) { 890 return true; 891 } 892 893 if($return_as_string) { 894 # start to buffer output 895 ob_start(); 896 } 897 898 if(is_string($options)) { 899 $this->render_file($options, true, $locals); 900 } elseif(is_array($options)) { 901 $options['locals'] = $options['locals'] ? $options['locals'] : array(); 902 $options['use_full_path'] = !$options['use_full_path'] ? true : $options['use_full_path']; 903 904 if($options['text']) { 905 $this->render_text($options['text']); 906 } else { 907 if($options['action']) { 908 $this->render_action($options['action'], $options); 909 } elseif($options['file']) { 910 $this->render_file($options['file'], $options['use_full_path'], $options['locals']); 911 } elseif($options['partial']) { 912 $this->render_partial($options['partial'], $options); 913 } elseif($options['nothing']) { 914 # Safari doesn't pass the headers of the return if the response is zero length 915 $this->render_text(" "); 916 } 917 } 918 } 919 920 $this->render_performed = true; 921 922 if($return_as_string) { 923 $result = ob_get_contents(); 924 ob_end_clean(); 925 return $result; 926 } 927 } 928 929 /** 930 * 931 * Rendering of text is usually used for tests or for rendering prepared content. 932 * By default, text rendering is not done within the active layout. 933 * 934 * # Renders the clear text "hello world" 935 * render(array("text" => "hello world!")) 936 * 937 * # Renders the clear text "Explosion!" 938 * render(array("text" => "Explosion!")) 939 * 940 * # Renders the clear text "Hi there!" within the current active layout (if one exists) 941 * render(array("text" => "Explosion!", "layout" => true)) 942 * 943 * # Renders the clear text "Hi there!" within the layout 944 * # placed in "app/views/layouts/special.phtml" 945 * render(array("text" => "Explosion!", "layout" => "special")) 946 * 947 */ 948 function render_text($text, $options = array()) { 949 if($options['layout']) { 950 $locals['content_for_layout'] = $text; 951 $layout = $this->determine_layout(); 952 $this->render_file($layout, false, $locals); 953 } else { 954 echo $text; 955 } 956 exit; 957 } 958 959 /** 960 * 961 * Action rendering is the most common form and the type used automatically by 962 * Action Controller when nothing else is specified. By default, actions are 963 * rendered within the current layout (if one exists). 964 * 965 * # Renders the template for the action "goal" within the current controller 966 * render(array("action" => "goal")) 967 * 968 * # Renders the template for the action "short_goal" within the current controller, 969 * # but without the current active layout 970 * render(array("action" => "short_goal", "layout" => false)) 971 * 972 * # Renders the template for the action "long_goal" within the current controller, 973 * # but with a custom layout 974 * render(array("action" => "long_goal", "layout" => "spectacular")) 975 * 976 */ 977 function render_action($action, $options = array()) { 978 if($this->render_performed) { 979 return true; 980 } 981 if($options['layout']) { 982 $this->layout = $options['layout']; 983 } 984 if($options['scaffold']) { 985 $this->view_file = TRAX_LIB_ROOT."/templates/scaffolds/".$action.".phtml"; 986 } else { 987 $this->view_file = $this->views_path . "/" . $action . "." . Trax::$views_extension; 988 } 989 //error_log(get_class($this)." - render_action() view_file: $this->view_file"); 990 return $this->render_file($this->view_file); 991 } 992 993 /** 994 * 995 * Renders according to the same rules as render, but returns the result in a string 996 * instead of sending it as the response body to the browser. 997 * 998 */ 999 function render_to_string($options = array(), $locals = array()) { 1000 return $this->render($options, $locals, true); 1001 } 1002 1003 /** 1004 * 1005 * File rendering works just like action rendering except that it takes a filesystem path. 1006 * By default, the path is assumed to be absolute, and the current layout is not applied. 1007 * 1008 * # Renders the template located at the absolute filesystem path 1009 * render(array("file" => "/path/to/some/template.phtml")) 1010 * render(array("file" => "c:/path/to/some/template.phtml")) 1011 * 1012 * # Renders a template within the current layout 1013 * render(array("file" => "/path/to/some/template.rhtml", "layout" => true)) 1014 * render(array("file" => "c:/path/to/some/template.rhtml", "layout" => true)) 1015 * 1016 * # Renders a template relative to app/views 1017 * render(array("file" => "some/template", "use_full_path" => true)) 1018 */ 1019 function render_file($path, $use_full_path = false, $locals = array()) { 1020 if($this->render_performed && !$this->action_called) { 1021 return true; 1022 } 1023 1024 # Renders a template relative to app/views 1025 if($use_full_path) { 1026 $path = $this->views_path."/".$path.".".Trax::$views_extension; 1027 } 1028 1029 //error_log("render_file() path:$path"); 1030 if(file_exists($path)) { 1031 1032 # Pull all the class vars out and turn them from $this->var to $var 1033 if(is_object($this)) { 1034 $controller_locals = get_object_vars($this); 1035 } 1036 if(is_array($controller_locals)) { 1037 $locals = array_merge($controller_locals, $locals); 1038 } 1039 if(count($locals)) { 1040 foreach($locals as $tmp_key => $tmp_value) { 1041 ${$tmp_key} = $tmp_value; 1042 } 1043 unset($tmp_key); 1044 unset($tmp_value); 1045 } 1046 include($path); 1047 $this->render_performed = true; 1048 return true; 1049 } 1050 return false; 1051 } 1052 1053 /** 1054 * Rendering partials 1055 * 1056 * <p>Partial rendering is most commonly used together with Ajax 1057 * calls that only update one or a few elements on a page without 1058 * reloading. Rendering of partials from the controller makes it 1059 * possible to use the same partial template in both the 1060 * full-page rendering (by calling it from within the template) 1061 * and when sub-page updates happen (from the controller action 1062 * responding to Ajax calls). By default, the current layout is 1063 * not used.</p> 1064 * 1065 * <ul> 1066 * <li><samp>render_partial("win");</samp><br> 1067 * Renders the partial 1068 * located at app/views/controller/_win.phtml</li> 1069 * 1070 * <li><samp>render_partial("win", 1071 * array("locals" => array("name" => "david")));</samp><br> 1072 * Renders the same partial but also makes a local variable 1073 * available to it</li> 1074 * 1075 * <li><samp>render_partial("win", 1076 * array("collection" => array(...)));</samp><br> 1077 * Renders a collection of the same partial by making each 1078 * element of the collection available through the local variable 1079 * "win" as it builds the complete response </li> 1080 * 1081 * <li><samp>render_partial("win", array("collection" => $wins, 1082 * "spacer_template" => "win_divider"));</samp><br> 1083 * Renders the same collection of partials, but also renders 1084 * the win_divider partial in between each win partial.</li> 1085 * </ul> 1086 * @param string $path Path to file containing partial view 1087 * @param string[] $options Options array 1088 */ 1089 function render_partial($path, $options = array()) { 1090 if(strstr($path, "/")) { 1091 $file = substr(strrchr($path, "/"), 1); 1092 $path = substr($path, 0, strripos($path, "/")); 1093 $file_with_path = Trax::$views_path."/".$path."/_".$file.".".Trax::$views_extension; 1094 } else { 1095 $file = $path; 1096 $file_with_path = $this->views_path."/_".$file.".".Trax::$views_extension; 1097 } 1098 1099 if(file_exists($file_with_path)) { 1100 1101 if(array_key_exists("spacer_template", $options)) { 1102 $spacer_path = $options['spacer_template']; 1103 if(strstr($spacer_path, "/")) { 1104 $spacer_file = substr(strrchr($spacer_path, "/"), 1); 1105 $spacer_path = substr($spacer_path, 0, strripos($spacer_path, "/")); 1106 $spacer_file_with_file = Trax::$views_path."/".$spacer_path."/_".$spacer_file.".".Trax::$views_extension; 1107 } else { 1108 $spacer_file = $spacer_path; 1109 $spacer_file_with_file = $this->views_path."/_".$spacer_file.".".Trax::$views_extension; 1110 } 1111 if(file_exists($spacer_file_with_file)) { 1112 $add_spacer = true; 1113 } 1114 } 1115 1116 $locals = array_key_exists("locals", $options) ? $options['locals'] : array(); 1117 if(array_key_exists("collection", $options) && is_array($options['collection'])) { 1118 foreach($options['collection'] as $tmp_value) { 1119 ${$file."_counter"}++; 1120 $locals[$file] = $tmp_value; 1121 $locals[$file."_counter"] = ${$file."_counter"}; 1122 unset($tmp_value); 1123 $this->render_performed = false; 1124 $this->render_file($file_with_path, false, $locals); 1125 if($add_spacer && (${$file."_counter"} < count($options['collection']))) { 1126 $this->render_performed = false; 1127 $this->render_file($spacer_file_with_file, false, $locals); 1128 } 1129 } 1130 $this->render_performed = true; 1131 } else { 1132 $this->render_file($file_with_path, false, $locals); 1133 } 1134 } 1135 } 1136 1137 /** 1138 * Select a layout file based on the controller object 1139 * 1140 * @uses $controller_object 1141 * @uses $layouts_base_path 1142 * @uses $layouts_path 1143 * @return mixed Layout file or null if none 1144 * @todo <b>FIXME:</b> Should this method be private? 1145 */ 1146 function determine_layout($full_path = true) { 1147 1148 // If the controller defines $layout and sets it 1149 // to NULL, that indicates it doesn't want a layout 1150 if(isset($this->layout) && is_null($this->layout)) { 1151 //error_log('controller->layout absent'); 1152 return null; 1153 } 1154 # $layout will be the layout defined in the current controller 1155 # or try to use the controller name for the layout 1156 $layout = (isset($this->layout) 1157 && $this->layout != '') 1158 ? $this->layout : $this->controller; 1159 1160 # Check if a method has been defined to determine the layout at runtime 1161 if(method_exists($this, $layout)) { 1162 $layout = $this->$layout(); 1163 } 1164 1165 # Default settings 1166 $layouts_base_path = Trax::$layouts_path; 1167 $default_layout_file = $layouts_base_path . "/application." . Trax::$views_extension; 1168 1169 if(!$full_path && $layout) { 1170 return $layout; 1171 } elseif($layout) { 1172 # Is this layout for from a different controller 1173 if(strstr($layout, "/")) { 1174 $file = substr(strrchr($layout, "/"), 1); 1175 $path = substr($layout, 0, strripos($layout, "/")); 1176 $layout = $layouts_base_path."/".$path."/".$file.".".Trax::$views_extension; 1177 } elseif(file_exists($this->layouts_path."/".$layout.".".Trax::$views_extension)) { 1178 # Is there a layout for the current controller 1179 $layout = $this->layouts_path."/".$layout.".".Trax::$views_extension; 1180 } else { 1181 $layout = $layouts_base_path."/".$layout.".".Trax::$views_extension; 1182 } 1183 if(file_exists($layout)) { 1184 $layout_file = $layout; 1185 } 1186 } 1187 1188 # No defined layout found so just use the default layout 1189 # app/views/layouts/application.phtml 1190 if(!isset($layout_file)) { 1191 $layout_file = $default_layout_file; 1192 } 1193 return $layout_file; 1194 } 1195 1196 /** 1197 * Redirect the browser to a specified target 1198 * 1199 * Redirect the browser to the target specified in $options. This 1200 * parameter can take one of three forms: 1201 * <ul> 1202 * <li>Array: The URL will be generated by calling 1203 * {@link url_for()} with the options.</li> 1204 * <li>String starting with a protocol:// (like http://): Is 1205 * passed straight through as the target for redirection.</li> 1206 * <li>String not containing a protocol: The current protocol 1207 * and host is prepended to the string.</li> 1208 * <li>back: Back to the page that issued the request. Useful 1209 * for forms that are triggered from multiple 1210 * places. Short-hand for redirect_to(request.env["HTTP_REFERER"]) 1211 * </ul> 1212 * 1213 * Examples: 1214 * <ul> 1215 * <li>redirect_to(array(":action" => "show", ":id" => 5))</li> 1216 * <li>redirect_to("http://www.rubyonrails.org")</li> 1217 * <li>redirect_to("/images/screenshot.jpg")</li> 1218 * <li>redirect_to("back")</li> 1219 * </ul> 1220 * 1221 * @param mixed $options array or string url 1222 * @todo <b>FIXME:</b> Make header configurable 1223 */ 1224 function redirect_to($options = null) { 1225 if($options == "back") { 1226 $url = $_SERVER["HTTP_REFERER"]; 1227 } else { 1228 $url = url_for($options); 1229 } 1230 1231 if(headers_sent()) { 1232 echo "<html><head><META HTTP-EQUIV=\"REFRESH\" CONTENT=\"0; URL=".$url."\"></head></html>"; 1233 } else { 1234 header("Location: ".$url); 1235 } 1236 1237 exit; 1238 } 1239 1240 /** 1241 * Raise an ActionControllerError exception 1242 * 1243 * @param string $error_message Error message 1244 * @param string $error_heading Error heading 1245 * @param string $error_code Error code 1246 * @throws ActionControllerError 1247 */ 1248 function raise($error_message, $error_heading, $error_code = "404") { 1249 throw new ActionControllerError("Error Message: ".$error_message, $error_heading, $error_code); 1250 } 1251 1252 /** 1253 * Generate an HTML page describing an error 1254 */ 1255 function process_with_exception(&$exception) { 1256 $error_code = $exception->error_code; 1257 $error_heading = $exception->error_heading; 1258 $error_message = $exception->error_message; 1259 $trace = $exception->getTraceAsString(); 1260 header('HTTP/1.0 {$error_code} {$error_heading}'); 1261 header('status: {$error_code} {$error_heading}'); 1262 # check for user's layout for errors 1263 if(TRAX_ENV == "development" && file_exists(Trax::$layouts_path."/trax_error.".Trax::$views_extension)) { 1264 include(Trax::$layouts_path."/trax_error.".Trax::$views_extension); 1265 } elseif(TRAX_ENV == "development" && file_exists(TRAX_LIB_ROOT."/templates/error.phtml")) { 1266 # use default layout for errors 1267 include (TRAX_LIB_ROOT."/templates/error.phtml"); 1268 } elseif(TRAX_ENV == "development") { 1269 echo "<font face=\"verdana, arial, helvetica, sans-serif\">\n"; 1270 echo "<h1>$error_heading</h1>\n"; 1271 echo "<p>$error_message</p>\n"; 1272 if($trace) { 1273 echo "<pre style=\"background-color: #eee;padding:10px;font-size: 11px;\">"; 1274 echo "<code>$trace</code></pre>\n"; 1275 } 1276 echo "</font>\n"; 1277 } else { 1278 echo "<font face=\"verdana, arial, helvetica, sans-serif\">\n"; 1279 echo "<h2>Application Error</h2>Trax application failed to start properly"; 1280 echo "</font>\n"; 1281 } 1282 } 1283 1284 } 1285 1286 // -- set Emacs parameters -- 1287 // Local variables: 1288 // tab-width: 4 1289 // c-basic-offset: 4 1290 // c-hanging-comment-ender-p: nil 1291 // indent-tabs-mode: nil 1292 // End: 1293 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 20:04:38 2007 | par Balluche grâce à PHPXref 0.7 |