最近因為工作需要用到ZF,所以就來摸一下
Zend Framework是php裡頭其中一種Framework,因為它實作的是按照MVC架構做的,所以要先把MVC的概念看懂,
可以參考維基寫的MVC
建立目錄架構:
首先把網站目錄結構建成(目錄結構規劃不一定要參照這個方式):
Project/ application/ controllers/ models/ views/ layouts/ scripts/ library/ public/ .htaccess index.php js/ img/ css/
另外設個DNS指到Project/public這個目錄
下載Zend Framework:
接著下載Zend Framework
他有 Full 跟 minimal 兩個版本,建議是下載Full,下載下來後解壓縮並把 /(Zend_Framework)/library/Zend整個目錄複製到你的Project/library下
建立index:
我們先在Project/public底下建立一個index.php,這支index.php的用途就是把除了靜態檔案以外,把其他的request都交給Zend Framework來處理,所以記得要把Rewrite的功能開起來。
首先在Project/public底下建一個.htaccess,填入以下內容:
RewriteEngine On RewriteCond %{REQUEST_FILENAME} -s [OR] RewriteCond %{REQUEST_FILENAME} -l [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^.*$ - [NC,L] RewriteRule ^.*$ index.php [NC,L] RewriteBase /
這段Rewrite的設定就是將所有目錄、檔案以外的URL都交給index.php處理,比如http://localhost/img/a.png便會直接吐內容,如果是http://localhost/foo/bar這類的就會丟給index.php處理
RewriteCond指令定義了規則生效的條件,也就是說RewriteCond要符合才會跑RewriteRule
-s:測試路徑名稱是否存在
-l:測試路徑名稱並確認是否有一個存在的符號連接
-d:測試路徑目錄是否存在
接著要設定index.php的內容:
<?php //設定application路徑常數 define('APPLICATION_PATH', realpath(dirname( __FILE__ ) . '/../application/')); //設定環境常數(開發者) define('APPLICATION_ENVIRONMENT', 'development'); //設定時區 date_default_timezone_set('Asia/Taipei'); //設定path,PATH_SEPARATOR是一個PHP中的常數,是用來串接路徑與路徑之間的區隔符號,因為UNIX是":"、windows是";",所以直接使用PATH_SEPARATOR才不會在移植時爛掉 set_include_path(APPLICATION_PATH . '/../library' . PATH_SEPARATOR . get_include_path()); require_once 'Zend/Loader/Autoloader.php'; //呼叫Zend_Loader_Autoloader,讓Zend Framework在有load classes的能力 $autoloader = Zend_Loader_Autoloader::getInstance(); //這適用於函式庫中沒有自己加的namepsace,所以會使用預設讀Zend Framework中class所使用的字首Zend_跟ZendX_,讓Zend Framework內的class能夠自動被載入。 //setFallbackAutoloader(true)是讓寫在include_path(library)中,又沒有註冊namespace的class能被載入 $autoloader->setFallbackAutoloader(true); //呼叫前端Controller $frontController = Zend_Controller_Front::getInstance(); //設定ControllerDirectory $frontController->setControllerDirectory(APPLICATION_PATH . '/controllers'); //設定環境為開發者模式 $frontController->setParam('env', APPLICATION_ENVIRONMENT); //執行 $frontController->dispatch(); ?>
Action Controller:
先在Project/application/controllers裡面建一個IndexController.php,在Zend Framework裡可以將request都交由front controller下的dispatcher來決定要交由哪個action controller來處理,所以controller命名的方式就是URL名稱(開頭大寫)Controller.php。例如http://DNS/foo就會去執行FooController的indexAction;http://DNS/foo/bar就是執行FooController的barAction。如果將Action命名成testOneAction,則DNS會對應成test-one
接著在IndexController.php輸入以下內容:
<?php class IndexController extends Zend_Controller_Action { public function init() { //當物件建立時會自動執行此函式 } public function indexAction() { //關閉預設viewRenderer,不會去找application/views/scripts裡的template來顯示 $this->_helper->viewRenderer->setNoRender(); echo 'hello from Index#index'; } } ?>
這時只要輸入http://DNS/就可以看到畫面顯示出hello from Index#index的字串
View Script:
剛剛上述Action的作法,只是拿來測試controller是否正常執行,事實上是不符合MVC架構的,controller是拿來運算而非拿來顯示的,顯示的部份必須由view來執行!
在Zend Framework中,action controller預設都會有一個view renderer來負責顯示的工作,他會根據controller/action的名稱去找application/views/scripts/controller_name/action.phtml來顯示,例如剛剛上述的IndexController/indexAction就會去找index/index.phtml,所以先在application/views/scripts底下建一個index目錄,index的目錄裡再建一個index.phtml
再將Project/application/controllers/IndexController.php改成以下內容:
<?php class IndexController extends Zend_Controller_Action { public function init() { //當物件建立時會自動執行此函式 } public function indexAction() { //將日期儲存到Controller裡view這個物件的today變數 $this->view->today = date('Y-m-d'); } } ?>
接著輸入Project/application/views/scripts/index/index.phtml內容:
<!-- #file: Project/application/views/scripts/index/index.phtml --> <!-- 可以使用 $this->escape() 函式針對變數做HTML escape--> <h1>It's <?php echo $this->today; ?> today.</h1>
這樣http://DNS/就會顯示出日期了
URL Routing:
上面有提過Controller和Action的命名方式,現在來實作一下 http://DNS/foo 和 http://DNS/foo/bar
首先先在Project/application/controllers裡建一個FooController.php並輸入以下內容:
<?php class FooController extends Zend_Controller_Action { public function indexAction() { //關閉預設viewRenderer $this->_helper->viewRenderer->setNoRender(); echo "It's Foo#index"; } public function barAction(){ //關閉預設viewRenderer $this->_helper->viewRenderer->setNoRender(); echo "It's Foo#bar"; } } ?>
選擇View Scripts:
上述有提到view renderer來負責顯示的工作,他會根據controller/action的名稱去找符合的phtml檔,
例如上述提到的狀況,若是改成view輸出,則應該會在Project/application/views/scripts/foo/裡多出index.phtml和bar.phtml
但Action也可以直接選擇其他的view script來顯示。
例如將Project/application/controllers裡的FooController.php改成:
<?php class FooController extends Zend_Controller_Action { public function indexAction() { $this->view->msg = "Foo#index"; //把view script改成Project/application/views/scripts/foo/bar.phtml(要在所有view的變數輸入完後再做render,不然render之後才輸入的變數皆會失效) $this->render('bar'); } public function barAction(){ //使用原本的view scripts輸出 $this->view->msg = "Foo#bar"; } } ?>
Project/application/views/scripts/foo/bar.phtml:
<!-- #file: Project/application/views/scripts/foo/bar.phtml --> It's <?php echo $this->msg; ?>.
使用Layout排版:
在設計網站時,都會有一些固定的版型,比如Header或sidebar大家都長一樣,只是內容不同而已,這樣的需求可以用Zend Framework中的Layout元件來完成。
首先要使用Layout元件時,需要一開始初始化時就把元件打開,並且設定layout存放的路徑,所以必須在Project/index.php中再加入一段程式碼:
<?php //程式碼要加在Zend_Loader_Autoloader::getInstance();之後 //啟用mvc,並設定layout路徑 Zend_Layout::startMvc(array('layoutPath' => APPLICATION_PATH . '/views/layouts')); //程式碼要加在Zend_Controller_Front::getInstance();之前 ?>
接著在Project/application/views/layouts/layout.phtml
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>ZF TEST</title> </head> <body> <div id="hd"><h1>Header</h1></div> <!-- $this->layout()->content就是view script的所有輸出 --> <div id="bd"><?php echo $this->layout()->content; ?></div> <div id="ft"><small>Footer</small></div> </body> </html>
現在可以試試上述幾個已經完成測試的foo/bar就都有layout了
選擇不同的Layout:
跟view script一樣,Layout也是可以選擇的,當然你要在Project/application/views/layouts裡再建一個,比如建了一個test_layout.phtml,
只要在Controller.php裡的Action方法加上以下這段程式碼就可以了:
$this->_helper->layout->setLayout('test_layout');
關閉Layout:
如果開啟了Layout元件,但某些action不需要用到Layout,
一樣在Controller.php裡的Action方法加上以下這段程式碼就可以了:
$this->_helper->layout->disableLayout();
錯誤處理:
當寫程式時,發生問題是難免的事,Zend Framework吐出來的錯誤訊息有點亂,可以做個簡單的錯誤處理畫面,
先在Project/application/controllers/裡建一個ErrorController.php
在ErrorController.php:
<?php class ErrorController extends Zend_Controller_Action { public function errorAction() { //取得error_handler參數 $error = $this->_getParam('error_handler'); //取得Controller Response $response = $this->getResponse(); //也可以使用view script和Layout來做好看的錯誤頁面 //關閉預設viewRenderer $this->_helper->viewRenderer->setNoRender(); //停止使用Layout $this->_helper->layout->disableLayout(); switch ($error->type) { //找不到CONTROLLER case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER: //找不到ACTION case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION: //設定HttpResponseCode為404 $response->setHttpResponseCode(404); echo "<h1>Page Not Found</h1>"; default: //設定HttpResponseCode為500 $response->setHttpResponseCode(500); echo "<h1>Application Error</h1>"; } } } ?>
此時當網頁有錯誤時,便會執行ErrorController的errorAction