[ Index ] |
|
Code source de PHPonTrax 2.6.6-svn |
1 <refentry id="{@id}" revision="$Id: ActionController.cls 199 2006-05-05 01:52:43Z haas $"> 2 <refnamediv> 3 <refname>ActionController</refname> 4 <refpurpose></refpurpose> 5 </refnamediv> 6 <refsynopsisdiv> 7 <author> 8 Walt Haas 9 <authorblurb> 10 {@link mailto:haas@xmission.com haas@xmission.com} 11 </authorblurb> 12 </author> 13 </refsynopsisdiv> 14 {@toc} 15 <refsect1 id="{@id intro}"> 16 <title>Introduction</title> 17 <para>The {@link ActionController} base class does the 18 following:</para> 19 <orderedlist> 20 <listitem>Accepts a URL as input</listitem> 21 <listitem>Translates the URL into a controller and action</listitem> 22 <listitem>Creates the indicated controller object (which is a subclass 23 of ActionController) and calls its action method</listitem> 24 <listitem>Redirects to another URL or renders the output of the 25 action method</listitem> 26 </orderedlist> 27 </refsect1> 28 <refsect1 id="{@id url}"> 29 <title>URL Processing</title> 30 31 <para> 32 When Apache receives an HTTP request addressed to a Trax 33 application, 34 {@link http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html Apache mod_rewrite} 35 is invoked and rewrites the request to invoke Trax file 36 <literal>dispatch.php</literal>. At this time the URL which was 37 input to the rewrite rules is in 38 {@link http://www.php.net/manual/en/reserved.variables.php#reserved.variables.server $_SERVER}['REDIRECT_URL']. 39 <literal>dispatch.php</literal> creates a new {@link Dispatcher} 40 object and calls its 41 {@link Dispatcher::dispatch() dispatch()} method. dispatch() 42 restores the state of the session identified by a cookie in the 43 request, or creates a session if none exists. Then it creates a 44 new ActionController object and calls its 45 {@link ActionController::process_route() <literal>process_route()</literal>} 46 method. 47 </para> 48 49 <para> 50 The word "route" is used in Trax to describe a rule which 51 translates some URL into a particular controller object and method. 52 When <literal>process_route()</literal> receives control, it calls 53 {@link ActionController::recognize_route() recognize_route()} to 54 parse the URL into controller, action and id 55 components. recognize_route() calls 56 {@link ActionController::load_router() load_router()} to load the 57 "routing table", which is a list of one or more 58 <literal>$router->connect()</literal> calls, from 59 {@link routes.php <literal>config/routes.php</literal>}. 60 This list of calls define the rules for translating a URL into a 61 controller and action. 62 </para> 63 64 <para> 65 The translation rules work as follows: Starting with the first 66 rule in <literal>routes.php</literal>, each rule is tested against 67 the URL to see 68 whether the rule matches. If a rule does not match, then the next 69 rule in the table is tested in turn, until a rule matches or the 70 table is exhausted. If no matching rule is found, 71 recognize_route() tests the last route in the table to see whether 72 it is the default route <literal>:controller/:action/:id</literal> 73 . If the last route is the default route, then 74 <literal>recognize_route()</literal> 75 returns it as a match, even if it does not in fact match. But if 76 there is no matching route and the last route in the table is not 77 the default route, then recognize_route() returns 'failure' which is 78 equivalent to HTTP code '404 Not found'. 79 </para> 80 81 <para> 82 Each entry in the route table contains two parts: 83 <orderedlist> 84 <listitem> 85 A <important>path</important>, which is a character string to 86 test against the URL. 87 </listitem> 88 <listitem> 89 <important>Parameters</important>, which are not tested against 90 the URL and aren't involved unless the 91 <important>path</important> part of the entry matches the URL. 92 <important>Parameters</important> are optional (and frequently 93 omitted). 94 </listitem> 95 </orderedlist> 96 A <important>path</important> is a series of substrings separated 97 by '/' (forward slash) characters. Each of these substrings can 98 contain any character except '/'. The <important>path</important> 99 does not begin or end with '/'. A substring may not be the null 100 (no characters) string, but it is legal for the entire 101 path to be the null string. Each substring is one of the following: 102 <itemizedlist> 103 <listitem><literal>:controller</literal></listitem> 104 <listitem><literal>:action</literal></listitem> 105 <listitem><literal>:id</literal></listitem> 106 <listitem>A 107 {@link http://www.php.net/manual/en/ref.pcre.php Perl regular expression} 108 that does not begin with ':' (colon)</listitem> 109 </itemizedlist> 110 The following are legal <important>path</important> values: 111 <itemizedlist> 112 <listitem><literal>:controller/:action/:id</literal> 113 This is the default <important>path</important>. It matches URLs 114 like <literal>word1/word2/word3</literal></listitem> 115 <listitem><literal>catalog/product/:action/:id</literal> 116 Remember that <literal>catalog</literal> is a Perl regular 117 expression that matches <literal>catalog</literal>, and 118 <literal>product</literal> is a Perl regular expression that 119 matches <literal>product</literal>, so this 120 <important>path</important> matches URLs like 121 <literal>catalog/product/word1/word2</literal></listitem> 122 <listitem><literal>''</literal> matches '' (the empty string as a 123 <important>path</important> value matches the empty string as a 124 URL).</listitem> 125 <listitem><literal>member/name=.*</literal> matches URLs like 126 <literal>member/name=</literal> or 127 <literal>member/name=Tom.Jones</literal> or 128 <literal>member/name=Smith,J/since=1987/type=full</literal> etc. 129 </listitem> 130 </itemizedlist> 131 <literal>:controller</literal>, <literal>:action</literal> and 132 <literal>:id</literal> may each appear at most once in a 133 <important>path</important>. 134 </para> 135 136 <para> 137 After the URL has been matched to a <important>path</important>, 138 the next step is to extract the name of the controller and action 139 to be invoked on this URL. These must be valid names in the PHP 140 language consisting only of lower-case alphameric characters and 141 '_' (underscore), because the controller name will translate 142 directly into a file name and a class name, and the action name 143 will be used as the name of a method in that class. The controller 144 and action names come from the route that matches the URL. 145 </para> 146 147 <para> 148 There are two places that a route can specify a controller or 149 action name: as part of the <important>path</important>, or in the 150 <important>parameters</important>. The 151 <important>parameters</important> are the optional second part of a 152 route. The value of <important>parameters</important> is an array 153 with key values that may be <literal>:controller</literal> or 154 <literal>:action</literal>. The following are legal 155 <important>parameters</important> values: 156 <itemizedlist> 157 <listitem><literal>array(':controller' => 158 'new_product')</literal></listitem> 159 <listitem><literal>array(':action' => 'enter')</literal></listitem> 160 <listitem><literal>array(':controller' => 'membership', ':action 161 => 'new')</literal></listitem> 162 </itemizedlist> 163 </para> 164 165 <para> 166 When a URL matches a route, the controller name is extracted as 167 follows: First, if the <important>parameters</important> array 168 exists and has an element whose key is 169 <literal>:controller</literal>, then the value of that element is 170 used as the controller name. If no <literal>:controller</literal> 171 is specified by the <important>parameters</important>, then the 172 <important>path</important> is tested for a substring whose value 173 is <literal>:controller</literal>. If found, then the part of the 174 URL which matched that substring is used as the controller value. 175 A controller value must be specified by either the 176 <important>parameters</important> or the 177 <important>path</important>. The action name is extracted by the 178 same process, substituting <literal>:action</literal> for 179 <literal>:controller</literal>. If the 180 <important>path</important> has a substring <literal>:id</literal>, 181 then the part of the URL which matched that substring is forced to 182 lower case and the result assigned to 183 <literal>$_REQUEST['id']</literal>. 184 </para> 185 186 <para> 187 If <literal>routes.php</literal> contains the following: 188 <example> 189 router->connect('',array(':controller' => 'home')); 190 router->connect('product\?.*', 191 array(':controller' => 'catalog', ':action' => 'find')); 192 router->connect(':controller/:action/:id'); 193 </example> 194 Then URLs will match routes as follows: 195 <itemizedlist> 196 <listitem>URL <literal>''</literal> (no characters) will select 197 controller <literal>home</literal>, action not specified. 198 </listitem> 199 <listitem>URL <literal>product?item=4317</literal> will select 200 controller <literal>catalog</literal>, action 201 <literal>find</literal> 202 </listitem> 203 <listitem>URL <literal>cart/add/4317</literal> will select 204 controller <literal>cart</literal>, action <literal>add</literal> 205 </listitem> 206 </itemizedlist> 207 </para> 208 209 </refsect1> 210 <refsect1 id="{@id action}"> 211 <title>Action Call</title> 212 <para>When the names of the controller and action have been 213 successfully determined from the URL, the associated filesystem 214 paths are constructed and relevant files are loaded, and any 215 parameters and their values are stored in 216 {@link ActionController::action_params}. 217 First file <literal>app/controllers/application.php</literal> is 218 loaded if it exists. This file contains the definition of the 219 {@link ApplicationController} class, which extends 220 <literal>ActionController</literal>. 221 <literal>ApplicationController</literal> contains properties and 222 methods used by all the controller classes, which should extend 223 <literal>ApplicationController</literal> . 224 Then the controller name is used to find the file and class 225 containing the selected controller. By Trax naming conventions, 226 if the controller name is 227 <arg choice="tute-comment">controller name</arg> 228 then the controller file name is 229 <arg choice="tute-comment">controller_name</arg><literal>_controller.php</literal> 230 and the controller class name is 231 <arg choice="tute-comment">ControllerName</arg> . So for a 232 "catalog item" controller, the controller file name is 233 <literal>catalog_item_controller</literal> and the controller class 234 name is <literal>CatalogItem</literal>. 235 The controller file is loaded and a new object of the controller 236 class is created. 237 </para> 238 239 <para> 240 Next any needed helper files are loaded. Helper files contain PHP 241 code which helps prepare the output of an action method for 242 viewing. If file 243 <literal>application_helper.php</literal> exists, it is loaded. 244 <literal>application_helper.php</literal> contains 245 helpers that apply to every controller in the application. 246 Then the controller-specific helper file 247 <arg choice="tute-comment">controller_name</arg><literal>_helper.php</literal> 248 is loaded if it exists. Finally any extra helper files, as 249 specified by calls to {@link ActionController::add_helper()}, are 250 loaded. 251 </para> 252 253 <para> 254 When controller and helper files have been loaded, the before 255 filters are executed (<important>FIXME:</important> We should check 256 return but don't). Next the controller object is tested for the 257 presence of a method with the name of the action as determined from 258 the URL. If such a method exists, it is called; if 259 no such method exists, then the controller object is tested 260 for the presence of a method named <literal>index()</literal>. 261 If such a method exists it is called, otherwise the request fails 262 with 404 Unknown action. If an action method was found 263 and called, the after filters are executed. 264 </para> 265 266 <refsect2 id="{@id helpers}"> 267 <title>Helper Loading</title> 268 <para>Helpers are classes that provide view logic. They exist to 269 hold view logic that would otherwise need to be added to a 270 template or controller. Helper services that are applicable to 271 the entire application go into 272 <literal>application_helper.php</literal>, while 273 controller-specific helper functions go into a helper file named 274 after the controller, as 275 <arg choice="tute-comment">controller_name</arg><literal>_helper.php</literal> 276 . Helper classes are written as subclasses of class {@link Helpers}, 277 which has a number of methods widely used by helper 278 subclasses. You can add a helper to an 279 <literal>ActionController</literal> object by calling its 280 {@link ActionController::add_helper() add_helper()} 281 method, passing the name of the helper as an argument. 282 </para> 283 284 <para> 285 A number of predefined helper classes are distributed with Trax: 286 <itemizedlist> 287 <listitem>{@link ActiveRecordHelper}</listitem> 288 <listitem>{@link AssetTagHelper}</listitem> 289 <listitem>{@link DateHelper}</listitem> 290 <listitem>{@link FormHelper}</listitem> 291 <listitem>{@link FormTagHelper}</listitem> 292 <listitem>{@link JavaScriptHelper}</listitem> 293 <listitem>{@link UrlHelper}</listitem> 294 </itemizedlist> 295 These classes are <important>not</important> automatically loaded, 296 you have to load them explicitly. 297 </para> 298 <para></para> 299 </refsect2> 300 301 <refsect2 id="{@id filters}"> 302 <title>Filters</title> 303 304 <para>Filters enable controllers to run shared pre and post 305 processing code for its actions. These filters can be used to do 306 authentication, caching, or auditing before the intended action is 307 performed. Or to do localization or output compression after the 308 action has been performed.</para> 309 310 <para>Filters have access to the request, response, and all the 311 instance variables set by other filters in the chain or by the 312 action (in the case of after filters). Additionally, it's possible 313 for a pre-processing <samp>before_filter</samp> to halt the processing 314 before the intended action is processed by returning false or 315 performing a redirect or render. (FIXME: we don't implement this) 316 This is especially useful for 317 filters like authentication where you're not interested in 318 allowing the action to be performed if the proper credentials are 319 not in order.</para> 320 321 <refsect3 id="{@id filter_inherit}"> 322 <title>Filter inheritance</title> 323 324 <para>Controller inheritance hierarchies share filters downwards, but 325 subclasses can also add new filters without affecting the 326 superclass. For example:</para> 327 328 <example> 329 class BankController extends ActionController 330 { 331 $this->before_filter = audit(); 332 333 private function audit() { 334 // record the action and parameters in an audit log 335 } 336 } 337 338 class VaultController extends BankController 339 { 340 $this->before_filter = verify_credentials(); 341 342 private function verify_credentials() { 343 // make sure the user is allowed into the vault 344 } 345 } 346 </example> 347 348 <para>Now any actions performed on the BankController will have the 349 audit method called before. On the VaultController, first the 350 audit method is called, then the verify_credentials method. If the 351 audit method returns false, then verify_credentials and the 352 intended action are never called. <important>FIXME: 353 This is currently broken.</important></para> 354 </refsect3> 355 356 <refsect3 id="{@id filter_types}"> 357 <title>Filter types</title> 358 359 <para>A filter can take one of three forms: method reference 360 (symbol), external class, or inline method (proc). The first is the 361 most common and works by referencing a protected or private method 362 somewhere in the inheritance hierarchy of the controller by use of 363 a symbol. In the bank example above, both BankController and 364 VaultController use this form.</para> 365 366 <para>Using an external class makes for more easily reused generic 367 filters, such as output compression. External filter classes are 368 implemented by having a static +filter+ method on any class and 369 then passing this class to the filter method. Example:</para> 370 371 <example> 372 class OutputCompressionFilter 373 { 374 static functionfilter(controller) { 375 controller.response.body = compress(controller.response.body) 376 } 377 } 378 379 class NewspaperController extends ActionController 380 { 381 $this->after_filter = OutputCompressionFilter; 382 } 383 </example> 384 385 <para>The filter method is passed the controller instance and is 386 hence granted access to all aspects of the controller and can 387 manipulate them as it sees fit.</para> 388 389 <para>The inline method (using a proc) can be used to quickly do 390 something small that doesn't require a lot of explanation. Or 391 just as a quick test. It works like this:</para> 392 393 <example> 394 class WeblogController extends ActionController 395 { 396 before_filter { |controller| false if controller.params["stop_action"] } 397 } 398 </example> 399 400 <para>As you can see, the block expects to be passed the controller 401 after it has assigned the request to the internal variables. This 402 means that the block has access to both the request and response 403 objects complete with convenience methods for params, session, 404 template, and assigns. Note: The inline method doesn't strictly 405 have to be a block; any object that responds to call and returns 1 406 or -1 on arity will do (such as a Proc or an Method object).</para> 407 </refsect3> 408 409 <refsect3 id="{@id filter_skip}"> 410 <title>Filter chain skipping</title> 411 412 <para>Some times its convenient to specify a filter chain in a 413 superclass that'll hold true for the majority of the subclasses, 414 but not necessarily all of them. The subclasses that behave in 415 exception can then specify which filters they would like to be 416 relieved of. Examples</para> 417 418 <example> 419 class ApplicationController extends ActionController 420 { 421 $this->before_filter = authenticate(); 422 } 423 424 class WeblogController extends ApplicationController 425 { 426 // will run the authenticate() filter 427 } 428 </example> 429 </refsect3> 430 431 <refsect3 id="{@id filter_conditions}"> 432 <title>Filter conditions</title> 433 434 <para>Filters can be limited to run for only specific 435 actions. This can be expressed either by listing the actions to 436 exclude or the actions to include when executing the 437 filter. Available conditions are +:only+ or +:except+, both of 438 which accept an arbitrary number of method references. For 439 example:</para> 440 441 <example> 442 class Journal extends ActionController 443 { 444 // only require authentication if the current action is edit or delete 445 before_filter :authorize, :only => [ :edit, :delete ] 446 447 private function authorize() { 448 // redirect to login unless authenticated 449 } 450 } 451 </example> 452 453 <para>When setting conditions on inline method (proc) filters the 454 condition must come first and be placed in parentheses.</para> 455 456 <example> 457 class UserPreferences extends ActionController 458 { 459 before_filter(:except => :new) { ? some proc ... } 460 ... 461 } 462 </example> 463 </refsect3> 464 </refsect2> 465 </refsect1> 466 <refsect1 id="{@id render}"> 467 <title>Redirect Browser or Render Output</title> 468 469 <para>After the controller object's action method has returned to 470 <literal>ActionController::process_route()</literal> and the after 471 filters have been executed, the controller object is examined for 472 a property named <literal>redirect_to</literal>. If this 473 property exists and has a value, it means that the action method 474 has decided to redirect the user's browser to a different URL. The 475 value of the <literal>redirect_to</literal> property is passed to 476 {@link ActionController::redirect_to() <literal>redirect_to()</literal>} 477 which outputs a header redirecting the browser, then calls 478 {@link http://www.php.net/manual/en/function.exit.php exit} .</para> 479 480 <para> 481 If the action didn't redirect the browser, it should have provided 482 output to send to the browser. This is in the form of explicit 483 output produced by calls to 484 {@link http://www.php.net/manual/en/function.echo.php echo}, 485 {@link http://www.php.net/manual/en/function.print.php print} or 486 {@link http://www.php.net/manual/en/function.printf.php printf} , 487 plus any properties of the controller object that are referenced in 488 the layout. <literal>ActionController::process_route()</literal> 489 collects all output produced by the controller's action method 490 in the output buffer, for presentation within a layout. 491 </para> 492 493 <para> 494 If the controller object has a property 495 <literal>render_text</literal> which contains a string, then this 496 string is sent directly to the browser and all output and view 497 files are ignored. 498 </para> 499 500 <para> 501 If <literal>render_text</literal> is undefined or empty, then the 502 saved output of the controller's action method is to be rendered. 503 A <important>view file</important> determined by the action is 504 found and included. The view file for an action is 505 <literal>app/views/</literal><arg choice="tute-comment">controller_name/action_name</arg><literal>.phtml</literal> . 506 This file contains HTML, which goes to the output buffer after the 507 action method's output. The output buffer is now assigned to 508 $content_for_layout. Finally the layout file is loaded. The 509 view file and layout file both contain HTML with 510 {@link http://www.php.net/manual/en/language.basic-syntax.php embedded PHP} 511 expressions to present action method output to the user. 512 </para> 513 </refsect1> 514 <!-- 515 Local variables: 516 mode: xml 517 c-basic-offset: 1 518 indent-tabs-mode: nil 519 End: 520 --> 521 </refentry>
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 |