[ Index ] |
|
Code source de Symfony 1.0.0 |
1 <?php 2 3 /* 4 * This file is part of the symfony package. 5 * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com> 6 * (c) 2004-2006 Sean Kerr. 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12 /** 13 * sfController directs application flow. 14 * 15 * @package symfony 16 * @subpackage controller 17 * @author Fabien Potencier <fabien.potencier@symfony-project.com> 18 * @author Sean Kerr <skerr@mojavi.org> 19 * @version SVN: $Id: sfController.class.php 3221 2007-01-11 07:33:23Z fabien $ 20 */ 21 abstract class sfController 22 { 23 protected 24 $context = null, 25 $controllerClasses = array(), 26 $maxForwards = 5, 27 $renderMode = sfView::RENDER_CLIENT, 28 $viewCacheClassName = null; 29 30 /** 31 * Indicates whether or not a module has a specific component. 32 * 33 * @param string A module name 34 * @param string An component name 35 * 36 * @return bool true, if the component exists, otherwise false 37 */ 38 public function componentExists($moduleName, $componentName) 39 { 40 return $this->controllerExists($moduleName, $componentName, 'component', false); 41 } 42 43 /** 44 * Indicates whether or not a module has a specific action. 45 * 46 * @param string A module name 47 * @param string An action name 48 * 49 * @return bool true, if the action exists, otherwise false 50 */ 51 public function actionExists($moduleName, $actionName) 52 { 53 return $this->controllerExists($moduleName, $actionName, 'action', false); 54 } 55 56 /** 57 * Looks for a controller and optionally throw exceptions if existence is required (i.e. 58 * in the case of {@link getController()}). 59 * 60 * @param string The name of the module 61 * @param string The name of the controller within the module 62 * @param string Either 'action' or 'component' depending on the type of controller to look for 63 * @param boolean Whether to throw exceptions if the controller doesn't exist 64 * 65 * @throws sfConfigurationException thrown if the module is not enabled 66 * @throws sfControllerException thrown if the controller doesn't exist and the $throwExceptions parameter is set to true 67 * 68 * @return boolean true if the controller exists, false otherwise 69 */ 70 protected function controllerExists($moduleName, $controllerName, $extension, $throwExceptions) 71 { 72 $dirs = sfLoader::getControllerDirs($moduleName); 73 foreach ($dirs as $dir => $checkEnabled) 74 { 75 // plugin module enabled? 76 if ($checkEnabled && !in_array($moduleName, sfConfig::get('sf_enabled_modules')) && is_readable($dir)) 77 { 78 $error = 'The module "%s" is not enabled.'; 79 $error = sprintf($error, $moduleName); 80 81 throw new sfConfigurationException($error); 82 } 83 84 // one action per file or one file for all actions 85 $classFile = strtolower($extension); 86 $classSuffix = ucfirst(strtolower($extension)); 87 $file = $dir.'/'.$controllerName.$classSuffix.'.class.php'; 88 if (is_readable($file)) 89 { 90 // action class exists 91 require_once($file); 92 93 $this->controllerClasses[$moduleName.'_'.$controllerName.'_'.$classSuffix] = $controllerName.$classSuffix; 94 95 return true; 96 } 97 98 $module_file = $dir.'/'.$classFile.'s.class.php'; 99 if (is_readable($module_file)) 100 { 101 // module class exists 102 require_once($module_file); 103 104 if (!class_exists($moduleName.$classSuffix.'s', false)) 105 { 106 if ($throwExceptions) 107 { 108 throw new sfControllerException(sprintf('There is no "%s" class in your action file "%s".', $moduleName.$classSuffix.'s', $module_file)); 109 } 110 111 return false; 112 } 113 114 // action is defined in this class? 115 if (!in_array('execute'.ucfirst($controllerName), get_class_methods($moduleName.$classSuffix.'s'))) 116 { 117 if ($throwExceptions) 118 { 119 throw new sfControllerException(sprintf('There is no "%s" method in your action class "%s"', 'execute'.ucfirst($controllerName), $moduleName.$classSuffix.'s')); 120 } 121 122 return false; 123 } 124 125 $this->controllerClasses[$moduleName.'_'.$controllerName.'_'.$classSuffix] = $moduleName.$classSuffix.'s'; 126 return true; 127 } 128 } 129 130 // send an exception if debug 131 if ($throwExceptions && sfConfig::get('sf_debug')) 132 { 133 $dirs = array_keys($dirs); 134 135 // remove sf_root_dir from dirs 136 foreach ($dirs as &$dir) 137 { 138 $dir = str_replace(sfConfig::get('sf_root_dir'), '%SF_ROOT_DIR%', $dir); 139 } 140 141 throw new sfControllerException(sprintf('{sfController} controller "%s/%s" does not exist in: %s', $moduleName, $controllerName, implode(', ', $dirs))); 142 } 143 144 return false; 145 } 146 147 /** 148 * Forwards the request to another action. 149 * 150 * @param string A module name 151 * @param string An action name 152 * 153 * @throws <b>sfConfigurationException</b> If an invalid configuration setting has been found 154 * @throws <b>sfForwardException</b> If an error occurs while forwarding the request 155 * @throws <b>sfInitializationException</b> If the action could not be initialized 156 * @throws <b>sfSecurityException</b> If the action requires security but the user implementation is not of type sfSecurityUser 157 */ 158 public function forward($moduleName, $actionName) 159 { 160 // replace unwanted characters 161 $moduleName = preg_replace('/[^a-z0-9\-_]+/i', '', $moduleName); 162 $actionName = preg_replace('/[^a-z0-9\-_]+/i', '', $actionName); 163 164 if ($this->getActionStack()->getSize() >= $this->maxForwards) 165 { 166 // let's kill this party before it turns into cpu cycle hell 167 $error = 'Too many forwards have been detected for this request (> %d)'; 168 $error = sprintf($error, $this->maxForwards); 169 170 throw new sfForwardException($error); 171 } 172 173 $rootDir = sfConfig::get('sf_root_dir'); 174 $app = sfConfig::get('sf_app'); 175 $env = sfConfig::get('sf_environment'); 176 177 if (!sfConfig::get('sf_available') || sfToolkit::hasLockFile($rootDir.'/'.$app.'_'.$env.'.clilock')) 178 { 179 // application is unavailable 180 $moduleName = sfConfig::get('sf_unavailable_module'); 181 $actionName = sfConfig::get('sf_unavailable_action'); 182 183 if (!$this->actionExists($moduleName, $actionName)) 184 { 185 // cannot find unavailable module/action 186 $error = 'Invalid configuration settings: [sf_unavailable_module] "%s", [sf_unavailable_action] "%s"'; 187 $error = sprintf($error, $moduleName, $actionName); 188 189 throw new sfConfigurationException($error); 190 } 191 } 192 193 // check for a module generator config file 194 sfConfigCache::getInstance()->import(sfConfig::get('sf_app_module_dir_name').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_config_dir_name').'/generator.yml', true, true); 195 196 if (!$this->actionExists($moduleName, $actionName)) 197 { 198 // the requested action doesn't exist 199 if (sfConfig::get('sf_logging_enabled')) 200 { 201 $this->getContext()->getLogger()->info('{sfController} action does not exist'); 202 } 203 204 // track the requested module so we have access to the data in the error 404 page 205 $this->context->getRequest()->setAttribute('requested_action', $actionName); 206 $this->context->getRequest()->setAttribute('requested_module', $moduleName); 207 208 // switch to error 404 action 209 $moduleName = sfConfig::get('sf_error_404_module'); 210 $actionName = sfConfig::get('sf_error_404_action'); 211 212 if (!$this->actionExists($moduleName, $actionName)) 213 { 214 // cannot find unavailable module/action 215 $error = 'Invalid configuration settings: [sf_error_404_module] "%s", [sf_error_404_action] "%s"'; 216 $error = sprintf($error, $moduleName, $actionName); 217 218 throw new sfConfigurationException($error); 219 } 220 } 221 222 // create an instance of the action 223 $actionInstance = $this->getAction($moduleName, $actionName); 224 225 // add a new action stack entry 226 $this->getActionStack()->addEntry($moduleName, $actionName, $actionInstance); 227 228 // include module configuration 229 require(sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_config_dir_name').'/module.yml')); 230 231 // check if this module is internal 232 if ($this->getActionStack()->getSize() == 1 && sfConfig::get('mod_'.strtolower($moduleName).'_is_internal') && !sfConfig::get('sf_test')) 233 { 234 $error = 'Action "%s" from module "%s" cannot be called directly'; 235 $error = sprintf($error, $actionName, $moduleName); 236 237 throw new sfConfigurationException($error); 238 } 239 240 if (sfConfig::get('mod_'.strtolower($moduleName).'_enabled')) 241 { 242 // module is enabled 243 244 // check for a module config.php 245 $moduleConfig = sfConfig::get('sf_app_module_dir').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_config_dir_name').'/config.php'; 246 if (is_readable($moduleConfig)) 247 { 248 require_once($moduleConfig); 249 } 250 251 // initialize the action 252 if ($actionInstance->initialize($this->context)) 253 { 254 // create a new filter chain 255 $filterChain = new sfFilterChain(); 256 $this->loadFilters($filterChain, $actionInstance); 257 258 if ($moduleName == sfConfig::get('sf_error_404_module') && $actionName == sfConfig::get('sf_error_404_action')) 259 { 260 $this->getContext()->getResponse()->setStatusCode(404); 261 $this->getContext()->getResponse()->setHttpHeader('Status', '404 Not Found'); 262 263 foreach (sfMixer::getCallables('sfController:forward:error404') as $callable) 264 { 265 call_user_func($callable, $this, $moduleName, $actionName); 266 } 267 } 268 269 // change i18n message source directory to our module 270 if (sfConfig::get('sf_i18n')) 271 { 272 $this->context->getI18N()->setMessageSourceDir(sfLoader::getI18NDir($moduleName), $this->context->getUser()->getCulture()); 273 } 274 275 // process the filter chain 276 $filterChain->execute(); 277 } 278 else 279 { 280 // action failed to initialize 281 $error = 'Action initialization failed for module "%s", action "%s"'; 282 $error = sprintf($error, $moduleName, $actionName); 283 284 throw new sfInitializationException($error); 285 } 286 } 287 else 288 { 289 // module is disabled 290 $moduleName = sfConfig::get('sf_module_disabled_module'); 291 $actionName = sfConfig::get('sf_module_disabled_action'); 292 293 if (!$this->actionExists($moduleName, $actionName)) 294 { 295 // cannot find mod disabled module/action 296 $error = 'Invalid configuration settings: [sf_module_disabled_module] "%s", [sf_module_disabled_action] "%s"'; 297 $error = sprintf($error, $moduleName, $actionName); 298 299 throw new sfConfigurationException($error); 300 } 301 302 $this->forward($moduleName, $actionName); 303 } 304 } 305 306 /** 307 * Retrieves an sfAction implementation instance. 308 * 309 * @param string A module name 310 * @param string An action name 311 * 312 * @return sfAction An sfAction implementation instance, if the action exists, otherwise null 313 */ 314 public function getAction($moduleName, $actionName) 315 { 316 return $this->getController($moduleName, $actionName, 'action'); 317 } 318 319 /** 320 * Retrieves a sfComponent implementation instance. 321 * 322 * @param string A module name 323 * @param string A component name 324 * 325 * @return sfComponent A sfComponent implementation instance, if the component exists, otherwise null 326 */ 327 public function getComponent($moduleName, $componentName) 328 { 329 return $this->getController($moduleName, $componentName, 'component'); 330 } 331 332 /** 333 * Retrieves a controller implementation instance. 334 * 335 * @param string A module name 336 * @param string A component name 337 * @param string Either 'action' or 'component' depending on the type of controller to look for 338 * 339 * @return object A controller implementation instance, if the controller exists, otherwise null 340 * 341 * @see getComponent(), getAction() 342 */ 343 protected function getController($moduleName, $controllerName, $extension) 344 { 345 $classSuffix = ucfirst(strtolower($extension)); 346 if (!isset($this->controllerClasses[$moduleName.'_'.$controllerName.'_'.$classSuffix])) 347 { 348 $this->controllerExists($moduleName, $controllerName, $extension, true); 349 } 350 351 $class = $this->controllerClasses[$moduleName.'_'.$controllerName.'_'.$classSuffix]; 352 353 // fix for same name classes 354 $moduleClass = $moduleName.'_'.$class; 355 356 if (class_exists($moduleClass, false)) 357 { 358 $class = $moduleClass; 359 } 360 361 return new $class(); 362 } 363 364 /** 365 * Retrieves the action stack. 366 * 367 * @return sfActionStack An sfActionStack instance, if the action stack is enabled, otherwise null 368 */ 369 public function getActionStack() 370 { 371 return $this->context->getActionStack(); 372 } 373 374 /** 375 * Retrieves the current application context. 376 * 377 * @return sfContext A sfContext instance 378 */ 379 public function getContext() 380 { 381 return $this->context; 382 } 383 384 /** 385 * Retrieves the presentation rendering mode. 386 * 387 * @return int One of the following: 388 * - sfView::RENDER_CLIENT 389 * - sfView::RENDER_VAR 390 */ 391 public function getRenderMode() 392 { 393 return $this->renderMode; 394 } 395 396 /** 397 * Retrieves a sfView implementation instance. 398 * 399 * @param string A module name 400 * @param string An action name 401 * @param string A view name 402 * 403 * @return sfView A sfView implementation instance, if the view exists, otherwise null 404 */ 405 public function getView($moduleName, $actionName, $viewName) 406 { 407 // user view exists? 408 $file = sfConfig::get('sf_app_module_dir').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_view_dir_name').'/'.$actionName.$viewName.'View.class.php'; 409 410 if (is_readable($file)) 411 { 412 require_once($file); 413 414 $class = $actionName.$viewName.'View'; 415 416 // fix for same name classes 417 $moduleClass = $moduleName.'_'.$class; 418 419 if (class_exists($moduleClass, false)) 420 { 421 $class = $moduleClass; 422 } 423 } 424 else 425 { 426 // view class (as configured in module.yml or defined in action) 427 $viewName = $this->getContext()->getRequest()->getAttribute($moduleName.'_'.$actionName.'_view_name', sfConfig::get('mod_'.strtolower($moduleName).'_view_class'), 'symfony/action/view'); 428 $class = sfCore::getClassPath($viewName.'View') ? $viewName.'View' : 'sfPHPView'; 429 } 430 431 return new $class(); 432 } 433 434 /** 435 * Initializes this controller. 436 * 437 * @param sfContext A sfContext implementation instance 438 */ 439 public function initialize($context) 440 { 441 $this->context = $context; 442 443 if (sfConfig::get('sf_logging_enabled')) 444 { 445 $this->context->getLogger()->info('{sfController} initialization'); 446 } 447 448 // set max forwards 449 $this->maxForwards = sfConfig::get('sf_max_forwards'); 450 } 451 452 /** 453 * Retrieves a new sfController implementation instance. 454 * 455 * @param string A sfController class name 456 * 457 * @return sfController A sfController implementation instance 458 * 459 * @throws sfFactoryException If a new controller implementation instance cannot be created 460 */ 461 public static function newInstance($class) 462 { 463 try 464 { 465 // the class exists 466 $object = new $class(); 467 468 if (!($object instanceof sfController)) 469 { 470 // the class name is of the wrong type 471 $error = 'Class "%s" is not of the type sfController'; 472 $error = sprintf($error, $class); 473 474 throw new sfFactoryException($error); 475 } 476 477 return $object; 478 } 479 catch (sfException $e) 480 { 481 $e->printStackTrace(); 482 } 483 } 484 485 /** 486 * Sends and email from the current action. 487 * 488 * This methods calls a module/action with the sfMailView class. 489 * 490 * @param string A module name 491 * @param string An action name 492 * 493 * @return string The generated mail content 494 * 495 * @see sfMailView, getPresentationFor(), sfController 496 */ 497 public function sendEmail($module, $action) 498 { 499 return $this->getPresentationFor($module, $action, 'sfMail'); 500 } 501 502 /** 503 * Returns the rendered view presentation of a given module/action. 504 * 505 * @param string A module name 506 * @param string An action name 507 * @param string A View class name 508 * 509 * @return string The generated content 510 */ 511 public function getPresentationFor($module, $action, $viewName = null) 512 { 513 if (sfConfig::get('sf_logging_enabled')) 514 { 515 $this->getContext()->getLogger()->info('{sfController} get presentation for action "'.$module.'/'.$action.'" (view class: "'.$viewName.'")'); 516 } 517 518 // get original render mode 519 $renderMode = $this->getRenderMode(); 520 521 // set render mode to var 522 $this->setRenderMode(sfView::RENDER_VAR); 523 524 // grab the action stack 525 $actionStack = $this->getActionStack(); 526 527 // grab this next forward's action stack index 528 $index = $actionStack->getSize(); 529 530 // set viewName if needed 531 if ($viewName) 532 { 533 $this->getContext()->getRequest()->setAttribute($module.'_'.$action.'_view_name', $viewName, 'symfony/action/view'); 534 } 535 536 // forward to the mail action 537 $this->forward($module, $action); 538 539 // grab the action entry from this forward 540 $actionEntry = $actionStack->getEntry($index); 541 542 // get raw email content 543 $presentation =& $actionEntry->getPresentation(); 544 545 // put render mode back 546 $this->setRenderMode($renderMode); 547 548 // remove the action entry 549 $nb = $actionStack->getSize() - $index; 550 while ($nb-- > 0) 551 { 552 $actionEntry = $actionStack->popEntry(); 553 554 if ($actionEntry->getModuleName() == sfConfig::get('sf_login_module') && $actionEntry->getActionName() == sfConfig::get('sf_login_action')) 555 { 556 $error = 'Your mail action is secured but the user is not authenticated.'; 557 558 throw new sfException($error); 559 } 560 else if ($actionEntry->getModuleName() == sfConfig::get('sf_secure_module') && $actionEntry->getActionName() == sfConfig::get('sf_secure_action')) 561 { 562 $error = 'Your mail action is secured but the user does not have access.'; 563 564 throw new sfException($error); 565 } 566 } 567 568 // remove viewName 569 if ($viewName) 570 { 571 $this->getContext()->getRequest()->getAttributeHolder()->remove($module.'_'.$action.'_view_name', 'symfony/action/view'); 572 } 573 574 return $presentation; 575 } 576 577 /** 578 * Sets the presentation rendering mode. 579 * 580 * @param int A rendering mode 581 * 582 * @throws sfRenderException If an invalid render mode has been set 583 */ 584 public function setRenderMode($mode) 585 { 586 if ($mode == sfView::RENDER_CLIENT || $mode == sfView::RENDER_VAR || $mode == sfView::RENDER_NONE) 587 { 588 $this->renderMode = $mode; 589 590 return; 591 } 592 593 // invalid rendering mode type 594 $error = 'Invalid rendering mode: %s'; 595 $error = sprintf($error, $mode); 596 597 throw new sfRenderException($error); 598 } 599 600 /** 601 * Indicates whether or not we were called using the CLI version of PHP. 602 * 603 * @return bool true, if using cli, otherwise false. 604 */ 605 public function inCLI() 606 { 607 return 0 == strncasecmp(PHP_SAPI, 'cli', 3); 608 } 609 610 /** 611 * Loads application nad module filters. 612 * 613 * @param sfFilterChain A sfFilterChain instance 614 * @param sfAction A sfAction instance 615 */ 616 public function loadFilters($filterChain, $actionInstance) 617 { 618 $moduleName = $this->context->getModuleName(); 619 620 require(sfConfigCache::getInstance()->checkConfig(sfConfig::get('sf_app_module_dir_name').'/'.$moduleName.'/'.sfConfig::get('sf_app_module_config_dir_name').'/filters.yml')); 621 } 622 623 /** 624 * Calls methods defined via the sfMixer class. 625 * 626 * @param string The method name 627 * @param array The method arguments 628 * 629 * @return mixed The returned value of the called method 630 * 631 * @see sfMixer 632 */ 633 public function __call($method, $arguments) 634 { 635 if (!$callable = sfMixer::getCallable('sfController:'.$method)) 636 { 637 throw new sfException(sprintf('Call to undefined method sfController::%s', $method)); 638 } 639 640 array_unshift($arguments, $this); 641 642 return call_user_func_array($callable, $arguments); 643 } 644 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Fri Mar 16 22:42:14 2007 | par Balluche grâce à PHPXref 0.7 |