Controller

第一節

什麼是controller?

controller是用來管理應用程式裡的邏輯部分。 說更白一點,controller是用來管理一個model的邏輯。 例如,如果要建立一個管理影片的網站,應該會負責管理影片和租金的邏輯,就叫VideoController和RentalController。 Cake裡的controller名稱通常是複數

程式裡的controller是一個繼承自AppController的類別。 Controller可以含有很多的Action,這些Action就是程式中呼叫顯示畫面的函式。

譯註:這些Action同時也是web應用程式用來回應使用者request的地方

AppController類別被定義在/app/app_controller.php內,含有的方法可有讓多個controller共用。 而它本身則繼承自Cake標準函式庫內的Controller類別。

Action就是controller裡的一個單一功能。當一個URL經過路由機制的解析後,會由 Dispatcher負責自動執行controller的Action。回到影片網站的例子,我們的VideoController應該 會包含view(),rent(),和search()等Action。這個controller會被定義在 /app/controllers/videos_controller.php中,程式碼像這樣:

class VideosController extends AppController
{
    function view($id)
    {
        //action logic goes here..
    }

    function rent($customer_id, $video_id)
    {
        //action logic goes here..
    }

    function search($query)
    {
        //action logic goes here..
    }
}

使用下面所列的URL可以使用這些Action:

http://www.example.com/videos/view/253
http://www.example.com/videos/rent/5124/0-235253
http://www.example.com/videos/search/hudsucker+proxy

但這些網頁看起來會長什麼樣子呢?我們還需要為每個Action定義一個view,下一章會 仔細說明,請拿出您的耐心,好好等待。這章我們會教您Cake的controller是多麼強桿,並教 您如何使用它。您會學到如果讓你的controller把資料交給view,轉交給使用者等等。

第二節

Controller的函式

雖然這一節主要著重於Cake的Controller裡常用的函式, 但請別忘了到http://api.cakephp.org查完整的資訊。

和view互動

  • set
  • string $var
  • mixed $value

這個函式是用來把資料從controller傳到view最主要的方法。這函式可以把任何東西傳過去,從單一值到整個陣列皆可。 一但用過set()之後,view裡就可以存取這個變數。例如,在controller執行set('color','blue),view裡就多出一個變數叫$color。

  • validateErrors

傳回儲存失敗時產生的錯誤

  • validate

使用model的驗証規則驗証model的資料。詳細資料請看"資料驗証"一章。

  • render
  • string $action
  • string $layout
  • string $file

這個函式會在每個controller的Action結束後自動被呼叫,然後以這個Action被命名的view就會被畫上去, 所以通常不會用到它。你也可以用這個函式在controller的任何一個地方把view畫上去。

使用者重新導向

  • redirect
  • string $url

用這個函式來告訴你的使用者接者要去那裡。URL變數可以填Cake內部的URL,也可以填完整的URL(http://....)。

  • flash
  • string $message
  • string $url
  • int $pause

這個函式會在快顯的layout(定義在app/views/layouts/flash.thtml)中顯示$message, 暫停幾秒,然後將使用者重導到$url指定的地方。

Cake的redirect()flash() 二個函式並不會呼叫exit()。如果要讓程式在redirect()flash()停止,必需在二個函式之後立該呼叫exit()。 在不同的情形下,也有可能想要return而不是要exit()(例如,可能需要執行一些回呼函式)

Controller 的回呼函式

Cake的controller提供了相當多的回呼函式讓您在重要Action之前和之後有機會做些事。 想要使用它們,只要在controller裡宣告這些函式,自然可以使用傳入的參數和傳回值。

  • beforeFilter

在controller的每一個Action之前呼叫。這是檢查session和使用者的好地方。

  • afterFilter

每個Action之後呼叫。

  • beforeRender

在Action執行完成之後,要畫view之前呼叫。

其他有用的函式

這些都是Cake裡Object類別的函式,而他們同樣都可以在Controller裡使用:

  • requestAction
  • string $url
  • array $extra

這函式可以允許你在任何地方呼叫controller的Action,傳回畫好的view。 $url是Cake的URL(/controllername/actionname/params)。 如果$extra陣列含有'return'鍵,controller Action的AutoRender會自動被設成true。

可以透過requestAction從其他controller的Action取得資料,或從controller取得完整個畫面。

我們只要在view裡任何需要資料的地方呼叫requestAction就可以很輕易的取得資料。

// Here is our simple controller:

class UsersController extends AppController
{
    function getUserList()
    {
        return $this->User->findAll();
    }
}

想像一下我們需要建立一個簡單的表單顯示系統內的使用者。 為了避免在另一個controller內再重寫同樣的程式碼,我們可以直接使用requestAction()來呼叫UsersController::getUserList()。

class ProductsController extends AppController
{
    function showUserProducts()
    {
        $this->set('users', $this->requestAction('/users/getUserList'));

        // 現在,view裡的$user變數裡會有來自UsersController::getUserList()
        // 的資料。
    }
}
 

如果程式裡有個很常用的元素,內容又不是固定的,則可以利用requestAction()取回它的view再放到畫面上。 如果$extra陣列含有'return'鍵則會把整個畫面一併傳回,而不單單只是把資料由UsersController::getUserList傳回, 我們真正需要的也就是要那個Action的畫面(裡頭可能含有一個表格)。 這麼做省下不少寫重覆程式碼的時間。

class ProgramsController extends AppController
{
    function viewAll()
    {
        $this->set('userTable', $this->requestAction('/users/getUserList', array('return')));

        // 現在我們可以在view裡echo $userTable,畫面上就會顯示/users/getUserList
        // 會畫出來的畫面
    }
}

請注意一點,透過requestAction()呼叫的Action會被畫在空的layout上, 所以不必擔心layout會被畫在layout裡的問題。

使用AJAX時requestAction()最有用,因為AJAX常常需要在更新時顯示部分畫面。

  • log
  • string $message
  • int $type = LOG_ERROR

可以用這個函式把web應用程式內所發生的任何事件記錄下來。 記錄的結果會被放在Cake的/tmp目錄下。

如果$type和PHP的LOG_DEBUG常數相同,訊息就會被常成除錯訊息記起來。 其他類則都被當作錯誤記錄。

// 在controller裡可以使用log()寫內容:

$this->log('Mayday! Mayday!');

//Log entry:

06-03-28 08:06:22 Error: Mayday! Mayday!

$this->log("Look like {$_SESSION['user']} just logged in.", LOG_DEBUG);

//Log entry:

06-03-28 08:06:22 Debug: Looks like Bobby just logged in.
  • postConditions
  • array $data

把$this->data傳進入,它會把資料轉成model使用的格式傳回。

例如,有一個找人的表單:

// app/views/people/search.thtml:

<?php echo $html->input('Person/last_name'); ?>

提交表單後,結果會放在$this->data陣列中,內容像這樣:

Array
(
    [Person] => Array
    (
        [last_name] => Anderson
    )
)

此時,我們可以使用postConditions()把資料改變,讓model使用:

// app/controllers/people_controller.php:

$conditions = $this->postConditions($this->data);

// 呼叫後傳回的陣列長的像這樣:

Array
(
    [Person.last_name] => Anderson
)

// 這種格式可以直接傳入model的查詢函式內查詢:

$this->Person->findAll($conditions);

第三節

Controller的變數

控制controller裡的一些特殊變數可以開啟Cake額外的功能:

$name

PHP 4無法得知目前這個類別的名稱。如果執行上遇到什麼問題,可以試試把這個變數 設成類別名稱。

$uses

你的controller同時使用二個以上的model嗎? FragglesController會自動載入$this->Fraggle,如果你也想取用$this->Smurf, 試試把下面的程式放到你的controller中:

var $uses = array('Fraggle','Smurf');

注意這裡同時也要把Fraggle也放進來。

$helpers

用這個變數叫你的controller把helpler載到它的view裡。 HTML helper會自動載入,要載入其他的,就得透過這個變數:

var $helpers = array('Html','Ajax','Javascript');

記住這裡也要把HTML Helper放進入,如果你還要使用它。 在沒定義$helper時,controller會自動載入它,一但定義了$helpers,就不會自動載入了。

$layout

在此設定這個controller要使用的layout。

$autoRender

如果把這個值設成false,所有Action完成後將不會自動把畫面輸出。

$beforeFilter

如果想在Action執行前做一點別的事,就可以用這個變數。 這個變數很好用,你可以在Action執行前先看看使用者權限是否足夠。 只要把Action發生前想要執行的函式名稱放在陣列內就行了:

class ProductsController extends AppController
{
    var $beforeFilter = array('checkAccess');

    function checkAccess()
    {
        //檢查使用者的程式放這兒....
    }

    function index()
    {
        //當這個Action被呼叫前,checkAccess()會先被呼叫。
    }
}

$components

就和$helpers 與 $uses一樣,這個變數會把需要的compoment載入:

var $components = array('acl');

Section 4

Controller 的參數

Controller的參數放在Cake controller的$this->params。 這個變數用來取得傳入controller的資料,存取目前request的資訊。 $this->params最常用在讀取透過POST和GET傳進controller的訊息。

$this->data

用來處理從HTML Helper表單傳過來的POST資料。

// 用來建立表單元件的 HTML Helper

$html->input('User/first_name');

// 畫成HTML時,看起來像這樣:

<input name="data[User][first_name]" value="" type="text" />

// 透過POST提交到controller時,則出現在
// $this->data['User']['first_name']

Array
(
    [data] => Array
        (
            [User] => Array
                (
                    [username] => mrrogers
                    [password] => myn3ighb0r
                    [first_name] => Mister
                    [last_name] => Rogers
                )

        )
)
 

$this->params['form']

任何一個表單所傳過來的POST資料都放在這裡,同樣的資料也可以在$_FILES找到。

$this->params['bare']

如果現在的layout是空的,就存'1',不是就存'0'。

$this->params['ajax']

如果現在的layout是AJAX就存'1',否則就存'0'。

$this->params['controller']

存放目前處理request的controller名稱。例如,URL /posts/view/1被呼叫時, $this->params['controller']會等於"posts"。

$this->params['action']

存放目前處理request的Action名稱。例如,若URL /posts/view/1被呼叫, $this->params['action']會等於'view'。

$this->params['pass']

存放目前request的GET字串。例如,若URL /posts/view/?var1=3&var2=4被呼叫, $this->params['pass'] 會等於"?var1=3&var2=4"。

$this->params['url']

以鍵-值的格式存放目前的URL。例如,如果URL是/posts/view/?var1=3&var2=4, $this->params['url'] 長得像這樣:

[url] => Array
(
    [url] => posts/view
    [var1] => 3
    [var2] => 4
)

附錄:讀者筆記

回呼函式使用注意 

liaosankai說:回呼函式像beforeFilter、afterFilter、beforeRender等…使用上必需注意一點就是,所指定呼叫的function不得宣告為private,則否將無法正常運作。以上心得提醒大家