Controller ( Yii Framework )

在mvc的controller,主要是處理邏輯部份,會依照不同的path、參數、method…等,決定要處理的資料,以及要回傳什麼資訊給user。在Yii的controller都繼承至CController,需要導向哪個action,會在controller裡面設定完成。

  1. Route
  2. Action
  3. Filter

Route

在Yii裡的程式進入點,都是透過project/index.php這一隻程式,在根據webApp的confifg,決定預設執行哪支controller,以及在project/protected/controllers對應的path。

例如在project/index.php裡,會指定使用哪個config:

1
2
3
$config=dirname(__FILE__).'/protected/config/main.php';

Yii::createWebApplication($config)->run();

然後在main.php的config中,可以透過defaultController指定預設controller:

1
2
3
4
return Array(
'defaultController'=>'post',
//doSomething
);

意思就是當path為根目錄時,會導向至PostController,例如url為:

1
http://localhost/

與下面url相同,會藉由r這個參數對照contoller/action(當action未指定時,預設執行actionIndex這function,也可透過defaultAction自訂):

1
http://localhost/index.php?r=post/index

對應的project/protected/controllers/PostController

1
2
3
4
5
6
class PostController extends CController {

public function actionIndex(){
//doSomething...
}
}

如果想自訂controller對應class的路徑,可使用controllerMap


自訂url對應controller和action

使用自訂的url規則,去對應controller和action,可以修改webapp的config:

1
2
3
4
5
6
7
8
9
10
11
return array(
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'post/<id:\d+>/<title:.*?>'=>'post/view',
'posts/<tag:.*?>'=>'post/index',
'<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
),
),
//doSomething...
);

nginx的config設定,將除了靜態檔案以外的request,全部導向至index.php:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
server {

listen 80 default;
server_name localhost;

access_log /var/log/nginx/localhost.access.log;

location ~* \.(js|png|jpg|gif|css|html)$ {

root /home/user/example/yii_example/yii/demos/blog;
}

location / {

index index.php index.html index.htm;
rewrite ^(.*) /index.php last;
}

location ~ \.php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
#fastcgi_param SCRIPT_FILENAME /tmp$fastcgi_script_name;
fastcgi_param SCRIPT_FILENAME /home/user/example/yii_example/yii/demos/blog$fastcgi_script_name;
include fastcgi_params;
}
}

Action

yii根據path導向至不同的controller,在透過controller指派action去處理。一般來說action可以直接寫在controller裡,也可以透過繼承CAction的方式,在controller定義此class。

在controller裡面定義action,有兩種方式:

  • 只需要讓function名稱的開頭為action,在加上action的名稱即可。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    class PostController extends CController {

    /**
    * path為
    /index.php?r=post
    /index.php?r=post/index
    **/
    public function actionIndex(){

    }

    /**
    * path為
    /index.php?r=post/create
    **/
    public function actionCreate(){

    }
    }
  • 透過actions這個function,回傳定義好的config,對應不同CAction

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class PostController extends CController {

    public function actions()
    {
    return array(
    // page action renders "static" pages stored under 'protected/views/site/pages'
    // They can be accessed via: index.php?r=site/page&view=FileName
    'page'=>array(
    'class'=>'CViewAction',
    ),
    // file path under 'protected/controllers/post/SayHelloAction'
    'sayhello'=>array(
    'class'=>'application.controllers.post.SayHelloAction',
    ),
    );
    }
    }

CAction

繼承至CAction的方式,如下:

1
2
3
4
5
6
7
class SayHelloAction extends CAction {

public function run()
{
//doSomething...
}
}

yii也提供一些現成的action可以使用,像是:

  • CCaptchaAction
    自動產生驗證碼,需要安裝php5-gd。

  • CViewAction
    可透過view這個參數,導向到不同頁面,而不需要針對每個頁面寫一個action。

Filter

yii的filter與action在controller的配置方式差不多,同樣可以在controller自訂filter的function,也可以class的方式繼承CFilter

在controller寫filter方式:

1
2
3
4
public function filterAccessControl($filterChain)
{
// call $filterChain->run() to continue filter and action execution
}

如果呼叫$filterChain->run(),將會繼續往下執行下個filter和action,反則會中斷掉。

與action在controller宣告不同的是,filter的套用,必須在controller裡定義filters這個function,回傳定義的config:

1
2
3
4
5
6
public function filters(){

return array(
"accessControl",
);
}

上面這種方式,將會套用此controller的所有action,若要套用個別action,如下:

1
2
3
4
5
6
7
public function filters(){

//將filter套用至edit和create action
return array(
"accessControl + edit, create",
);
}

如果把+替換成-,指的就是除了edit和create這兩個不套用filter,剩下全部套用。

CFilter

CFilter將會透過preFilter這個function,決定要繼續向下執行或者停止,而postFilter則是會在preFilter向下執行時,才會去呼叫。

定義一個filter:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class PerformanceFilter extends CFilter
{

public $unit;

protected function preFilter($filterChain)
{
// logic being applied before the action is executed
//print $unit;
return true; // false if the action should not be executed
}

protected function postFilter($filterChain)
{
// logic being applied after the action is executed
}
}

在controller中使用PerformanceFilter:

1
2
3
4
5
6
7
8
9
10
11
12
13
class PostController extends CController
{
......
public function filters()
{
return array(
array(
'application.filters.PerformanceFilter - edit, create',
'unit'=>'second',
),
);
}
}

filter第二個傳入參數unit,將會設定PerformanceFilter的unit值。所以除了第一個參數,會設定filter,之後的參數都會對應filter的public屬性。

Getting Started with the Yii Framework

REQUIREMENTS

實際需要使用到的:

文章中需要使用到:

INSTALL

在終端機上執行以下command:

1
2
sudo apt-get update
sudo apt-get install php5-cgi php5-fpm php5-sqlite php5-mysql nginx git

QUICK START

抓取yii的source:

1
git clone https://github.com/yiisoft/yii.git

建立一個webapp:

1
2
mkdir webapp
./yii/framework/yiic webapp webapp/

建立完後的目錄結構:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
.
├── assets
├── css
│   ├── bg.gif
│   ├── form.css
│   ├── ie.css
│   ├── main.css
│   ├── print.css
│   └── screen.css
├── images
├── index.php
├── index-test.php
├── protected
│   ├── commands
│   ├── components
│   ├── config
│   ├── controllers
│   ├── data
│   ├── extensions
│   ├── messages
│   ├── migrations
│   ├── models
│   ├── runtime
│   ├── tests
│   ├── vendor
│   ├── views
│   ├── yiic
│   ├── yiic.bat
│   └── yiic.php
└── themes
└── classic

其中assets、runtime和data,必須要讓www-data(nginx、apache)有讀、寫和執行的功能,可使用設定群組的方式,或者執行chmod -R 777 assets protected/runtime protected/data

打開nginx config:

1
sudo vi /etc/nginx/sites-enabled/default

修改以下這兩個location,設定你的webapp位置和設定fastcgi連接到php-fpm:

1
2
3
4
5
6
7
8
9
10
11
12
location / { 
root /tmp/webapp;
index index.html index.htm index.php;
}

location ~ \.php$ {
#fastcgi_pass 127.0.0.1:9000;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /tmp/webapp$fastcgi_script_name;
include /etc/nginx/fastcgi_params;
}

如果使用的是nginx和php-fpm,請檢查php-fpm的listen設定,對應上面的fastcgi_pass。檔案位置在/etc/php5/fpm/pool.d/www.conf

設定完之後,重開nginx:

1
2
3
4
sudo /etc/init.d/nginx restart

#若是php-fpm的config的有被修改到,需重啟fpm
sudo /etc/init.d/php5-fpm restart

在瀏覽上打開http://localhost/,就可以看到剛剛佈署完的結果了。