| 2 | | # $Id$ |
| 3 | | # |
| 4 | | # Copyright (c) 2005 John Peterson |
| 5 | | # |
| 6 | | # Permission is hereby granted, free of charge, to any person obtaining |
| 7 | | # a copy of this software and associated documentation files (the |
| 8 | | # "Software"), to deal in the Software without restriction, including |
| 9 | | # without limitation the rights to use, copy, modify, merge, publish, |
| 10 | | # distribute, sublicense, and/or sell copies of the Software, and to |
| 11 | | # permit persons to whom the Software is furnished to do so, subject to |
| 12 | | # the following conditions: |
| 13 | | # |
| 14 | | # The above copyright notice and this permission notice shall be |
| 15 | | # included in all copies or substantial portions of the Software. |
| 16 | | # |
| 17 | | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| 18 | | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 19 | | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| 20 | | # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
| 21 | | # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
| 22 | | # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
| 23 | | # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 24 | | |
| | 2 | /** |
| | 3 | * File containing ActionController class |
| | 4 | * |
| | 5 | * (PHP 5) |
| | 6 | * |
| | 7 | * @package PHPonTrax |
| | 8 | * @version $Id$ |
| | 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><b>Filters</b></p> |
| | 35 | * |
| | 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> |
| | 184 | * |
| | 185 | * @package PHPonTrax |
| | 186 | */ |