Yii2的一些小坑---關於跳轉和助手類的靈活使用

YII自己的跳轉很靈活。通常的MVC出現跳轉的也不外乎:
(1)V->V   頁面以前的跳轉javascript

(2)C->V  正常的MVC方式php

(3)V->C   請求數據接口數據傳參,我仍是通常都會用JS的ajax實現html

這三種也都逃不了YII特有的方法和PHP原生的方法實現java

首先針對於v->v這種頁面直接跳轉的方式,最多見的就是超連接。git

超連接在原生的寫法中是直接寫絕對地址或ur拼接。這種在YII中因爲跳轉基本是經過controller從中實現的,這邊要注意其實這裏仍是和v->c相似,url拼接的仍是相應規則的內容(不然不少有YII引入的樣式表和JS都沒法正常表現)github

原生寫法web

<a href='index.php/index?data="abc" ' >

YII寫法ajax

<a href="<?= URL::to('index','date'=>'abc') ?>" >

或更直接的PHP風格數組

<?=HTML::a('index','date'=>'abc') ?>

看的出來這裏的URL就是C層轉向V的地址,因此咱們的V->C層代碼也不外乎這樣服務器

再來看下c->v

這一步能夠說是MVC的最經典的操做,通常其餘框架比較常見的是SMARTY傳至並訪問。這裏咱們要用的是YII的redner系列方法。例如最經常使用的

$this->render('index',[參數列表])

 

另外若是實現返回上一個頁面的效果可使用:

Yii::$app->request->referrer 或者 Yii::$app->request->getReferre()

 

這裏有幾個tips:
1.對於render其實底層實現的就是renderContent。只是將頁面的中間部分放入,包含YII的頭部和底部,這裏若是須要修改能夠換位rendiect

2.在跳轉的時候默認的是本控制器,若是須要其餘控制器能夠在前面多加一個「/」.好比我是經過DefaultController.php的index方法跳轉當前頁,若是我要去LoginController處理登陸業務的頁面,我就須要「//login/login」

簡單整理:

在yii2中,引入視圖模版文件的4種方法的區別以下:

    1)、「@app」 開頭,「@app」是一個路徑別名,對應站點根目錄。好比項目路徑爲:E:/www/yii2/,引入爲:$this->render('@app/views/site/about.php'),則對應的文件所在磁盤路徑爲:「E:/www/yii2/views/site/about.php」(能夠用var_dump(Yii::getAlias('@app'));查看@app的值)。

   2)、默認爲控制器或小部件對應默認的路徑,例如:SiteController.php中return $this->render(「about」) 對應到  @app/views/site/about.php (即:E:/www/yii2/views/site/about.php)。

   3)、「//」 開頭對應的視圖文件路徑爲 @app/views/... ,例如 //site/about 對應到 @app/views/site/about.php 。

   4)、「/」開頭表示相對於當前views目錄的位置,例如:若是當前模塊爲user,/site/about對應成@app/modules/user/views/site/about.php , 若是不是模塊,/site/about對應 @app/views/site/about.php 。注意:「//」和「/」的區別在於,「//」至關於絕對路徑,「/」至關於相對路徑。具體對好比下:

 

控制器 $this->render 模版路徑
E:/yii2/controllers/SiteController.php //site/about E:/yii2/views/site/about.php
E:/yii2/modules/user/controllers/SiteController.php //site/about E:/yii2/views/site/about.php
E:/yii2/controllers/SiteController.php /site/about E:/yii2/views/site/about.php
E:/yii2/modules/user/controllers/SiteController.php /site/about E:/yii2/modules/user/views/site/about.php

PS:若是不指定模版的後綴名,默認爲」.php」。

 

3.$this在不一樣地方的意義。在VIEW層的$this就是yii/web/view;在CONTROLLERyii/web/controller,因此不能夠在view層用render跳轉

4.對於URL**和HTML的用法

(1)YII有一些助手類,HTML是能夠生成一些HTML代碼的類。例如在上面實例中HTML::a就是生成了一個a標籤。而對於這個的實現其實就是調用內部的HTML::tag。因此也能夠直接用這個實現。舉個例子:

Html::img( '/abc/image1.jpg', [ 'alt' => '頭像' ] )

這個是一個生成HTML中img標籤,框架在實現的函數:

public static function img($src, $options = [])
    {
        $options['src'] = Url::to($src);

        if (isset($options['srcset']) && is_array($options['srcset'])) {
            $srcset = [];
            foreach ($options['srcset'] as $descriptor => $url) {
                $srcset[] = Url::to($url) . ' ' . $descriptor;
            }
            $options['srcset'] = implode(',', $srcset);
        }

        if (!isset($options['alt'])) {
            $options['alt'] = '';
        }

        return static::tag('img', '', $options);
    }

能夠看到這裏最後一行仍是返回一個靜態的tag函數:

public static function tag($name, $content = '', $options = [])
    {
        if ($name === null || $name === false) {
            return $content;
        }
        $html = "<$name" . static::renderTagAttributes($options) . '>';
        return isset(static::$voidElements[strtolower($name)]) ? $html : "$html$content</$name>";
    }

因此也能夠寫做:

<?= Html::tag('img') ?>

後面也能夠添加參數,可是注意第二個參數在img標籤的時候爲空,由於是圖像標籤沒有文字內容。圖片源和文字說明都是做爲第三個參數填入的。HTML在生成標籤的時候還有lable、button、input等等經常使用標籤。

(2)HTML助手類在使用的時候,對於標籤嵌套的時候要注意使用參數。例如在ul標籤中嵌套li的時候,li的內容要防止編碼要注意能夠在ul()使用第二個參數:

public static function ul($items, $options = [])
    {
        $tag = ArrayHelper::remove($options, 'tag', 'ul');
        $encode = ArrayHelper::remove($options, 'encode', true);
        $formatter = ArrayHelper::remove($options, 'item');
        $separator = ArrayHelper::remove($options, 'separator', "\n");
        $itemOptions = ArrayHelper::remove($options, 'itemOptions', []);

例如:
不想被轉義就應該用Html::ul($arr, ['encode' => false]);

 

(3)Url 幫助類提供一系列的靜態方法來幫助管理 URL。和HTML同樣都是助手類,在使用的時候都須要use下該類。例如:use yii\helps\Url;

關於這個類比較經常使用的就是to和toRoute

(I)關於toRoute----獲取某一地址

看下官網上的說法:

爲了建立一個給定路由的 URL 地址,請使用 `Url::toRoute()`方法。 
$url = Url::toRoute(['product/view', 'id' => 42]);

你能夠指定一個字符串來做爲路由,如: site/index 。若是想要指定將要被建立的 URL 的附加查詢參數, 你一樣可使用一個數組來做爲路由。數組的格式須爲:
// generates: /index.php?r=site/index&param1=value1&param2=value2
['site/index', 'param1' => 'value1', 'param2' => 'value2']
若是你想要建立一個帶有 anchor 的 URL ,你可使用一個帶有 # 參數的數組。好比:
// generates: /index.php?r=site/index&param1=value1#name
['site/index', 'param1' => 'value1', '#' => 'name']
一個路由既多是絕對的又多是相對的。一個絕對的路由之前導斜槓開頭(如: /site/index), 而一個相對的路由則沒有(好比: site/index 或者 index)。一個相對的路由將會按照以下規則轉換爲絕對路由:
* 若是這個路由是一個空的字符串,將會使用當前 yii\web\Controller::route 做爲路由;
* 若是這個路由不帶任何斜槓(好比 index ),它會被認爲是當前控制器的一個 action ID, 而後將會把 yii\web\Controller::uniqueId 插入到路由前面。
* 若是這個路由不帶前導斜槓(好比: site/index ),它會被認爲是相對當前模塊(module)的路由, 而後將會把 yii\base\Module::uniqueId 插入到路由前面。

如下是該方法的一些例子:
// /index.php?r=site/index
echo Url::toRoute('site/index');

// /index.php?r=site/index&src=ref1#name
echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);

// /index.php?r=post/edit&id=100     assume the alias "@postEdit" is defined as "post/edit"
echo Url::toRoute(['@postEdit', 'id' => 100]);

// http://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', true);

// https://www.example.com/index.php?r=site/index
echo Url::toRoute('site/index', 'https');

稍做整理:有第二個參數且不是URL傳遞解析的內容就會得到絕對地址,也就是包含協議域名等部分的內容

1://獲取某地址 - 相對路徑

$url = Url::toRoute('site/index');

2://獲取某地址 - 相對路徑

$url = Url::toRoute('site/index', false);

說明: 等價於1 由於默認是false

3://獲取某地址 - 相對路徑

$url = Url::toRoute(['site/index', 'id' => 1]);

4://獲取某地址的 - 絕對路徑

$url = Url::toRoute('site/index', true);

5://獲取某地址的 -絕對路徑

 

$url = Url::toRoute('site/index', ['id' => 1]);

說明: 參數沒有輸出,說明,這種寫法['id' => 1], 他當成了true,因此等價於4

 

6://獲取某地址的 - 絕對路徑 (傳輸協議-http)

$url = Url::toRoute('site/index', 'http');

7://獲取某地址的 -絕對路徑(傳輸協議-https)

$url = Url::toRoute('site/index', 'https');

(II)關於toRoute----建立一個基於給定參數的網址

一樣看下官網的說法:

還有另一個方法 Url::to() 和 toRoute() 很是相似。這兩個方法的惟一區別在於,前者要求一個路由必須用數組來指定。 若是傳的參數爲字符串,它將會被直接當作 URL 。
Url::to() 的第一個參數能夠是:
* 數組:將會調用 toRoute() 來生成URL。好比: ['site/index'], ['post/index', 'page' => 2] 。 詳細用法請參考 toRoute() 。
* 帶前導 @ 的字符串:它將會被當作別名, 對應的別名字符串將會返回。
* 空的字符串:當前請求的 URL 將會被返回;
* 普通的字符串:返回自己。

如下是一些使用示例:
// /index.php?r=site/index
echo Url::to(['site/index']);

// /index.php?r=site/index&src=ref1#name
echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);

// /index.php?r=post/edit&id=100     assume the alias "@postEdit" is defined as "post/edit"
echo Url::to(['@postEdit', 'id' => 100]);

// the currently requested URL
echo Url::to();

// /images/logo.gif
echo Url::to('@web/images/logo.gif');

// images/logo.gif
echo Url::to('images/logo.gif');

// http://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', true);

// https://www.example.com/images/logo.gif
echo Url::to('@web/images/logo.gif', 'https');

稍做整理:有第二個參數且不是URL傳遞解析的內容就會得到絕對地址,也就是包含協議域名等部分的內容,另外能夠引用配置參數是添加的別名

1): //獲某網址 - 相對路徑

$url = Url::to(['site/index']);

2): //獲取網址(帶參數) - 相對路徑

$url = Url::to(['site/index', 'id' => 1]);

3): 獲取當前路徑 - 相對路徑

$url = Url::to();

4): 獲取url - 相對路徑

$url = Url::to('@web/image/1.jpg');

說明:它將指定到你的某一個別名目錄下@web

5): 獲取url - 相對路徑

$url = Url::to('image/1.jpg');

6): 獲取url - 絕對路徑(@mobileUrl 本身配置好的)

$url = Url::to('@mobileUrl/image/1.jpg', true);

7): //獲取url -絕對路徑(傳輸協議-https)

$url = Url::to('@mobileUrl/image/1.jpg', 'https');

8): //獲取url -絕對路徑(傳輸協議-http)

$url = Url::to('@mobileUrl/image/1.jpg', 'http');
(III)current()   remember()    previous()

current() 
另外從2.0.3版本開始,你可使用 yii\helpers\Url::current() 來建立一個基於當前請求路由和 GET 參數的 URL。 你能夠經過傳遞一個 $params 給這個方法來添加或者刪除 GET 參數。

// /index.php?r=post/view&id=123&src=google
echo Url::current();

// /index.php?r=post/view&id=123
echo Url::current(['src' => null]);
// /index.php?r=post/view&id=100&src=google
echo Url::current(['id' => 100]);


記住 URLs

有時,你須要記住一個 URL 並在後續的請求處理中使用它。 你能夠用如下方式達到這個目的:

// Remember current URL 
Url::remember();

// Remember URL specified. See Url::to() for argument format.
Url::remember(['product/view', 'id' => 42]);

// Remember URL specified with a name given
Url::remember(['product/view', 'id' => 42], 'product');

在後續的請求處理中,能夠用以下方式得到記住的 URL:

$url = Url::previous();
$productUrl = Url::previous('product');

檢查相對 URLs

你能夠用以下代碼檢測一個 URL 是不是相對的(好比,包含主機信息部分)。

$isRelative = Url::isRelative('test/it');

 

5.關於render**系列的跳轉

render是最長使用的一種跳轉方法,必須填寫的參數就是跳轉去的頁面,以後若是須要將參數傳過去就能夠把參數組成數組的形式傳遞去頁面。然而有一個很明顯的問題 ,這裏不論你須要不須要都會帶着layout中的header個footer一塊兒。有疑問直接去看源碼有時候是最快的解決方法。去看下源碼:

public function render($view, $params = [])
    {
        $content = $this->getView()->render($view, $params, $this);
        return $this->renderContent($content);
    }

//上面的函數最後仍是調用的下面的方法,
 public function renderContent($content)
    {
//這裏加載了佈局方法
        $layoutFile = $this->findLayoutFile($this->getView());
        if ($layoutFile !== false) {
            return $this->getView()->renderFile($layoutFile, ['content' => $content], $this);
        }

        return $content;
    }

因此咱們能夠直接本身調用if判斷裏面的內容去實現,可是對於這地方,YII仍是有作考慮的,能夠看到一個函數:

public function renderPartial($view, $params = [])
    {
        return $this->getView()->render($view, $params, $this);
    }

這個就是實現了沒有佈局概念的跳轉或者

public function renderFile($file, $params = [])
    {
        return $this->getView()->renderFile($file, $params, $this);
    }

 

另外有資料說redirect方法是控制器內跳轉方法

public function redirect($url, $statusCode = 302, $checkAjax = true)
    {
        if (is_array($url) && isset($url[0])) {
            // ensure the route is absolute
            $url[0] = '/' . ltrim($url[0], '/');
        }
        $url = Url::to($url);
        if (strpos($url, '/') === 0 && strpos($url, '//') !== 0) {
            $url = Yii::$app->getRequest()->getHostInfo() . $url;
        }

        if ($checkAjax) {
            if (Yii::$app->getRequest()->getIsAjax()) {
                if (Yii::$app->getRequest()->getHeaders()->get('X-Ie-Redirect-Compatibility') !== null && $statusCode === 302) {
                    // Ajax 302 redirect in IE does not work. Change status code to 200. See https://github.com/yiisoft/yii2/issues/9670
                    $statusCode = 200;
                }
                if (Yii::$app->getRequest()->getIsPjax()) {
                    $this->getHeaders()->set('X-Pjax-Url', $url);
                } else {
                    $this->getHeaders()->set('X-Redirect', $url);
                }
            } else {
                $this->getHeaders()->set('Location', $url);
            }
        } else {
            $this->getHeaders()->set('Location', $url);//通常執行這裏
        }

        $this->setStatusCode($statusCode);

        return $this;
    }

從代碼看,這是直接去對地址發起請求,將獲得的結果進行處理。

再來整個梳理下:

(1)remder()

這是帶模板的跳轉,含帶header和footer

  (2) renderPartial()

  (3)renderFile()

(2)(3)是不帶模板的跳轉,實際執行的代碼同樣,能夠交替使用。

  (4)redirect()

不支持參數POST傳遞。最後依然是調用header方法.只不過,自定義控制器裏的redirect方法,是調用yii\web\Controller裏邊的redirect方法,而後調用yii\web\Response組件,而後在Response組件裏邊,調用yii\web\HeaderCollection類裏邊的get()方法,實現跳轉的.或者執行http302重定向。利用這個方法,還能夠實現外部服務器請求

 

 

 

 

另外能夠參考YIIChina的部分教程和資料,例如:http://www.yiichina.com/tutorial/819

相關文章
相關標籤/搜索