iWebShop 二次開發之商城後臺模板渲染流程
layouts是全域性的,即是一個網站的基礎排版,比如一個經典的三欄佈局,上(網站logo、主選單)、左(左邊選單)、右(右邊內容)。
如下圖所示:
在上面佈局的右邊即是viewContent(檢視內容),這部分內容是由使用者定義的,即我們所寫的檢視會自動插入到右邊。
那麼我們看看admin.html佈局檔案結構,開啟檔案:views/sysdefult/layouts/admin.html
如下圖所示:
我們現在看這個檔案lib/core/webapplication_class.php
找到execRequest
/** * @brief 請求執行方法,是application執行的入口方法 */ public function execRequest() { IUrl::beginUrl(); $ctrlId = IUrl::getInfo("controller"); $actionId = IUrl::getInfo('action'); IInterceptor::run("onBeforeCreateController",$ctrlId); //重點看這句,這一句主要是建立一個控制器物件,接著我們看下一段建立控制器的程式碼 $this->controller = $this->createController($ctrlId); IInterceptor::run("onCreateController",$this->controller); //以及這句程式碼 $this->controller->run($actionId); IInterceptor::run("onFinishController",$this->controller); }
重點看這句,這一句主要是建立一個控制器物件
$this->controller = $this->createController($ctrlId);
以及這句程式碼
$this->controller->run($actionId);
接著我們看建立控制器(createController)的程式碼實現:
主要看上面程式碼的這一句:/** * @brief 建立當前的Controller物件 * @param string $ctrlId 控制器ID * @return object Controller物件 */ public function createController($ctrlId) { $ctrlId = $ctrlId ? $ctrlId : $this->defaultController; $ctrlObject = null; $ctrlFile = $this->basePath."controllers/".$ctrlId.".php"; if(is_file($ctrlFile) && class_exists($ctrlId) && get_parent_class($ctrlId) == "IController") { $ctrlObject = new $ctrlId($this,$ctrlId); } //主要看這一句的new IController,這裡通過IController這個類建立一個控制器 return $ctrlObject ? $ctrlObject : new IController($this,$ctrlId); }
return $ctrlObject ? $ctrlObject : new IController($this,$ctrlId);
這裡通過IController這個類建立一個控制器。
接著我們看IController這個類的實現,開啟檔案:lib/web/controller/controller_class.php
接著找到IController中run方法中的這句程式碼$actionObj = $this->createAction($actionId);
然後我們在IController類中找到上面$this->createAction方法的實現,在createAction方法中找到這句程式碼:
$this->action = new IViewAction($this,$actionId);
現在我們看IViewAction類的實現,開啟檔案:lib/web/action/view_action.php
找到IViewAction類中的run方法中的這句程式碼$controller->render($this->view);
乍一看,我們現在又要回到控制器類了,開啟檔案:lib/web/controller/controller_class.php
找到render方法中的這句程式碼$output = $this->renderView($view,$data,$return);
renderView方法的實現可以在控制器基類中找到,開啟檔案:lib/web/controller/controller_class.php
然後再在renderView方法中找到這句程式碼:
$layoutFile = $this->getLayoutFile().$this->extend;
哈哈...我們終於找到了生成佈局檔案的入口點了。
然後getLayoutFile的實現又在controllerbase的子類中實現
開啟檔案:lib/web/controller/controller_class.php就可找到getLayoutFile的實現,程式碼如下:
/**
* @brief 獲取layout檔案路徑(無副檔名)
* @return string layout路徑
*/
public function getLayoutFile()
{
//$this->layout這句是一定要注意的,佈局的檔名是使用者自己寫控制器的時候繼承IController時賦值的,
//換而言之就是使用者去定義佈局檔名是什麼。
if(!$this->layout)
return false;
return $this->getViewPath().$this->defaultLayoutPath.DIRECTORY_SEPARATOR.$this->layout;
}
下面是renderView的完整實現:
/**
* @brief 渲染處理 交流QQ:82530662
* @param string $viewFile 要渲染的頁面
* @param string or array $rdata 要渲染的資料
* @param boolean $return 是否返回路徑名稱
*/
public function renderView($viewFile,$rdata=null,$return=false)
{
//要渲染的檢視
$renderFile = $viewFile.$this->extend;
//檢查檢視檔案是否存在
if(is_file($renderFile))
{
//控制器的檢視(需要進行編譯並且生成可以執行的php檔案)
if(stripos($renderFile,IWEB_PATH.'web/view/')===false)
{
//生成檔案路徑
$runtimeFile = str_replace($this->app->getBasePath(),$this->app->getRuntimePath(),$viewFile.".php");
//layout檔案
$layoutFile = $this->getLayoutFile().$this->extend;
$issetLayout= is_file($layoutFile);
if($this->isRanderCache == false || !is_file($runtimeFile) || (filemtime($renderFile) > filemtime($runtimeFile)) || ($issetLayout && (filemtime($layoutFile) > filemtime($runtimeFile))))
{
//獲取view內容
$viewContent = file_get_contents($renderFile);
//處理layout
if($issetLayout && stripos($viewContent,"<html") === false)
{
$viewContent = $this->renderLayout($layoutFile,$viewContent);
}
//標籤編譯
$inputContent = $this->tagResolve($viewContent);
//建立檔案
$fileObj = new IFile($runtimeFile,'w+');
$fileObj->write($inputContent);
$fileObj->save();
unset($fileObj);
}
}
else
{
$runtimeFile = $renderFile;
}
return $return ? $runtimeFile : $this->requireFile($runtimeFile,$rdata);
}
else
{
return false;
}
}