Show
Ignore:
Timestamp:
03/13/06 21:10:15 (6 years ago)
Author:
haas
Message:

ActionController? doc done

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/trax/vendor/trax/action_controller.php

    r167 r174  
    3232 *  Action controller 
    3333 * 
    34  *  <p><b>Filters</b></p> 
     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> 
    3543 * 
    36  *  <p>Filters enable controllers to run shared pre and post 
    37  *  processing code for its actions. These filters can be used to do 
    38  *  authentication, caching, or auditing before the intended action is 
    39  *  performed. Or to do localization or output compression after the 
    40  *  action has been performed.</p> 
    41  * 
    42  *  <p>Filters have access to the request, response, and all the 
    43  *  instance variables set by other filters in the chain or by the 
    44  *  action (in the case of after filters). Additionally, it's possible 
    45  *  for a pre-processing <samp>before_filter</samp> to halt the processing 
    46  *  before the intended action is processed by returning false or 
    47  *  performing a redirect or render.  This is especially useful for 
    48  *  filters like authentication where you're not interested in 
    49  *  allowing the action to be  performed if the proper credentials are 
    50  *  not in order.</p> 
    51  * 
    52  *  <p><b>Filter inheritance</b></p> 
    53  * 
    54  *  <p>Controller inheritance hierarchies share filters downwards, but 
    55  *  subclasses can also add new filters without affecting the 
    56  *  superclass. For example:</p> 
    57  * 
    58  *  <pre> 
    59  *   class BankController extends ActionController 
    60  *   { 
    61  *     $this->before_filter = audit(); 
    62  * 
    63  *     private function audit() { 
    64  *       <i>record the action and parameters in an audit log</i> 
    65  *     } 
    66  *   } 
    67  * 
    68  *   class VaultController extends BankController 
    69  *   { 
    70  *     $this->before_filter = verify_credentials(); 
    71  * 
    72  *     private function verify_credentials() { 
    73  *       <i>make sure the user is allowed into the vault</i> 
    74  *     } 
    75  *   } 
    76  *  </pre> 
    77  * 
    78  *  <p>Now any actions performed on the BankController will have the 
    79  *  audit method called before. On the VaultController, first the 
    80  *  audit method is called, then the verify_credentials method. If the 
    81  *  audit method returns false, then verify_credentials and the 
    82  *  intended action are never called.</p> 
    83  * 
    84  *  <p><b>Filter types</b></p> 
    85  * 
    86  *  <p>A filter can take one of three forms: method reference 
    87  *  (symbol), external class, or inline method (proc). The first is the 
    88  *  most common and works by referencing a protected or private method 
    89  *  somewhere in the inheritance hierarchy of the controller by use of 
    90  *  a symbol. In the bank example above, both BankController and 
    91  *  VaultController use this form.</p> 
    92  * 
    93  *  <p>Using an external class makes for more easily reused generic 
    94  *  filters, such as output compression. External filter classes are 
    95  *  implemented by having a static +filter+ method on any class and 
    96  *  then passing this class to the filter method. Example:</p> 
    97  * 
    98  *  <pre> 
    99  *   class OutputCompressionFilter 
    100  *   { 
    101  *     static functionfilter(controller) { 
    102  *       controller.response.body = compress(controller.response.body) 
    103  *     } 
    104  *   } 
    105  * 
    106  *   class NewspaperController extends ActionController 
    107  *   { 
    108  *     $this->after_filter = OutputCompressionFilter; 
    109  *   } 
    110  *  </pre> 
    111  * 
    112  *  <p>The filter method is passed the controller instance and is 
    113  *  hence granted access to all aspects of the controller and can 
    114  *  manipulate them as it sees fit.</p> 
    115  * 
    116  *  <p>The inline method (using a proc) can be used to quickly do 
    117  *  something small that doesn't require a lot of explanation.  Or 
    118  *  just as a quick test. It works like this:</p> 
    119  * 
    120  *  <pre> 
    121  *   class WeblogController extends ActionController 
    122  *   { 
    123  *     before_filter { |controller| false if controller.params["stop_action"] } 
    124  *   } 
    125  *  </pre> 
    126  * 
    127  *  <p>As you can see, the block expects to be passed the controller 
    128  *  after it has assigned the request to the internal variables.  This 
    129  *  means that the block has access to both the request and response 
    130  *  objects complete with convenience methods for params, session, 
    131  *  template, and assigns. Note: The inline method doesn't strictly 
    132  *  have to be a block; any object that responds to call and returns 1 
    133  *  or -1 on arity will do (such as a Proc or an Method object).</p> 
    134  * 
    135  *  <p><b>Filter chain skipping</b></p> 
    136  * 
    137  *  <p>Some times its convenient to specify a filter chain in a superclass  
    138  *  that'll hold true for the majority of the subclasses, but not necessarily 
    139  *  all of them. The subclasses that behave in exception can then specify 
    140  *  which filters they would like to be relieved of. Examples</p> 
    141  * 
    142  *  <pre> 
    143  *   class ApplicationController extends ActionController 
    144  *   { 
    145  *     $this->before_filter = authenticate(); 
    146  *   } 
    147  * 
    148  *   class WeblogController extends ApplicationController 
    149  *   { 
    150  *      // will run the authenticate() filter 
    151  *   } 
    152  *  </pre> 
    153  * 
    154  *  <p><b>Filter conditions</b></p> 
    155  * 
    156  *  <p>Filters can be limited to run for only specific actions. This 
    157  *  can be expressed either by listing the actions to exclude or 
    158  *  the actions to include when executing the filter. Available 
    159  *  conditions are +:only+ or +:except+, both of which accept an 
    160  *  arbitrary number of method references. For example:</p> 
    161  * 
    162  *  <pre> 
    163  *   class Journal extends ActionController 
    164  *   { 
    165  *     // only require authentication if the current action is edit or delete 
    166  *     before_filter :authorize, :only => [ :edit, :delete ] 
    167  *     
    168  *     private function authorize() { 
    169  *      // redirect to login unless authenticated 
    170  *     } 
    171  *   } 
    172  *  </pre> 
    173  *  
    174  *  <p>When setting conditions on inline method (proc) filters the 
    175  *  condition must come first and be placed in parentheses.</p> 
    176  * 
    177  *  <pre> 
    178  *   class UserPreferences extends ActionController 
    179  *   { 
    180  *     before_filter(:except => :new) { ? some proc ... } 
    181  *  * ... 
    182  *   } 
    183  *  </pre> 
     44 *  For details see the 
     45 *  {@tutorial PHPonTrax/ActionController.cls class tutorial} 
    18446 */ 
    18547class ActionController { 
     
    20264 
    20365    /** 
    204      *  @todo Document this attribute 
     66     *  Value of :id parsed from URL then forced to lower case 
     67     * 
     68     *  Set by {@link recognize_route()} 
     69     *  @var string 
    20570     */ 
    20671    private $id; 
     
    22388 
    22489    /** 
     90     *  Filesystem path to ../app/helpers/<i>extras</i> directory 
     91     * 
     92     *  Set by {@link recognize_route()}, {@link set_paths()} 
     93     *  @var string 
     94     */ 
     95    private $helpers_path; 
     96 
     97    /** 
    22598     *  Filesystem path to ../app/helpers/ directory 
    22699     * 
     
    228101     *  @var string 
    229102     */ 
    230     private $helpers_path; 
    231  
    232     /** 
    233      *  @todo Document this attribute 
    234      */ 
    235103    private $helpers_base_path; 
    236104 
    237105    /** 
    238      *  Filesystem path to ../app/layouts/ directory 
    239      * 
    240      *  Set by {@link recognize_route()} 
    241      *  @todo <b>FIXME:</> declare $layouts_base_path 
     106     *  Filesystem path to ../app/views/layouts/<i>extras</i> directory 
     107     * 
     108     *  Set by {@link recognize_route()}, {@link set_paths()} 
    242109     *  @var string 
    243110     */ 
    244111    private $layouts_path; 
     112 
     113    /** 
     114     *  Filesystem path to ../app/views/layouts/ directory 
     115     * 
     116     *  Set by {@link recognize_route()} 
     117     *  @var string 
     118     */ 
     119    private $layouts_base_path; 
    245120 
    246121    /** 
     
    263138 
    264139    /** 
    265      *  @todo Document this attribute 
     140     *  Filesystem path to the controllername_helper.php file 
     141     * 
     142     *  Set by {@link recognize_route()} 
     143     *  @var string 
    266144     */ 
    267145    private $helper_file; 
     
    306184 
    307185    /** 
     186     *  List of additional helper files for this controller object 
     187     * 
     188     *  Set by {@link add_helper()} 
     189     *  @var string[] 
     190     */ 
     191    private $helpers = array(); 
     192 
     193    /** 
     194     *  List of filters to execute before calling action method 
     195     * 
     196     *  Set by {@link add_before_filters() 
     197     *  @var string[] 
     198     */ 
     199    private $before_filters = array(); 
     200 
     201    /** 
     202     *  List of filters to execute after calling action method 
     203     * 
     204     *  Set by {@link add_after_filters() 
     205     *  @var string[] 
     206     */ 
     207    private $after_filters = array();      
     208 
     209    /** 
    308210     *  @todo Document this attribute 
    309211     */ 
    310     private $helpers = array(); 
     212    protected $before_filter = null; 
    311213 
    312214    /** 
    313215     *  @todo Document this attribute 
    314216     */ 
    315     private $before_filters = array(); 
    316  
    317     /** 
    318      *  @todo Document this attribute 
    319      */ 
    320     private $after_filters = array();      
    321  
    322     /** 
    323      *  @todo Document this attribute 
    324      */ 
    325     protected $before_filter = null; 
    326  
    327     /** 
    328      *  @todo Document this attribute 
    329      */ 
    330217    protected $after_filter = null; 
    331218 
     
    340227 
    341228    /** 
    342      *  @todo Document this attribute 
     229     *  Filesystem path to the view file selected for this action 
     230     * 
     231     *  Set by {@link process_route() 
     232     *  @var string 
    343233     */ 
    344234    public $view_file; 
     
    371261    /** 
    372262     *  @todo Document this attribute 
     263     *  @todo <b>FIXME:</b> Not referenced in this class - is it used 
     264     *        by subclasses?  If so, for what? 
    373265     */ 
    374266    public $asset_host = null; 
    375267 
    376268    /** 
    377      *  @todo Document this attribute 
     269     *  File extension appended to view files 
     270     * 
     271     *  Set from a define in {@link environment.php}.  Usually phtml 
     272     *  @var string 
    378273     */ 
    379274    public $views_file_extention = TRAX_VIEWS_EXTENTION; 
     
    462357     *  Convert URL to controller, action and id 
    463358     * 
    464      *  Parse the URL in $_SERVER['REDIRECT_URL'] into elements. 
     359     *  Parse the URL in 
     360     *  {@link 
     361     *  http://www.php.net/manual/en/reserved.variables.php#reserved.variables.server $_SERVER}['REDIRECT_URL'] 
     362     *  into elements. 
    465363     *  Compute filesystem paths to the various components used by the 
    466364     *  URL and store the paths in object private variables. 
     
    499397        # current url 
    500398        $browser_url = $_SERVER['REDIRECT_URL']; 
     399        //error_log('browser url='.$browser_url); 
    501400        # strip off url prefix, if any 
    502401        if(!is_null(TRAX_URL_PREFIX)) { 
    503             $browser_url = str_replace(TRAX_URL_PREFIX,"",$browser_url); 
    504         } 
     402            // FIXME: Do we know for sure that the 
     403            // initial '/' will be there? 
     404            $browser_url = str_replace('/'.TRAX_URL_PREFIX,"",$browser_url); 
     405        } 
     406        //error_log('browser url='.$browser_url); 
    505407 
    506408        # strip leading slash 
     409        // FIXME: Do we know for sure that the 
     410        // initial '/' will be there? 
    507411        $browser_url = substr($browser_url,1); 
     412        //error_log('browser url='.$browser_url); 
    508413 
    509414        # strip trailing slash (if any) 
     
    511416            $browser_url = substr($browser_url, 0, -1); 
    512417        } 
     418        //error_log('browser url='.$browser_url); 
    513419 
    514420        if($browser_url) { 
     
    528434 
    529435            $route = $this->router->find_route($browser_url); 
     436 
     437            //  find_route() returns an array if it finds a path that 
     438            //  matches the URL, null if no match found 
    530439            if(is_array($route)) { 
    531440                $this->set_paths(); 
     
    538447                    $this->controller = strtolower($this->url_path[@array_search(":controller", $route_path)]); 
    539448                } 
    540  
     449                //error_log('controller='.$this->controller); 
    541450                if(@array_key_exists(":action",$route_params)) { 
    542451                    $this->action = $route_params[':action']; 
     
    546455                    $this->action = strtolower($this->url_path[@array_search(":action", $route_path)]); 
    547456                } 
    548  
     457                //error_log('action='.$this->action); 
     458                //  FIXME: RoR uses :name as a keyword parameter, id 
     459                //  is not treated as a special case. 
     460                //  Do we want to do the same? 
    549461                if(@in_array(":id",$route_path) 
    550462                   && array_key_exists(@array_search(":id", $route_path), 
     
    555467                    } 
    556468                } 
    557  
     469                //error_log('id='.$this->id); 
    558470                $this->views_path .= "/" . $this->controller; 
    559471                $this->controller_file = $this->controllers_path . "/" .  $this->controller . "_controller.php"; 
     
    573485 
    574486    /** 
    575      *  @todo Document this method 
     487     *  Parse URL, extract controller and action and execute them 
     488     * 
    576489     *  @uses $action 
    577490     *  @uses $application_controller_file 
     
    591504     *  @uses raise() 
    592505     *  @uses ScaffoldController 
    593      *  @uses Session::unset() 
     506     *  @uses Session::unset_var() 
    594507     *  @uses $view_file 
    595508     *  @uses $views_file_extention 
     
    599512    function process_route() { 
    600513 
     514        $render_layout = true; 
    601515        # First try to load the routes and setup the paths to everything 
    602516        if(!$this->loaded) { 
     
    616530        } 
    617531 
    618         error_log('process_route() controller="'.$this->controller 
    619                   .'"  action="'.$this->action.'"'); 
     532        //error_log('process_route() controller="'.$this->controller 
     533        //          .'"  action="'.$this->action.'"'); 
    620534        # Include the controller file and execute action 
    621535        // FIXME: redundant, recognize_route() already test for file exists 
    622         if(file_exists($this->controller_file)) { 
     536        if (file_exists($this->controller_file)) { 
    623537            include_once($this->controller_file); 
    624538            if(class_exists($this->controller_class,false)) { 
     
    633547                    $GLOBALS['current_action_name'] = $this->action; 
    634548                    $GLOBALS['current_controller_object'] =& $this->controller_object; 
    635                     error_log('$GLOBALS[\'current_action_name\']=' 
    636                               .$GLOBALS['current_action_name']); 
    637                     error_log('$GLOBALS[\'current_controller_name\']=' 
    638                               .$GLOBALS['current_controller_name']); 
    639                     error_log('$GLOBALS[\'current_controller_path\']=' 
    640                               .$GLOBALS['current_controller_path']); 
     549                    // error_log('$GLOBALS[\'current_action_name\']=' 
     550                    //           .$GLOBALS['current_action_name']); 
     551                    // error_log('$GLOBALS[\'current_controller_name\']=' 
     552                    //           .$GLOBALS['current_controller_name']); 
     553                    // error_log('$GLOBALS[\'current_controller_path\']=' 
     554                    //           .$GLOBALS['current_controller_path']); 
    641555                } 
    642556 
    643557                # Which layout should we use? 
    644558                $layout_file = $this->determine_layout(); 
    645                 error_log('layout_file="'.$layout_file.'"'); 
    646                 # Check if there is any defined scaffolding to load 
     559                // error_log('layout_file="'.$layout_file.'"'); 
     560                // # Check if there is any defined scaffolding to load 
    647561                if(isset($this->controller_object->scaffold)) { 
    648562                    $scaffold = $this->controller_object->scaffold; 
     
    694608                # Call the controller method based on the URL 
    695609                $this->execute_before_filters(); 
     610                // FIXME: shouldn't we check return here? 
    696611                if(method_exists($this->controller_object, $this->action)) { 
    697                     error_log('controller has method "'.$this->action.'"'); 
     612                    //error_log('controller has method "'.$this->action.'"'); 
    698613                    $action = $this->action; 
    699614                    $this->controller_object->$action(); 
    700615                } elseif(file_exists($this->views_path . "/" . $this->action . "." . $this->views_file_extention)) { 
    701                     error_log('views file "'.$this->action.'"'); 
     616                    // error_log('views file "'.$this->action.'"'); 
    702617                    $action = $this->action; 
    703618                } elseif(method_exists($this->controller_object, "index")) { 
    704                     error_log('calling index()'); 
     619                    //error_log('calling index()'); 
    705620                    $this->controller_object->index(); 
    706621                } else { 
    707                     error_log('no action'); 
     622                    //error_log('no action'); 
    708623                    $this->raise("No action responded to ".$this->action, "Unknown action", "404"); 
    709624                } 
     
    714629                    && $this->controller_object->redirect_to != '') { 
    715630                    $this->redirect_to($this->controller_object->redirect_to); 
     631                    //  redirect_to() exits instead of returning 
    716632                } else { 
    717633                    # Pull all the class vars out and turn them from $this->var to $var 
     
    725641                    # If this isn't a scaffolding then get the view file to include 
    726642                    if(!isset($scaffold)) {  
     643                        // error_log('not scaffolding, looking for view file'); 
    727644                        # Normal processing of the view 
    728645                        if(isset($this->controller_object->render_action) 
     
    735652                            $this->view_file = $this->views_path . "/" . "index" . "." . $this->views_file_extention; 
    736653                        } 
     654                        // error_log('view file='.$this->view_file); 
    737655                    } 
    738656 
     
    748666                    ob_end_clean(); 
    749667 
     668                    //error_log('layout file='.$layout_file 
     669                    //          .'  render_layout=' 
     670                    //          .var_export($render_layout,true)); 
    750671                    if(file_exists($layout_file) && $render_layout !== false) { 
    751672                        # render the layout 
     
    765686        } 
    766687 
     688        // error_log('keep flash='.var_export($this->keep_flash,true)); 
    767689        if(!$this->keep_flash) { 
    768690            # Nuke the flash 
     
    774696 
    775697    /** 
    776      *  @todo Document this method 
     698     *  Extend the search path for components 
     699     * 
     700     *  On entry, $url_path is set according to the browser's URL and  
     701     *  $controllers_path has been set according to the configuration 
     702     *  in {@link environment.php config/environment.php} .  Examine 
     703     *  the $controllers_path directory for files or directories that 
     704     *  match any component of the URL.  If one is found, add that 
     705     *  component to all paths.  Replace the contents of $url_path 
     706     *  with the list of URL components that did NOT match any files 
     707     *  or directories. 
    777708     *  @uses $added_path 
    778709     *  @uses $controllers_path 
    779710     *  @uses $helpers_path 
    780      *  @uses $layous_path 
     711     *  @uses $layouts_path 
    781712     *  @uses $views_path 
    782713     *  @uses $url_path 
     714     *  @todo <b>FIXME:</b> Creating a file or directory in 
     715     *        app/controllers with the same name as a controller, action or 
     716     *        other URL element will hijack the browser! 
    783717     */ 
    784718    function set_paths() { 
     
    808742    /** 
    809743     *  Execute the before filters 
     744     *  @uses $before_filters 
    810745     */ 
    811746    function execute_before_filters() { 
     
    825760     *  one filter function, or array of strings with the names of 
    826761     *  several filter functions. 
     762     *  @uses $before_filters 
    827763     */ 
    828764    function add_before_filter($filter_function_name) { 
     
    840776    } 
    841777 
     778    /** 
     779     *  Execute the after filters 
     780     *  @uses $after_filters 
     781     */ 
    842782    function execute_after_filters() { 
    843783        if(count($this->controller_object->after_filters) > 0) { 
     
    857797     *  one filter function, or array of strings with the names of 
    858798     *  several filter functions. 
     799     *  @uses $after_filters 
    859800     */ 
    860801    function add_after_filter($filter_function_name) { 
     
    872813    } 
    873814 
     815    /** 
     816     *  Add a helper to the list of helpers used by a controller 
     817     *  object 
     818     * 
     819     *  @param $helper_name string Name of a helper to add to the list 
     820     *  @uses  $helpers 
     821     *  @uses  $controller_object 
     822     */ 
    874823    function add_helper($helper_name) { 
    875824        if(!in_array($helper_name, $this->controller_object->helpers)) { 
     
    969918 
    970919    /** 
    971      *  @todo Document this method 
     920     *  Select a layout file based on the controller object 
     921     * 
    972922     *  @uses $controller_object 
    973923     *  @uses $layouts_base_path 
     
    979929        # I guess you don't want any layout 
    980930        if($this->controller_object->layout == "null") { 
     931            //error_log('controller->layout absent'); 
    981932            return null; 
    982933        } 
     
    1015966 
    1016967    /** 
    1017      * Redirects the browser to the target specified in options. This parameter can take one of three forms: 
    1018      *  
    1019      *     * Array: The URL will be generated by calling url_for() with the options. 
    1020      *     * String starting with protocol:// (like http://): Is passed straight through as the target for redirection. 
    1021      *     * String not containing a protocol: The current protocol and host is prepended to the string. 
    1022      *     * back: Back to the page that issued the request. Useful for forms that are triggered from multiple places. Short-hand for redirect_to(request.env["HTTP_REFERER"]) 
    1023      *  
    1024      * Examples: 
    1025      *  
    1026      *   redirect_to(array(":action" => "show", ":id" => 5)) 
    1027      *   redirect_to("http://www.rubyonrails.org") 
    1028      *   redirect_to("/images/screenshot.jpg") 
    1029      *   redirect_to("back") 
    1030      * 
    1031      * @param mixed $options array or string url   
     968     *  Redirect the browser to a specified target 
     969     * 
     970     *  Redirect the browser to the target specified in $options. This 
     971     *  parameter can take one of three forms: 
     972     *  <ul> 
     973     *    <li>Array: The URL will be generated by calling 
     974     *      {@link url_for()} with the options.</li> 
     975     *    <li>String starting with a protocol:// (like http://): Is 
     976     *      passed straight through as the target for redirection.</li> 
     977     *    <li>String not containing a protocol: The current protocol 
     978     *      and host is prepended to the string.</li> 
     979     *    <li>back: Back to the page that issued the request. Useful 
     980     *      for forms that are triggered from multiple 
     981     *      places. Short-hand for redirect_to(request.env["HTTP_REFERER"])  
     982     *   </ul> 
     983     * 
     984     *  Examples: 
     985     *  <ul> 
     986     *    <li>redirect_to(array(":action" => "show", ":id" => 5))</li> 
     987     *    <li>redirect_to("http://www.rubyonrails.org")</li> 
     988     *    <li>redirect_to("/images/screenshot.jpg")</li> 
     989     *    <li>redirect_to("back")</li> 
     990     *  </ul> 
     991     * 
     992     *  @param mixed $options array or string url   
     993     *  @todo <b>FIXME:</b> Make header configurable 
    1032994     */     
    1033995    function redirect_to($options = null) {