一週試用yii開發一個帶各種該有功能的web程式(三)

CL.TANG發表於2016-10-18

  接上篇,為什麼index 模版裡沒有任何有關require,inculde型別關鍵字,卻任然有我們認為“多餘”的字元出現。因為在至少我的認知裡html的結構該是<html><head></head><body></body></html>這樣的,而index.php模版中存在這樣的結構,而如果那裡採用特殊技術的話會不會存在html標籤在包含html標籤,那就不是一個標準的html文件了。而我們檢視原始碼生成的html原始碼時也發現了該html原始碼內容為:

    <div id="content">
    <html>
<head>
</head>
<body>
<center>這是我自己的第一個頁面,雖然將原來的大段內容刪除了。不在是一個部落格</center>
<a href="/admin/post/index/">指向admin/post/index.php的內容</a>
</body>
</html></div><!-- content -->

    <div class="clear"></div>

即現在生成的頁面是由一些其他頁面加上我們自己的index.php結合生成的!

但是,他是在那裡實現的呢?

先看我們的控制器:

class SiteController extends Controller
{
    public function actions()
    {
        return array(
            // captcha action renders the CAPTCHA image displayed on the contact page
            'captcha'=>array(
                'class'=>'CCaptchaAction',
                'backColor'=>0xFFFFFF,
            ),
            // page action renders "static" pages stored under 'protected/views/site/pages'
            // They can be accessed via: index.php?r=site/page&view=FileName
            'page'=>array(
                'class'=>'CViewAction',
            ),
        );
    }

    /**
     * This is the default 'index' action that is invoked
     * when an action is not explicitly requested by users.
     */
    public function actionIndex()
    {

        $this->render('index');
    }

這裡的actionIndex就是我們訪問localhost/index.php要呼叫的方法。但是我們的除了自己編寫的那點程式碼外,其他的模版呢?

可以檢視父類,有沒有一種可能,在做控制器例項化或者其他操作時呼叫了那個其他模版的程式,然後,index.php的內容作為一個執行後的string引數傳入進去最終得到我們想要的頁面?

class Controller extends CController
{
    /**
     * @var string the default layout for the controller view. Defaults to '//layouts/column1',
     * meaning using a single column layout. See 'protected/views/layouts/column1.php'.
     */
    public $layout='//layouts/column1';

這裡可以注意到有$layout。

最終我們定位到layout資料夾,如下圖:

column1.php的內容有:

<?php $this->beginContent('//layouts/main'); ?>
<div id="content">
    <?php echo $content; ?>
</div><!-- content -->
<?php $this->endContent(); ?>

這裡已經有一些眉目了,可以看到<div id="content">了,因為我們知道id屬性在html中的單一頁面是唯一的,而我們剛才檢視html頁面也有一個<div id="content">,那麼肯定是在呼叫actionIndex這個控制器方法的時候會將返回的字串作為變數名為$content的變數賦值給另外一個作用模組,而這個作用模組主要是頁面佈局。由此,可以分析出protected/component/Controller.php的類我們也可以模擬編寫出來一個其他的頁面佈局,讓我們的邏輯控制器(如SiteController.php)來繼承,達到更換佈局,而展示內容不變的目的,此為推斷,後面我會給出示例。

  由上面一些推斷,總結出yii的裝飾功能。

  要完成只顯示我們自己的頁面。可以將column1.php檔案修改為

<?php //$this->beginContent('//layouts/main'); ?>
<div id="content">
    <?php echo $content; ?>
</div><!-- content -->
<?php //$this->endContent(); ?>

當然編碼問題也要注意,在index.php中加入<meta content="text/html;charset=utf-8" http-equiv="Content-Type"/>就會如願看到:

 

現在看$this->beginContent和$this->endContent()到底為我們做了什麼工作。

 

1. 首先需要明確這裡的$this指的是什麼,這個變數當然指的是控制器。

  修改columns.php的內容為:

  

<?php //$this->beginContent('//layouts/main'); ?>
<div id="content">
    <?php print_r($this) ?>
    <?php echo $content; ?>
</div><!-- content -->
<?php //$this->endContent(); ?>

  有圖為證:

  也就是說,beginContent和endContent也是我們的SiteController的一個方法,檢視沒有,那麼一定是父類方法了。

2. 分析/frameworks/web/CBaseController.php的內容。

  

    public function beginContent($view=null,$data=array())
    {
        $this->beginWidget('CContentDecorator',array('view'=>$view, 'data'=>$data));
    }

  檢視到這個罪魁禍首了。追根溯源,通過一堆工廠實現類方法呼叫可以檢視到最終會彙集到/framework/web/CContentDecorator.php檔案。

  CContentDecorator.php核心:

  

    protected function decorate($content)
    {
        $owner=$this->getOwner();
        if($this->view===null)
            $viewFile=Yii::app()->getController()->getLayoutFile(null);
        else
            $viewFile=$owner->getViewFile($this->view);
        if($viewFile!==false)
        {
            $data=$this->data;
            $data['content']=$content;
            return $owner->renderFile($viewFile,$data,true);
        }
        else
            return $content;
    }

即$this->beginContent("layout_path"),這裡可以看到一個關鍵點是'content',即為什麼我們要使用$content在模版中進行展示了。

那麼更重要的main.php中控制的資料該展示在何處?

原來的main.php中的內容:

    <?php endif?>

    <?php echo $content; ?>

    <div class="clear"></div>

    <div id="footer">
        Copyright &copy; <?php echo date('Y'); ?> by My Company.<br/>
        All Rights Reserved.<br/>
        <?php echo Yii::powered(); ?>
    </div><!-- footer -->

</div><!-- page -->

</body>
</html>

注意main.php中也存在這個$content

所以,將該內容移動到Copyright下,檢視頁面已經出現變化了。

  即在main.php中也是通過$content來進行控制。

 

但是在這裡除了頁面的除錯佈局外,當我們想檢視某個類的某個方法是否存在時,有沒有更好的處理方法呢?下篇處理該問題吧。

相關文章