问:如何获取module参数?如果module参数不存在,如何处理?
答:首先检查$_REQUEST['module'],然后再检查$sugar_config['default_module']是否有设置,如果都没有则用SugarApplication类的实例变量$default_module(默认为Home)。这些在SugarApplication::execute()函数的开头进行处理:
if (!empty($sugar_config['default_module'])) $this->default_module = $sugar_config['default_module']; $module = $this->default_module; if (!empty($_REQUEST['module'])) $module = $_REQUEST['module'];
问:获得module后,会去创建控制器类,在哪里找到该类?
答:ControllerFactory::getController($module)函数负责创建控制器类:
function getController($module) { $class = ucfirst($module).'Controller'; $customClass = 'Custom' . $class; if (file_exists('custom/modules/'.$module.'/controller.php')){ $customClass = 'Custom' . $class; require_once('custom/modules/'.$module.'/controller.php'); if (class_exists($customClass)) { $controller = new $customClass(); } else if (class_exists($class)) { $controller = new $class(); } } elseif (file_exists('modules/'.$module.'/controller.php')) { require_once('modules/'.$module.'/controller.php'); if (class_exists($customClass)) { $controller = new $customClass(); } else if (class_exists($class)) { $controller = new $class(); } } else { if (file_exists('custom/include/MVC/Controller/SugarController.php')) { require_once('custom/include/MVC/Controller/SugarController.php'); } if (class_exists('CustomSugarController')){ $controller = new CustomSugarController(); } else { $controller = new SugarController(); } } //setup the controller $controller->setup($module); }
从代码分析,ControllerFactory按照下列顺序寻找控制器类:
问:如何获取action参数?如果action参数不存在,如何处理?
答:action参数对应到SugarController的$action实例变量,该实例变量默认值为index:
class SugarController{ /** * The name of the current action. */ public $action = 'index'; }
当控制器setup()时调用loadPropertiesFromRequest()获取$_REQUEST中的action参数:
public function setup($module = ''){ ...... //set properties on the controller from the $_REQUEST $this->loadPropertiesFromRequest(); //load the mapping files $this->loadMappings(); } private function loadPropertiesFromRequest(){ if(!empty($_REQUEST['action'])) $this->action = $_REQUEST['action']; if(!empty($_REQUEST['record'])) $this->record = $_REQUEST['record']; if(!empty($_REQUEST['view'])) $this->view = $_REQUEST['view']; if(!empty($_REQUEST['return_module'])) $this->return_module = $_REQUEST['return_module']; if(!empty($_REQUEST['return_action'])) $this->return_action = $_REQUEST['return_action']; if(!empty($_REQUEST['return_id'])) $this->return_id = $_REQUEST['return_id']; }
也就是说,action参数首选会从$_REQUEST['action']获取,如果没有设置$_REQUEST['action']则使用SugarController的默认值index。
问:SugarController中如何装入Mapping文件?
答:控制器中有一个loadMapping()函数用来装入Mapping文件。该函数在控制器的setup()函数中被调用:
public function setup($module = ''){ ...... //load the mapping files $this->loadMappings(); } private function loadMappings(){ $this->loadMapping('action_view_map'); $this->loadMapping('action_file_map'); $this->loadMapping('action_remap', true); }
控制器允许会从多个地方寻找Mapping文件:
private function loadMapping($var, $merge = false){ if ($merge && !empty($this->$var)){ $$var = $this->$var; } else { $$var = array(); } if(file_exists('include/MVC/Controller/'. $var . '.php')){ require('include/MVC/Controller/'. $var . '.php'); } if(file_exists('modules/'.$this->module.'/'. $var . '.php')){ require('modules/'.$this->module.'/'. $var . '.php'); } if(file_exists('custom/modules/'.$this->module.'/'. $var . '.php')){ require('custom/modules/'.$this->module.'/'. $var . '.php'); } if(file_exists('custom/include/MVC/Controller/'. $var . '.php')){ require('custom/include/MVC/Controller/'. $var . '.php'); } // entry_point_registry -> EntryPointRegistry $varname = str_replace(" ","",ucwords(str_replace("_"," ", $var))); if(file_exists("custom/application/Ext/$varname/$var.ext.php")){ require("custom/application/Ext/$varname/$var.ext.php"); } if(file_exists("custom/modules/{$this->module}/Ext/$varname/$var.ext.php")){ require("custom/modules/{$this->module}/Ext/$varname/$var.ext.php"); } $this->$var = $$var; }
loadMapping()函数在最后会将装入的Mapping映射为控制器的实例变量。
问:控制器中如何实现URL重定向?
答:SugarController中定义了一个实例变量redirect_url:
class SugarController { /** * url to redirect to */ public $redirect_url = ''; }
在Action方法中设置$redirect_url就可以实现URL重定向。例如:
function action_redirect() { $this->redirect_url = 'http://www.baidu.com/'; |
这是因为SugarController使用execute()函数处理请求,在该函数末尾有检查$redirect_url是否有设值。若有设值,则调用SugarApplication::redirect()跳转:
final public function execute() { try { $this->process(); if(!empty($this->view)) { $this->processView(); } elseif(!empty($this->redirect_url)) { $this->redirect(); } } catch (Exception $e) { $this->handleException($e); } } protected function redirect(){ if (!empty($this->redirect_url)) SugarApplication::redirect($this->redirect_url); }
如果不在控制器中要实现URL重定向,就应该用SugarApplication::redirect()函数。
问:控制器如何自动读取Bean?
答:如果请求参数中有record存在,则SugarController会自动读取后台数据到实例变量$bean中。首先控制器要从$_REQUEST获取record参数到$this->record:
public function setup($module = ''){ ...... //set properties on the controller from the $_REQUEST $this->loadPropertiesFromRequest(); } private function loadPropertiesFromRequest(){ ...... if(!empty($_REQUEST['record'])) $this->record = $_REQUEST['record']; }
然后,控制器在处理请求时通过在process()函数中调用loadBean()实现读取Bean:
public function process(){ ...... $this->loadBean(); } public function loadBean() { if(!empty($GLOBALS['beanList'][$this->module])){ $class = $GLOBALS['beanList'][$this->module]; if(!empty($GLOBALS['beanFiles'][$class])){ require_once($GLOBALS['beanFiles'][$class]); $this->bean = new $class(); if(!empty($this->record)){ $this->bean->retrieve($this->record); if($this->bean) $GLOBALS['FOCUS'] = $this->bean; } } } }
从loadBean()代码可以发现,要自动装入Bean需要定义$GLOBALS['beanList']和$GLOBALS['beanFiles']。默认的定义在include/modules.php:
// index.php // require_once('include/entryPoint.php') // require_once('include/modules.php'); $beanList['Leads'] = 'Lead'; $beanFiles['Lead'] = 'modules/Leads/Lead.php';
问:控制器如何处理action_remap?
问:控制器如何处理action_file_map和action_view_map?
问:控制器如何检查用户请求的权限?例如谁人可以执行数据库的备份和恢复处理?