[Wacow] 處理 Request 的方式

分類: 技術分享 作者: jaceju

22 4 月 2009

Wacow

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 {
                // 導向其他頁面
            }
        }
    });
});

這樣的方式是不是很簡單呢?希望這樣的介紹能給大家帶來更棒的想法。

我要留言

關於這裡

這個部落格分享了哇寶在電子商務領域的技術及資訊,希望能讓更多人一起為台灣的網路產業加油。