[ Index ]
 

Code source de PHPonTrax 2.6.6-svn

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/vendor/trax/ -> action_controller.php (source)

   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  ?>


Généré le : Sun Feb 25 20:04:38 2007 par Balluche grâce à PHPXref 0.7