[ Index ] |
|
Code source de LifeType 1.2.4 |
1 <?php 2 3 /** 4 * \defgroup Controller 5 * 6 * The controller is the central piece of the MVC pattern, and the object that takes care of 7 * transferrign the process flow to the right action class based on a certain value in the 8 * incoming request. 9 * 10 * This package includes the basic Controller class, as well as the BlogController and 11 * AdminController ones, which implement a bit of extra logic for loading the maps and so on. 12 * 13 * There is also a dynamic class loader (ResourceClassLoader) that takes care of loading action classes 14 * from a certain set of folders. 15 */ 16 17 lt_include( PLOG_CLASS_PATH."class/action/action.class.php" ); 18 lt_include( PLOG_CLASS_PATH."class/controller/resourceclassloader.class.php" ); 19 20 // 21 // various constants that will come handy 22 // 23 define("DEFAULT_ACTION_PARAM", "op"); 24 define("DEFAULT_ACTION_NAME", "Default"); 25 26 // 27 // global array to hold the mappings between action keys and action classes. It is implemented as a 28 // global arry because the Controller::registerAction is a static method and PHP4 does not implement 29 // class-level static methods, and therefore, this is the only way have to accomplish this 30 // functionality 31 // 32 $_plogController_actionMap = array(); 33 34 // 35 // Pretty much the same as above... 36 // 37 $_plogController_forwardAction = array(); 38 39 /** 40 * \ingroup Controller 41 * 42 * This is how MVC works, using the pattern of the 'Front Controller'. With this pattern, we have 43 * a single controller class that receives all the requests from the client, identifies the 44 * action to be taken and the relays the execution of the action to the most suitable Action class. 45 * The 'Action' class then will use the application business logic (the Model) to carry out the 46 * operations necessary. 47 * 48 * (according to http://java.sun.com/blueprints/guidelines/designing_enterprise_applications_2e/web-tier/web-tier5.html) 49 * 50 * # The controller receives a POST from the client. 51 * # The controller creates an Action corresponding to the requested operation (as described in the previous section). 52 * # The controller calls the Action's perform method. 53 * perform calls a model business method. 54 * # The controller calls the screen flow manager to select the next view to display. 55 * # The screen flow manager determines the next view and returns its name to the controller. 56 * # The controller forwards the request to the templating service, which assembles and delivers the selected view to the client. 57 * 58 * The Controller uses an action map file that maps action parameters to action classes. This is file is 59 * nothing more than an associative PHP array where the key of the array is the value of the action 60 * parameter and the key is the name of an action class. The default action parameter is "op" and the default 61 * action is "Default" unless otherwise specified. 62 * 63 * This is an example of a map file: 64 * 65 * <pre> 66 * $actions["Default"] = "AdminDefaultAction"; 67 * $actions["Login"] = "AdminLoginAction"; 68 * $actions["blogSelect"] = "AdminMainAction"; 69 * $actions["Dashboard"] = "AdminMainAction"; 70 * $actions["Manage"] = "AdminManageAction"; 71 * </pre> 72 * 73 * It is not necesary to specify the full extension of the file, and by default it is considered to be 74 * ".class.php". In case this is not the case, please the ResourceClassLoader::setClassFileSuffix() 75 * method. 76 * 77 * Classes can be dynamically loaded (meaning that we 78 * do not need to load all of them via include() or lt_include() at the top of our code), via the 79 * ResourceClassLoader class. This class will scan a set of pre-defined folders looking for the action 80 * class and load it if it's the one we were looking for. 81 * 82 * In order to create a Controller object and process a request, we would use something like: 83 * 84 * <pre> 85 * $controller = new Controller( "myactionmap.properties.php" ); 86 * $controller->process( $_REQUEST ); 87 * </pre> 88 * 89 * It is also possible to register new actions dynamically at run time via the static method 90 * Controller::registerAction() which takes an action class name and an action id as parameters. This is the 91 * method used by plugins to register new actions (although via the wrapper PluginBase::registerAction()) 92 * 93 * In our particular implementation, each action class should extend the Action class or a child of it 94 * such as BlogAction, AdminAction, etc. Each one of this action classes should at least implement 95 * the Action::perform() method and include there its business logic (which can be whatever) Action classes 96 * are expected to generate a valid View class that the Controller will use to render the contents that 97 * will be sent back to the client. The Controller will get the right view via the Action::getView() method, and 98 * views can be set via the Action::_view attribute or the Action::setView() method. 99 * 100 * Another method that the controller will call is the validate() method that can be used for basic 101 * data validation logic. The base Action class already provides some code in this method, which is tied to 102 * the FormValidator and Validator classes so in case of data validation, it is advisable to use those 103 * methods. However if required, feel free to reimplement Action::validate(), keeping in mind that if the controller 104 * receives a positive value, it will continue processing the Action::perform() and if not, it will stop 105 * processing and call Action::getView() right away. 106 * 107 * Actions can also forward the process flow to another action without generating a view by calling 108 * the static method Controller::setForwardAction(), which takes an action class identifier as a parameter. If 109 * after processing action the controller detects that there is a forwarding in place, it will <b>not</b> 110 * call Action::getView() but instead, start the process again and call validate() and process() in the next 111 * action in line. 112 * 113 * @see BlogController 114 * @see AdminController 115 * @see Action 116 * @see BlogAction 117 * @see AdminAction 118 * @see FormValidator 119 * @see Validator 120 */ 121 class Controller 122 { 123 var $_actionParam; 124 125 /** 126 * @public 127 * Determines the base path from where action files can be dynamically loaded 128 */ 129 var $actionFolderPath; 130 131 /** 132 * @private 133 */ 134 var $_cannotPerformAction; 135 136 /** 137 * @private 138 */ 139 var $_forwardAction; 140 141 /** 142 * @private 143 */ 144 var $_loader; 145 146 /** 147 * $ActionsMap is an associative array of the form: 148 * 149 * ( $actionName, $actionClassName ) 150 * 151 * Where for every different possible value of the 'action' parameter in the request, 152 * there is an object inheriting form the Action class that will take care of 153 * that requested action. 154 * 155 * @param actionMap is the associative array with the mappings 156 * @param actionParam is the name of the parameter in the request that will be used 157 * @param loadActionClasses By default set to 'true', enables dynamic loading of the 158 * action classes from disk. Set it to false if the action classes that are going 159 * to be needed by the controller have already been loaded and there is no need to 160 * do it again. 161 * to identify the action to be taken 162 */ 163 function Controller( $actionMap, $actionParam = DEFAULT_ACTION_PARAM ) 164 { 165 global $_plogController_actionMap; 166 if( !is_array($_plogController_actionMap)) 167 $_plogController_actionMap = Array(); 168 169 $_plogController_actionMap = $actionMap; 170 171 $this->_actionParam = $actionParam; 172 $this->_forwardAction = null; 173 174 // default folder where actions are located 175 $this->actionFolderPath = PLOG_CLASS_PATH.'class/action/'; 176 177 // get a resource loader so that we can dynamically load classes if they 178 // have not been loaded yet! 179 $this->_loader =& ResourceClassLoader::getLoader( $this->actionFolderPath ); 180 181 // no action defined in case we cannot perform 182 $this->_cannotPerformAction = null; 183 } 184 185 /** 186 * sets the folder where action classes can be dynamically loaded 187 * 188 * @param newActionFolderPath absolute or relative path to the folder 189 */ 190 function setActionFolderPath( $newActionFolderPath ) 191 { 192 $this->_loader->addSearchFolder( $newActionFolderPath ); 193 } 194 195 /** 196 * @static 197 */ 198 function registerAction( $actionKey, $actionClass ) 199 { 200 global $_plogController_actionMap; 201 if( !is_array($_plogController_actionMap)) // make sure that we have an array 202 $_plogController_actionMap = Array(); 203 $_plogController_actionMap[ $actionKey ] = $actionClass; 204 205 return true; 206 } 207 208 /** 209 * Add function info here 210 * 211 * @private 212 */ 213 function _getActionClassName( $actionName ) 214 { 215 global $_plogController_actionMap; 216 $actionMap = $_plogController_actionMap; 217 218 if (($actionName == '') || (!empty($actionMap) && !array_key_exists($actionName, $actionMap))) { 219 $actionName = DEFAULT_ACTION_NAME; 220 } 221 222 if (!empty($actionMap)) { 223 $actionClassName = $actionMap[$actionName]; 224 } 225 else { 226 $actionClassName = $actionName . 'Action'; 227 } 228 229 return $actionClassName; 230 } 231 232 /** 233 * Sets the action to which we will forward the process 234 * 235 * @param forwardAction Name of the action to which we will forward the current 236 * workflow. 237 * @param previousActionObject 238 * @static 239 */ 240 function setForwardAction( $forwardAction, $previousActionObject = null ) 241 { 242 global $_plogController_forwardAction; 243 global $_plogController_previousAction; 244 245 $_plogController_forwardAction = $forwardAction; 246 $_plogController_previousAction = $previousActionObject; 247 } 248 249 /** 250 * Loads an action class from disk. I have refactored it and put this little bit in its 251 * own method because doing so, applications that want to load the action classes from 252 * somewhere else than PLOG_CLASS_PATH/class/action/, or have a different naming scheme 253 * can extend this class and reimplement this method at will. 254 * 255 * @param actionClass The name of the action class that is to be loaded. 256 * @return Always true. 257 */ 258 function loadActionClass( $actionClass ) 259 { 260 if( !class_exists($actionClass)) { 261 $this->_loader->load( $actionClass ); 262 } 263 264 return true; 265 } 266 267 /** 268 * Specific controllers should use this method to set a class that will be used in case 269 * Action::canPerform() return false. The controller will then load this class and execute 270 * it as if it was a normal action. 271 * This feature can be used to display a view with an error message in case our controller 272 * and actions are working together to provide permission-based access: each action checks whether 273 * the credentials of the current user allow him to execute the current action or not in 274 * the Action::canPeform() method and if it returns true, then the action specified in this method 275 * call takes over and displays whatever error message needs to be displayed (or does some 276 * cleanup, etc, whatever needed) 277 * 278 * @param actionClass A string with the name of the class that should be loaded when 279 * Action::canPerform() returns false. Please note that this is the name of the class, not the 280 * class object itself! 281 */ 282 function setCannotPerformAction( $actionClass ) 283 { 284 $this->_cannotPerformAction = $actionClass; 285 } 286 287 /** 288 * Processess the HTTP request sent by the client 289 * 290 * @param httpRequest HTTP request sent by the client 291 */ 292 function process( $httpRequest ) 293 { 294 lt_include( PLOG_CLASS_PATH."class/net/request.class.php" ); 295 296 // get the name of the action 297 $request = new Request( $httpRequest ); 298 299 $i = 0; 300 $performed = false; 301 302 while( !$performed ) { 303 // get the value of this varilable, every loop 304 global $_plogController_forwardAction; 305 global $_plogController_previousAction; 306 307 // jondaley: 08/29/2005, what are these here for?? 308 // perhaps the global statements should be moved 309 // inside the elseif loop below? 310 $_plogController_forwardAction; 311 $_plogController_previousAction; 312 313 if ($i == 0) { 314 // if this is the first iteration, then we have to take this path... 315 // since we will use the http request to determine which action to 316 // use next 317 $actionName = $request->getValue($this->_actionParam ); 318 $actionClass = $this->_getActionClassName($request->getValue($this->_actionParam)); 319 } 320 elseif (!empty($_plogController_forwardAction)) { 321 // if we're forwarding the current execution flow to another action, then 322 // we'll go this way 323 $actionName = $_plogController_forwardAction; 324 $actionClass = $this->_getActionClassName($_plogController_forwardAction); 325 $httpRequest = HttpVars::getRequest(); 326 $_plogController_forwardAction = null; 327 } 328 else { 329 // if there's nothing else to do, finish 330 $performed = true; 331 } 332 333 if( !$performed ) { 334 lt_include( PLOG_CLASS_PATH."class/action/actioninfo.class.php" ); 335 336 // load the class if it hasn't been loaded yet 337 $this->loadActionClass( $actionClass ); 338 339 $actionInfo = new ActionInfo( $this->_actionParam, $actionName ); 340 $actionObject = new $actionClass( $actionInfo, $httpRequest ); 341 $actionObject->setPreviousAction( $_plogController_previousAction ); 342 343 if( $actionObject->canPerform()) { 344 // we can use the validate method to check the values of the form variables. If validate() 345 // returns 'true', then we call the 'perform' method. If not, then we won't :) 346 if( $actionObject->validate()) { 347 if( $actionObject->perform()) 348 $actionObject->setSuccess( true ); 349 else 350 $actionObject->setSuccess( false ); 351 } 352 } 353 else { 354 // check that we have an action defined for this kind of situations 355 if( $this->_cannotPerformAction === null ) { 356 throw( new Exception( "Action ".$actionName." was not allowed to execute and there is no fallback action to execute" )); 357 die(); 358 } 359 $actionClass = $this->_cannotPerformAction; 360 $this->loadActionClass( $actionClass ); 361 $actionObject = new $actionClass( $actionInfo, $httpRequest ); 362 $actionObject->perform(); 363 } 364 } 365 366 $i++; 367 } 368 369 // once the operation has been carried out, fetch and send the view 370 // to the client 371 $view = $actionObject->getView(); 372 373 // this is not good... 374 if( empty( $view )) { 375 $e = new Exception( 'The view is empty after calling the perform method.' ); 376 throw( $e ); 377 } 378 else 379 $view->render(); 380 } 381 } 382 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Mon Nov 26 21:04:15 2007 | par Balluche grâce à PHPXref 0.7 |
![]() |