和ControllerFactory类似,ViewFactory则负责实例并初始各个模块的视图类,不过调用的视图工厂则是在各个具体控制器内。
class SugarController { ``` private function processView(){ if(!isset($this->view_object_map['remap_action']) && isset($this->action_view_map[strtolower($this->action)])) { $this->view_object_map['remap_action'] = $this->action_view_map[strtolower($this->action)]; } $view = ViewFactory::loadView($this->view, $this->module, $this->bean, $this->view_object_map, $this->target_module); $GLOBALS['current_view'] = $view; if(!empty($this->bean) && !$this->bean->ACLAccess($view->type) && $view->type != 'list'){ ACLController::displayNoAccess(true); sugar_cleanup(true); } if(isset($this->errors)){ $view->errors = $this->errors; } $view->process(); } ``` }
class ViewFactory { /** * load the correct view * @param string $type View Type * @return valid view */ function loadView($type = 'default', $module, $bean = null, $view_object_map = array(), $target_module=''){ $type = strtolower($type); // first let's check if the module handles this view $view = null; // Check to see if we should load a custom parent view instance /** * 这一步加载具体的视图类【ViewSidecar】文件,并且进而引入试图类【SidecarView】,最后引入总的视图继承类 * class ViewSidecar extends SidecarView {```} * class SidecarView extends SugarView {```} * class SugarView {```} function loadParentView($type) { SugarAutoLoader::requireWithCustom('include/MVC/View/views/view.'.$type.'.php'); } */ loadParentView($type); if(!empty($target_module)) { $view_file = SugarAutoLoader::existingCustomOne('modules/'.$target_module.'/views/view.'.$type.'.php'); $view_module = $target_module; } else { $view_module = $module; } // 下面三步,逐次提高,现在所属模块查找view文件,没有再提升到总的视图查找 // 这里侧重的是如果用户定制了视图文件,那么就加载用户定制的视图文件 // 因为existingCustomOne最后加载的视图文件[如果有的话],返回时array_pop会把此文件给弹出来 if(empty($view_file)) { $view_file = SugarAutoLoader::existingCustomOne('modules/'.$module.'/views/view.'.$type.'.php'); } if(empty($view_file)) { $view_file = SugarAutoLoader::existingCustomOne('include/MVC/View/views/view.'.$type.'.php'); } if(!empty($view_file)) { $view = ViewFactory::_buildFromFile($view_file, $bean, $view_object_map, $type, $view_module); } if(empty($view)) { // Default to SugarView if still nothing found/built $view = new SugarView(); } ViewFactory::_loadConfig($view, $type); return $view; } /** * This is a private function which just helps the getView function generate the * proper view object * * @return a valid SugarView */ function _buildFromFile($file, &$bean, $view_object_map, $type, $module){ // 第一优先级,查找HomeViewSidecar类 require_once($file); //try ModuleViewType first then try ViewType if that fails then use SugarView $class = SugarAutoLoader::customClass(ucfirst($module).'View'.ucfirst($type)); if(class_exists($class)){ return ViewFactory::_buildClass($class, $bean, $view_object_map); } // 第二优先级,查找ViewSidecar类,bingo //Now try the next set of possibilites if it was none of the above //It can be expensive to load classes this way so it's not recommended $class = SugarAutoLoader::customClass('View'.ucfirst($type)); if(class_exists($class)){ return ViewFactory::_buildClass($class, $bean, $view_object_map); } // 第三优先级,查找SugarView类 //Now check if there is a custom SugarView for generic handling // autoloader will check filesystem $class = SugarAutoLoader::customClass('SugarView', true); //if all else fails return SugarView return new $class($bean, $view_object_map); } /** * instantiate the correct view and call init to pass on any obejcts we need to * from the controller. * * @param string class - the name of the class to instantiate * @param object bean = the bean to pass to the view * @param array view_object_map - the array which holds obejcts to pass between the * controller and the view. * * @return SugarView */ function _buildClass($class, $bean, $view_object_map){ // 实例并初始化 $view = new $class(); $view->init($bean, $view_object_map); if($view instanceof SugarView){ return $view; }else return new SugarView($bean, $view_object_map); } /** * Load the view_<view>_config.php file which holds options used by the view. */ function _loadConfig(&$view, $type){ $view_config_custom = array(); $view_config_module = array(); $view_config_root_cstm = array(); $view_config_root = array(); $view_config_app = array(); $config_file_name = 'view.'.$type.'.config.php'; $view_config = sugar_cache_retrieve("VIEW_CONFIG_FILE_".$view->module."_TYPE_".$type); if(!$view_config){ $view_config_all = array('actions' => array(), 'req_params' => array(),); // 加载include/MVC/View/views/view.config.php后,$view_config会有数据 foreach(SugarAutoLoader::existingCustom( 'include/MVC/View/views/view.config.php', 'include/MVC/View/views/'.$config_file_name, 'modules/'.$view->module.'/views/'.$config_file_name ) as $file) { $view_config = array(); require $file; if(!empty($view_config['actions'])) { $view_config_all['actions'] = array_merge($view_config_all['actions'], $view_config['actions']); } if(!empty($view_config['req_params'])) { $view_config_all['req_params'] = array_merge($view_config_all['req_params'], $view_config['req_params']); } } $view_config = $view_config_all; sugar_cache_put("VIEW_CONFIG_FILE_".$view->module."_TYPE_".$type, $view_config); } $action = strtolower($view->action); $config = null; if(!empty($view_config['req_params'])){ // try the params first foreach($view_config['req_params'] as $key => $value){ if(!empty($_REQUEST[$key]) && $_REQUEST[$key] == "false") { $_REQUEST[$key] = false; } if(!empty($_REQUEST[$key])){ if(!is_array($value['param_value'])){ if($value['param_value'] == $_REQUEST[$key]){ $config = $value['config']; break; } }else{ foreach($value['param_value'] as $v){ if($v == $_REQUEST[$key]){ $config = $value['config']; break; } } } } } } if($config == null && !empty($view_config['actions']) && !empty($view_config['actions'][$action])){ $config = $view_config['actions'][$action]; } if($config != null) $view->options = $config; } }
require_once('include/MVC/View/SidecarView.php'); class ViewSidecar extends SidecarView { /** * Constructor * * @see SidecarView::SidecarView() */ public function __construct($bean = null, $view_object_map = array()) { $this->options['show_title'] = false; $this->options['show_header'] = false; $this->options['show_footer'] = false; $this->options['show_javascript'] = false; $this->options['show_subpanels'] = false; $this->options['show_search'] = false; parent::__construct($bean = null, $view_object_map = array()); } }
class SidecarView extends SugarView { ``` protected $configFileName = "config.js"; protected $configFile; public function __construct() { $this->configFile = sugar_cached($this->configFileName); parent::SugarView(); } ``` }
class SugarView { ``` /** * Constructor which will peform the setup. */ public function SugarView($bean = null, $view_object_map = array()) { $this->base_menu = SugarAutoLoader::loadExtension("menus", "application"); } public function init($bean = null, $view_object_map = array()) { $this->bean = $bean; $this->view_object_map = $view_object_map; $this->action = $GLOBALS['action']; $this->module = $GLOBALS['module']; $this->_initSmarty(); } // 加载smarty模板类 protected function _initSmarty() { $this->ss = new Sugar_Smarty(); $this->ss->assign('MOD', $GLOBALS['mod_strings']); $this->ss->assign('APP', $GLOBALS['app_strings']); } ``` }