[Wacow] 處理 Request 的方式

這篇是在講 Wacow Framework ,是寫給同事看的一篇技術文章;如果你沒用到它,請直接跳過吧。
Wacow Framewok 在這裡找得到,它仍在進化中。
前端部份
一般非表單 AJAX
如果是用連結或其他非表單元素來啟動 AJAX ,那麼就可以使用 jQuery 內建的 $.ajax 方法,範例如下:
$(function () { $('a').click(function () { var link = this; $.ajax({ url: link.href, type: 'post', dataType: 'json', beforeSend: function () {}, error: function (xhr, status, e) {}, success: function (json) {} }); return false; }); });
這樣連結就不會執行預設的頁面導向,而只會處理 AJAX 的部份。
注意 dataType 只是給 jQuery 用來判斷 Server 端回傳回來的資料可能是什麼格式,它並不能控制 Server 要回傳什麼格式回來。如果我們要控制 Wacow 回傳回來的資料格式,要在網址後面加上 /format/json 或 /format/html (目前僅支援 JSON 與 HTML 兩種格式) 。
註:因為 /format/json 是網址參數的部份,所以前面還是要補上完整的 controller 與 action ;否則就要改用 ?format=json 這樣的格式。
表單 AJAX
如果是表單要使用 AJAX 的話,首推 jQuery Form Plugin ,不僅用法簡單,而且功能強大。 Form Plugin 使用的 ajaxForm 及 ajaxSubmit 方法,其參數物件跟 jQuery 內建的 $.ajax 方法所需要的參數物件是一樣的。範例如下:
$(function () { $('#formId').ajaxForm({ dataType: 'json', beforeSubmit: function () {}, // 同 $.ajax 方法的 beforeSend 選項 error: function (xhr, status, e) {}, success: function (json) {} }); });
另外使用 Form Plugin 最大的好處之一,就是它會幫我們自動處理檔案上傳的部份,更強大的是它支援多檔上傳 (其他 Plugin 只能做到單一檔案上傳,而且還不能把其他非檔案欄位一併傳上) 。而後端的 PHP 程式就照一般的寫法開發即可,真的可說是超完美的 Plugin 。
後端部份
處理回傳值
其實在 Wacow 後端可以直接使用 $_GET 、 $_POST 、 $_COOKIE 及 $_FILES 等這種預設的超全域變數;所以在 Action Controller 中,我們可以直接處理它們。例如:
class IndexController extend App_Controller_Action { public function indexAction() { var_dump($_GET, $_POST, $_FILES, $_COOKIE); } }
不過這裡建議使用 Zend Framework 內建的 Request 物件所產生的陣列,這樣可以避開索引未設定的錯誤,例如:
class IndexController extend App_Controller_Action { public function indexAction() { $username = $this->getRequest()->getPost('username'); // 沒有 username 這個 key 時,就回傳 null 值。 } }
其他還有 getQuery() (對應 $_GET) 、 getCookie() (對應 $_COOKIE) 、 getServer() (對應 $_SERVER) 及 getEnv() (對應 $_ENV ) 等方法 (但注意沒有 getFile() 這個方法) 。
如果是使用 /key/value 這種參數型態的話,就要改用 getParam() 。
註: Zend Framework 並沒有幫我們處理 magic_quotes 的問題,你自己得小心。建議把 magic_quotes 關掉。
同一頁處理 POST 回傳
Wacow 的 Action Controller 提供兩個方法來判斷是否為 POST 回傳: isPost() 及 isAjax() 。
isPost() 是以 $_SERVER 變數的 REQUEST_METHOD 是否為 POST 為依據,但一般採用 POST 的 AJAX Request 也會有這個值;所以如果需要特別指定是否為 AJAX Request ,就要用 isAjax() 來判斷, isAjax() 會判斷 Request Header 的 X_REQUESTED_WITH 屬性值是否為 XMLHttpRequest (大多數瀏覽器產生的 XMLHttpRequest 都會丟出這個 HEADER ) 。
用法如下:
class IndexController extend App_Controller_Action { public function indexAction() { if ($this->isPost()) { // 處理回傳值 $username = $this->getRequest()->getPost('username'); } // 處理一般頁面輸出 } }
這樣一來,我們可以同時在一個 action 中,處理頁面及頁面本身所回傳的資訊。
不同的回傳格式
如果我們在前端沒有用 format 特別指定回傳格式的話,那麼一般 POST 回傳的 View 格式會是 HTML ,而 AJAX 回傳的格式則會是 JSON 。例如:
class IndexController extend App_Controller_Action { public function indexAction() { echo get_class($this->view); // 如果未指定 format 時,執行結果可能有以下兩種: // Wacow_View_Html_Smarty // 一般 POST // Wacow_View_Json // 採用 AJAX } }
這是 Wacow 預設的 View 處理方式。
不過就像上面提過的,我們可以利用 format 來改變 View 輸出的格式;這裡就看各位需要的格式是什麼了。
特別要注意的是如果用到了 Form Plugin 來做 AJAX 檔案上傳時,因為 Form Plugin 會透過 iframe 來處理 AJAX 動作,所以實際上 isAjax() 並不回傳 true 。這時如果需要回傳 JSON 格式的資料,那麼就要前端的 AJAX url 後加上 /format/json (別忘了 controller 和 action ) ,並在後端改用 isPost() 判斷。
表單驗證範例
一般在處理表單驗證時,都會使用 JavaScript 在前端先行驗證的方式。不過這樣的風險在於使用者關掉 JavaScript ,或是根本不透過我們的頁面來送出表單時,我們所得到的資料其實都有潛在的危險性。
所以這裡我會建議直接採用伺服端驗證的方式來處理,然後以 AJAX 的方式來呈現在瀏覽器端。
註:當然如果簡單的驗證還是可以先以 JavaScript 處理,以避免多次的 Request 及 Response 。
先來看看後端範例寫法:
class IndexController extend App_Controller_Action { public function indexAction() { $error = false; $messenger = $this->pageMessenger; /* @var $messenger Wacow_Controller_Action_Helper_PageMessenger */ if ($this->isPost()) { $filter = new Zend_Filter_StripTags(); $username = $filter->filter(trim($this->getRequest()->getPost('username'))); $password = $filter->filter(trim($this->getRequest()->getPost('password'))); if ('' === $username) { $error = true; $messenger->addMessage('請輸入帳號'); } if ('' === $password) { $error = true; $messenger->addMessage('請輸入密碼'); } if (!$error) { // 這裡我採用的是 error 判斷法 // 進行帳號密碼都有輸入的處理 // 然後導向到其他頁 (不一定需要) } } // 處理一般頁面輸出 // ... // 處理錯誤訊息 $this->view->error = $error; $this->view->messages = $messenger->getMessages(); } }
註: PageMessenger 是 Wacow Framework 提供的,用法同 Zend Framework 的 FlashMessenger ,但沒有用到 Session ,所以不能跨頁面。
如果瀏覽首頁時,就會顯示解析 index/index.tpl.htm 的內容。而如果用 AJAX 將 Request POST 到 index/index 這個網址時,就會改用 JSON 輸出,例如:
{"error":true,"messages":["\uXXXX\uXXXX\uXXXX\uXXXX\uXXXX","\uXXXX\uXXXX\uXXXX\uXXXX\uXXXX"]}
這時我們就可以用 jQuery 來處理回傳的結果了。
前端範例寫法如下:
$(function () { $('#formId').ajaxForm({ dataType: 'json', success: function (json) { if (json.error) { var message = ''; for (var i in json.messages) { message += json.messages[i] + "\n"; } alert(message); // 這裡可以用任何效果來呈現錯誤訊息,這裡我採用最簡單的 alert() } else { // 導向其他頁面 } } }); });
這樣的方式是不是很簡單呢?希望這樣的介紹能給大家帶來更棒的想法。
good job! 如果再附上一個範例就更好了。