昨天小魚遇到一個詭異的 Zend Framework 與 Smarty 整合問題,幫她解決之後,順手記一下。
在「將 Smarty 3 整合到 Zend Framework 1.11 中」一文裡,我們在 My_View_Smarty 中註冊了「 this 」這個樣版變數,目的就是讓 Smarty 可以在樣版中透過 $this 來使用 View Helper 。
不過因為 Smarty 和 Zend_View 在解析樣版時,對 $this 這個變數的解釋是不一樣的,這樣一來就會造成了一些麻煩。
重建問題
接著我們來做個小實驗,先依照「將 Smarty 3 整合到 Zend Framework 1.11 中」準備好一個已經將 Smarty 整合好的 Zend Framework 專案。
然後在 application/layouts/scripts/layout.phtml 的 head 標籤內加入以下的 Smarty 語法:
1
| |
接著在 application/views/scripts/index/index.phtml 中加入以下語法:
1
| |
最後再建立一個 application/views/scripts/test.phtml ,內容如下:
1
| |
現在瀏覽首頁,你會發現程式出現了以下的錯誤:
1
| |
這是為什麼呢?因為在原生的 Zend_View 樣版中,因為樣版是透過 include 指令來載入並解析的,所以 $this 變數就是 Zend_View 物件本身;但是在 Smarty 底下就不一樣了,在 My_View_Smarty 的建構函式裡,我們透過了以下指令來將 My_View_Smarty 物件本身指定給 Smarty 的 this 樣版變數:
1
| |
這樣一來,在 Smarty 樣版的 $this 就是一個樣版變數,而不是 View 物件本身。
然後問題來了,在 Partial View Helper 執行的過程中,竟然會把 View 物件複製出來後,再清空裡面所有指定好的樣版變數!換句話說,在透過 Partial View Helper 去呼叫的 Smarty 子樣版,會因為所有樣版變數都被清掉的關係而把 $this 當做是 null 值;這下子,對子樣版來說,當然就無法透過 $this 來呼叫 View 物件了。
而這個問題也會發生在使用 PaginationControl 這個 View Helper 上,因為它就是透過 Partial View Helper 來完成它的工作的。
該怎麼辦呢?
解決方案
答案很簡單,再告訴子樣版 $this 是什麼就好了。怎麼做呢?有兩個方法可以達成。
解法一
我們可以在 Partial View Helper 的第二個參數重新指定 $this ,如下:
1
| |
這樣一來, Partial View Helper 就會把重新把現在 Smarty 主樣版的 $this 再指定給子樣版的 $this ,所以我們就可以在子樣版裡再次利用 $this 來呼叫 View Helper 了。
而 PaginationControl View Helper 也是同樣的原理:
1
| |
不過這個解決方案就得一直在呼叫 Partial View Helper 加上指定 this 的動作,感覺上很麻煩;還好我們有第二種方式來一勞永逸地解決它。
解法二
第二個方法就是直接讓 Partial View Helper 預先把 $this 變數指向 View 物件就可以了,但我們並不需要修改 Zend Framework 的原始碼, Zend Framework 提供了一個更好的擴充方式。
首先我們建立 library/My/View/Helper/Partial.php 這個檔案,其內容如下:
1 2 3 4 5 6 7 8 9 10 | |
然後在 application.ini 中,指定自訂的 View Helper 位置:
1
| |
這樣一來,我們就可以安心地透過 Smarty 來呼叫 Partial View Helper ,而不必再加上 ['this' => $this] 了。
解法一與解法二共有的問題
這兩種解法還是有一個問題,那就是在主樣版的變數無法被傳遞到 Partial 樣版中,以下直接用例子來說明。
假設我們在 IndexController::indexAction() 中加入以下程式碼:
1 2 3 4 5 6 7 | |
在 application/views/scripts/test.phtml 中再加入:
1
| |
你會發現 test.phtml 並沒有辦法正確顯示 $data 的內容。
因此我們必須把主樣版的變數再複製一份給 Partial 樣版,所以解法一就必須修改成如下程式碼:
1 2 | |
原理就是把原來的樣版變數和 $this 變數合併後再傳給 Partial 樣版。
至於解法二的修改也是一樣:
1 2 3 4 5 6 7 8 9 10 11 | |
這樣一來就沒問題了。