早上在ruby-china發了個帖子,詢問“現今PHP的框架中最接近RAILS的是什么?”大部分答曰"Yii”。所以晚上回來就來學下這個框架看看。
Yii 是一個基於組件、純OOP的、用於開發大型 Web 應用的高性能 PHP 框架。
下載回來的軟件包解壓后結構如下:
- CHANGELOG, LICENSE, README, and UPGRADE text documents
- demos folder
- framework folder
- requirements folder
第一部分為更新文檔、許可(BSD許可,可以自由商用),升級文檔以及README。
demos中有四個示例:a blog, the game Hangman, a basic “Hello, World!”, and a phone book。
framework 中是使用Yii必須的框架,核心部分。
requirements 主要是檢查運行環境用的工具,另外還有一些小東西。
在WEB根目錄下,建立yii的文件夾,放入framework 和requirements ,然后打開瀏覽器訪問 http://localhost/yii/requirements,可以看到:
這是一個運行環境檢查的程序,檢查通過后就可以刪掉requirements 了。
接着往下看:
YII帶了一個類似於rails的命令行生成器:yiic 。通過這個生成器可以幫助我們快速生成網站架構和MVC相關的文件!
好吧,這一條命令就是rails new 以及 rails g等等的衍生品。
1: E:\xampp\htdocs\yii\framework>yiic
2: Yii command runner (based on Yii v1.1.10)
3: Usage: E:\xampp\htdocs\yii\framework\yiic <command-name> [parameters...]
4:
5: The following commands are available:
6: - message
7: - migrate
8: - shell
9: - webapp
10:
11: To see individual command help, use the following:
12: E:\xampp\htdocs\yii\framework\yiic help <command-name>
創建我的第一個APP--運行:
D:\xampp\htdocs>d:\xampp\php\php.exe d:\xampp\htdocs\framework\yiic webapp myblog
生成初始化的目錄結構:
1: css/ 包含 CSS 文件
2: images/ 包含圖片文件
3: themes/ 包含應用主題
4: protected/ 包含受保護的應用文件
5: yiic yiic 命令行腳本
6: yiic.bat Windows 下的 yiic 命令行腳本
7: yiic.php yiic 命令行 PHP 腳本
8: commands/ 包含自定義的 'yiic' 命令
9: shell/ 包含自定義的 'yiic shell' 命令
10: components/ 包含可重用的用戶組件
11: Controller.php 所有控制器類的基礎類
12: Identity.php 用來認證的 'Identity' 類
13: config/ 包含配置文件
14: console.php 控制台應用配置
15: main.php Web 應用配置
16: test.php 功能測試使用的配置
17: controllers/ 包含控制器的類文件
18: SiteController.php 默認控制器的類文件
19: data/ 包含示例數據庫
20: schema.mysql.sql 示例 MySQL 數據庫
21: schema.sqlite.sql 示例 SQLite 數據庫
22: testdrive.db 示例 SQLite 數據庫文件
23: extensions/ 包含第三方擴展
24: messages/ 包含翻譯過的消息
25: models/ 包含模型的類文件
接下來就可以瀏覽了:
應用設置文件在這里:protected/config/main.php
1: <?php
2:
3: // uncomment the following to define a path alias
4: // Yii::setPathOfAlias('local','path/to/local-folder');
5:
6: // This is the main Web application configuration. Any writable
7: // CWebApplication properties can be configured here.
8: return array(
9: 'basePath'=>dirname(__FILE__).DIRECTORY_SEPARATOR.'..',
10: 'name'=>'My Web Application',
11:
12: // preloading 'log' component
13: 'preload'=>array('log'),
14:
15: // autoloading model and component classes
16: 'import'=>array(
17: 'application.models.*',
18: 'application.components.*',
19: ),
20:
21: 'modules'=>array(
22: // uncomment the following to enable the Gii tool
23: /*
24: 'gii'=>array(
25: 'class'=>'system.gii.GiiModule',
26: 'password'=>'Enter Your Password Here',
27: // If removed, Gii defaults to localhost only. Edit carefully to taste.
28: 'ipFilters'=>array('127.0.0.1','::1'),
29: ),
30: */
31: ),
32:
33: // application components
34: 'components'=>array(
35: 'user'=>array(
36: // enable cookie-based authentication
37: 'allowAutoLogin'=>true,
38: ),
39: // uncomment the following to enable URLs in path-format
40: /*
41: 'urlManager'=>array(
42: 'urlFormat'=>'path',
43: 'rules'=>array(
44: '<controller:\w+>/<id:\d+>'=>'<controller>/view',
45: '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
46: '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
47: ),
48: ),
49: */
50: 'db'=>array(
51: 'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
52: ),
53: // uncomment the following to use a MySQL database
54: /*
55: 'db'=>array(
56: 'connectionString' => 'mysql:host=localhost;dbname=testdrive',
57: 'emulatePrepare' => true,
58: 'username' => 'root',
59: 'password' => '',
60: 'charset' => 'utf8',
61: ),
62: */
63: 'errorHandler'=>array(
64: // use 'site/error' action to display errors
65: 'errorAction'=>'site/error',
66: ),
67: 'log'=>array(
68: 'class'=>'CLogRouter',
69: 'routes'=>array(
70: array(
71: 'class'=>'CFileLogRoute',
72: 'levels'=>'error, warning',
73: ),
74: // uncomment the following to show log messages on web pages
75: /*
76: array(
77: 'class'=>'CWebLogRoute',
78: ),
79: */
80: ),
81: ),
82: ),
83:
84: // application-level parameters that can be accessed
85: // using Yii::app()->params['paramName']
86: 'params'=>array(
87: // this is used in contact page
88: 'adminEmail'=>'webmaster@example.com',
89: ),
90: );
這里可以修改數據庫
'db'=>array(
'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',
),
默認使用了sqlite,改成mysql 如下:
'db'=>array(
'connectionString'=>'mysql:host=localhost;dbname=webapp,
'username'=>'root',
'password'=>'toor',
),
不得不說PHP的語法真丑,
工作流程描述如下:
1. 用戶請求此 URL http://www.example.com/blog/index.php?r=site/contact;
2. 入口腳本 被網站服務器執行以處理此請求;
3. 一個 應用 的實例被創建,其配置參數為/wwwroot/blog/protected/config/main.php 應用配置文件中
指定的初始值;
4. 應用分派此請求到一個 控制器(Controller) 和一個 控制器動作(Controller action)。對於聯系
頁(Contact)的請求,它分派到了 site 控制器和 contact 動作 ( 即 /wwwroot/blog/protected/
controllers/SiteController.php 中的 actionContact 方法);
5. 應用按 SiteController 實例創建了 site 控制器並執行;
6. SiteController 實例通過調用它的 actionContact() 方法執行 contact 動作;
7. actionContact 方法為用戶䘦染一個名為 contact 的 視圖(View) 。在程序內部,這是通過包含一
個視圖文件 /wwwroot/blog/protected/views/site/contact.php 並將結果插入 布局 文件 /wwwroot/
blog/protected/views/layouts/column1.php 實現的。
配置Gii (Gii 自版本 1.1.2 可用)
為了使用 Gii,首先需要編輯文件 WebRoot/testdrive/protected/main.php,取消關於gii的注釋部分:
1: 'gii'=>array(
2: 'class'=>'system.gii.GiiModule',
3: 'password'=>'test123',
4: // If removed, Gii defaults to localhost only. Edit carefully to taste.
5: 'ipFilters'=>array('127.0.0.1','::1'),
6: ),
然后,訪問 URL http://localhost/myblog/index.php?r=gii 密碼為上面這里配置的密碼 test123。驗證通過后可以看到:
創建一個model:
這里的tbl_user表是應用默認初始建立的用戶表。
Generating code using template "D:\xampp\htdocs\framework\gii\generators\model\templates\default"... generated models\User.php done!
相關代碼(D:\xampp\htdocs\myblog\protected\models\User.php)如下:
1: <?php
2:
3: /**
4: * This is the model class for table "tbl_user".
5: *
6: * The followings are the available columns in table 'tbl_user':
7: * @property integer $id
8: * @property string $username
9: * @property string $password
10: * @property string $email
11: */
12: class User extends CActiveRecord
13: {
14: /**
15: * Returns the static model of the specified AR class.
16: * @param string $className active record class name.
17: * @return User the static model class
18: */
19: public static function model($className=__CLASS__)
20: {
21: return parent::model($className);
22: }
23:
24: /**
25: * @return string the associated database table name
26: */
27: public function tableName()
28: {
29: return 'tbl_user';
30: }
31:
32: /**
33: * @return array validation rules for model attributes.
34: */
35: public function rules()
36: {
37: // NOTE: you should only define rules for those attributes that
38: // will receive user inputs.
39: return array(
40: array('username, password, email', 'required'),
41: array('username, password, email', 'length', 'max'=>128),
42: // The following rule is used by search().
43: // Please remove those attributes that should not be searched.
44: array('id, username, password, email', 'safe', 'on'=>'search'),
45: );
46: }
47:
48: /**
49: * @return array relational rules.
50: */
51: public function relations()
52: {
53: // NOTE: you may need to adjust the relation name and the related
54: // class name for the relations automatically generated below.
55: return array(
56: );
57: }
58:
59: /**
60: * @return array customized attribute labels (name=>label)
61: */
62: public function attributeLabels()
63: {
64: return array(
65: 'id' => 'ID',
66: 'username' => 'Username',
67: 'password' => 'Password',
68: 'email' => 'Email',
69: );
70: }
71:
72: /**
73: * Retrieves a list of models based on the current search/filter conditions.
74: * @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
75: */
76: public function search()
77: {
78: // Warning: Please modify the following code to remove attributes that
79: // should not be searched.
80:
81: $criteria=new CDbCriteria;
82:
83: $criteria->compare('id',$this->id);
84: $criteria->compare('username',$this->username,true);
85: $criteria->compare('password',$this->password,true);
86: $criteria->compare('email',$this->email,true);
87:
88: return new CActiveDataProvider($this, array(
89: 'criteria'=>$criteria,
90: ));
91: }
92: }
生成 CRUD 代碼
Generating code using template "D:\xampp\htdocs\framework\gii\generators\crud\templates\default"... generated controllers\UserController.php generated views\user\_form.php generated views\user\_search.php generated views\user\_view.php generated views\user\admin.php generated views\user\create.php generated views\user\index.php generated views\user\update.php generated views\user\view.php done!
這里生成了一個control 和 8個view。
control 代碼:
1: <?php
2:
3: class UserController extends Controller
4: {
5: /**
6: * @var string the default layout for the views. Defaults to '//layouts/column2', meaning
7: * using two-column layout. See 'protected/views/layouts/column2.php'.
8: */
9: public $layout='//layouts/column2';
10:
11: /**
12: * @return array action filters
13: */
14: public function filters()
15: {
16: return array(
17: 'accessControl', // perform access control for CRUD operations
18: );
19: }
20:
21: /**
22: * Specifies the access control rules.
23: * This method is used by the 'accessControl' filter.
24: * @return array access control rules
25: */
26: public function accessRules()
27: {
28: return array(
29: array('allow', // allow all users to perform 'index' and 'view' actions
30: 'actions'=>array('index','view'),
31: 'users'=>array('*'),
32: ),
33: array('allow', // allow authenticated user to perform 'create' and 'update' actions
34: 'actions'=>array('create','update'),
35: 'users'=>array('@'),
36: ),
37: array('allow', // allow admin user to perform 'admin' and 'delete' actions
38: 'actions'=>array('admin','delete'),
39: 'users'=>array('admin'),
40: ),
41: array('deny', // deny all users
42: 'users'=>array('*'),
43: ),
44: );
45: }
46:
47: /**
48: * Displays a particular model.
49: * @param integer $id the ID of the model to be displayed
50: */
51: public function actionView($id)
52: {
53: $this->render('view',array(
54: 'model'=>$this->loadModel($id),
55: ));
56: }
57:
58: /**
59: * Creates a new model.
60: * If creation is successful, the browser will be redirected to the 'view' page.
61: */
62: public function actionCreate()
63: {
64: $model=new User;
65:
66: // Uncomment the following line if AJAX validation is needed
67: // $this->performAjaxValidation($model);
68:
69: if(isset($_POST['User']))
70: {
71: $model->attributes=$_POST['User'];
72: if($model->save())
73: $this->redirect(array('view','id'=>$model->id));
74: }
75:
76: $this->render('create',array(
77: 'model'=>$model,
78: ));
79: }
80:
81: /**
82: * Updates a particular model.
83: * If update is successful, the browser will be redirected to the 'view' page.
84: * @param integer $id the ID of the model to be updated
85: */
86: public function actionUpdate($id)
87: {
88: $model=$this->loadModel($id);
89:
90: // Uncomment the following line if AJAX validation is needed
91: // $this->performAjaxValidation($model);
92:
93: if(isset($_POST['User']))
94: {
95: $model->attributes=$_POST['User'];
96: if($model->save())
97: $this->redirect(array('view','id'=>$model->id));
98: }
99:
100: $this->render('update',array(
101: 'model'=>$model,
102: ));
103: }
104:
105: /**
106: * Deletes a particular model.
107: * If deletion is successful, the browser will be redirected to the 'admin' page.
108: * @param integer $id the ID of the model to be deleted
109: */
110: public function actionDelete($id)
111: {
112: if(Yii::app()->request->isPostRequest)
113: {
114: // we only allow deletion via POST request
115: $this->loadModel($id)->delete();
116:
117: // if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
118: if(!isset($_GET['ajax']))
119: $this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
120: }
121: else
122: throw new CHttpException(400,'Invalid request. Please do not repeat this request again.');
123: }
124:
125: /**
126: * Lists all models.
127: */
128: public function actionIndex()
129: {
130: $dataProvider=new CActiveDataProvider('User');
131: $this->render('index',array(
132: 'dataProvider'=>$dataProvider,
133: ));
134: }
135:
136: /**
137: * Manages all models.
138: */
139: public function actionAdmin()
140: {
141: $model=new User('search');
142: $model->unsetAttributes(); // clear any default values
143: if(isset($_GET['User']))
144: $model->attributes=$_GET['User'];
145:
146: $this->render('admin',array(
147: 'model'=>$model,
148: ));
149: }
150:
151: /**
152: * Returns the data model based on the primary key given in the GET variable.
153: * If the data model is not found, an HTTP exception will be raised.
154: * @param integer the ID of the model to be loaded
155: */
156: public function loadModel($id)
157: {
158: $model=User::model()->findByPk($id);
159: if($model===null)
160: throw new CHttpException(404,'The requested page does not exist.');
161: return $model;
162: }
163:
164: /**
165: * Performs the AJAX validation.
166: * @param CModel the model to be validated
167: */
168: protected function performAjaxValidation($model)
169: {
170: if(isset($_POST['ajax']) && $_POST['ajax']==='user-form')
171: {
172: echo CActiveForm::validate($model);
173: Yii::app()->end();
174: }
175: }
176: }
177:
VIEW: update.php的代碼,
1: <?php
2: $this->breadcrumbs=array(
3: 'Users'=>array('index'),
4: $model->id=>array('view','id'=>$model->id),
5: 'Update',
6: );
7:
8: $this->menu=array(
9: array('label'=>'List User', 'url'=>array('index')),
10: array('label'=>'Create User', 'url'=>array('create')),
11: array('label'=>'View User', 'url'=>array('view', 'id'=>$model->id)),
12: array('label'=>'Manage User', 'url'=>array('admin')),
13: );
14: ?>
15:
16: <h1>Update User <?php echo $model->id; ?></h1>
17:
18: <?php echo $this->renderPartial('_form', array('model'=>$model)); ?>
代碼結構跟Rails驚人相似,而且連view都分離出了一個_form.php來給create.php和update.php復用。Rails的dry的理念已經貫穿了Yii。
可以訪問了:http://localhost/myblog/index.php?r=User
自動實現了CRUD的所有代碼,並且還帶search功能。還是很方便的,很節約人力的!
Yii 應用的典型流程
1. 用戶訪問 http://www.example.com/index.php?r=post/show&id=1
Web 服務器執行入口腳本index.php 來處理該請求。
2. 入口腳本建立一個應用實例並運行之。
3. 應用從一個叫 request 的應用組件獲得詳細的用戶請求信息。
4. 在名為 urlManager 的應用組件的幫助下,應用確定用戶要請求的控制器和動作。
5. 應用建立一個被請求的控制器實例來進一步處理用戶請求,控制器確定由它的actionShow 方法來處理 show 動作。然后它建立並應用和該動作相關的過濾器(比如訪問控制和性能測試的准備工作),如果過濾器允許的話,動作被執行。
6. 動作從數據庫讀取一個 ID 為 1 的 Post 模型。
7. 動作使用 Post 模型來渲染一個叫 show 的視圖。
8. 視圖讀取 Post 模型的屬性並顯示之。
9. 視圖運行一些widget。
10. 視圖的渲染結果嵌在布局中。
11. 動作結束視圖渲染並顯示結果給用戶。
應用的核心組件
Yii預定義了一套核心應用組件提供Web應用程序的常見功能。例如,request組件用於解析用戶請求和提供信息,如網址,cookie。在幾乎每一個方面,通過配置這些核心組件的屬性,我們都可以更改Yii的默認行為。
下面我們列出CWebApplication預先聲明的核心組件。
assetManager: CAssetManager -管理發布私有asset文件。
authManager: CAuthManager - 管理基於角色控制 (RBAC)。
cache: CCache - 提供數據緩存功能。請注意,您必須指定實際的類(例如CMemCache, CDbCache ) 。否則,將返回空當訪問此元件。
clientScript: CClientScript -管理客戶端腳本(javascripts and CSS)。
coreMessages: CPhpMessageSource -提供翻譯Yii框架使用的核心消息。
db: CDbConnection - 提供數據庫連接。請注意,你必須配置它的connectionString屬性才能使用此元件。
errorHandler: CErrorHandler - 處理沒有捕獲的PHP錯誤和例外。
format: CFormatter - 為顯示目的格式化數據值。已自版本 1.1.0 可用。
messages: CPhpMessageSource - 提供翻譯Yii應用程序使用的消息。
request: CHttpRequest - 提供和用戶請求相關的信息。
securityManager: CSecurityManager -提供安全相關的服務,例如散列(hashing), 加密(encryption)。
session: CHttpSession - 提供會話(session)相關功能。
statePersister: CStatePersister -提供全局持久方法(global state persistence method)。
urlManager: CUrlManager - 提供網址解析和某些函數。
user: CWebUser - 代表當前用戶的身份信息。
themeManager: CThemeManager - 管理主題(themes)。
路由
控制器和actions通過ID標識的。控制器ID的格式: path/to/xyz對應的類文件protected/controllers/path/to/XyzController.php, 相應的 xyz應該用實際的控制器名替換 (例如 post對應 protected/controllers/PostController.php). Action ID 與 action 前輟構成 action method。例如,控制器類包含一個 actionEdit 方法, 對應的 action ID就是 edit。
用戶請求一個特定的 controller 和 action 用術語即為 route. 一個 route 由一個 controller ID 和一個 action ID 連結而成,二者中間以斜線分隔. 例如, route post/edit 引用的是 PostController 和它的 edit action. 默認情況下, URLhttp://hostname/index.php?r=post/edit 將請求此 controller 和 action.
注意: 默認地, route 是大小寫敏感的. 從版本 1.0.1 開始, 可以讓其大小寫不敏感,通過在應用配置中設置CUrlManager::caseSensitive 為 false . 當在大小寫不敏感模式下, 確保你遵照約定:包含 controller 類文件的目錄是小寫的, controller map 和 action map 都使用小寫的 keys.
自版本 1.0.3, 一個應用可以包含 模塊. 一個 module 中的 controller 的 route 格式是 moduleID/controllerID/actionID.
使用 Form Builder
當創建 HTML 表單時,經常我們發現我們在寫很多重復而且在不同項目中很難重用的視圖代碼。例如,對於每個輸入框,
我們需要以一個文本標簽和顯示可能的驗證錯誤來關聯它。為了改善這些代碼的重用性,我們可以使用自版本 1.1.0 可
用的 form builder 特征。
Yii form builder 使用一個 CForm 對象來呈現一個 HTML 表單,包括此表單關聯哪些數據模型,在此表單中有哪些種
輸入框, 以及如何渲染整個表單。開發者主要需要創建和配置此 CForm 對象,然后調用它的渲染方法來顯示此表單。
表單輸入的規格被組織為一個分層的表單元素。在分層的根部,它是 CForm 對象。根表單對象維護着它的 children 為
兩個集合: CForm::buttons 和 CForm::elements。 前者包含按鈕元素(例如提交按鈕,重設按鈕),而后者包含輸入元素,
靜態文本和子表單。 子表單是一個包含在另外一個表單 CForm::elements 中的 CForm 對象。它可以有自己的數據模型,
CForm::buttons 和 CForm::elements 集合。
當用戶提交一個表單,整個表單輸入框中填寫的值被提交,包含屬於子表單的輸入框。CForm提供了方便的方法,可以
自動賦值輸入數據到相應的模型屬性並執行數據驗證。
聲明關聯
在使用AR進行關聯查詢之前,我們需要讓 AR 知道它和其他 AR 之間有怎樣的關聯。
AR類之間的關聯直接反映着數據庫中這個類所代表的數據表之間的關聯。 從數據庫的角度來說,兩個數據表A,B之
間可能的關聯有三種:一對多(例如tbl_user 和tbl_post),一對一(例如tbl_user 和tbl_profile),多對多(例如tbl_category
和tbl_post)。而在AR中,關聯有以下四種:
BELONGS_TO: 如果數據表A和B的關系是一對多,那我們就說B屬於A, 例如Post屬於User。
HAS_MANY: 如果數據表A和B的關系是一對多,那我們就說A有多個B, 例如User有多個Post。
HAS_ONE: 這是„HAS_MANY‟關系中的一個特例,當A最多有一個B,例如一個User最多只有一個Profile
MANY_MANY: 這個相當於關系數據庫中的多對多關系。因為絕大多數關系數據庫並不直接 支持多對多的關系,
這時通常都需要一個單獨的關聯表,把多對多的關系分解為兩個一對多的關系。 在我們的例子中,
tbl_post_category就是這個用作關聯的表。用AR的術語,我們可以將 MANY_MANY解釋為BELONGS_TO和
HAS_MANY的結合。例如Post屬於多個Category並且 Category有多個Post。
在AR中聲明關聯,是通過覆蓋(Override)父類CActiveRecord中的 relations() 方法來實現的。這個方法返回一個包
含了關系定義的數組,數組中的每一組鍵值代表一個關聯:
'VarName'=>array('RelationType', 'ClassName', 'ForeignKey', ...additional options)
這里的VarName是這個關聯的名稱;RelationType指定了這個關聯的類型,可以是下面四個常量之一:
self::BELONGS_TO,self::HAS_ONE,self::HAS_MANY和self::MANY_MANY; ClassName是這個關系關聯
到的AR類的類名;ForeignKey指定了這個關聯是通過哪個外鍵聯系起來的。 后面的additional options可以
加入一些額外的設置,后面會做介紹。
下面的代碼演示了如何定義User和Post之間的關聯。
1: class Post extends CActiveRecord
2: {
3: public function relations()
4: { return array(
5: 'author'=>array(self::BELONGS_TO, 'User', 'author_id'),
6: 'categories'=>array(self::MANY_MANY, 'Category',
7: 'tbl_post_category(post_id, category_id)'),
8: );
9: }
10: }
11:
12: class User extends CActiveRecord
13: {
14: public function relations()
15: { return array(
16: 'posts'=>array(self::HAS_MANY, 'Post', 'author_id'),
17: 'profile'=>array(self::HAS_ONE, 'Profile', 'owner_id'),
18: );
19: }
20: }
開發流程
1. 創建目錄結構。
2. 配置 application。就是修改application配置文件。這步有可能會寫一些application組件(例如:用戶組件)
3. 每種類型的數據都創建一個 model 類來管理。 同樣,yiic可以為我們需要的數據庫表自動生成active record 類。
4. 每種類型的用戶請求都創建一個 controller 類。 依據實際的需求對用戶請求進行分類。一般來說,如果一個model類需要用戶訪問,就應該對應一個controller類。yiic工具也能自動完成這步。
5. 實現 actions 和相應的 views。這是真正需要我們編寫的工作。
6. 在controller類里配置需要的action filters 。
7. 如果需要主題功能,編寫 themes。
8. 如果需要 internationalization 國際化功能,編寫翻譯語句。
9. 使用 caching 技術緩存數據和頁面。
10. 最后 tune up調整程序和發布。
以上每個步驟,有可能需要編寫測試案例來測試。
嗯,就到這里吧,其他的看直接看手冊比較合適。另外研讀代碼的同學可以直接看安裝包里帶的幾個DEMOS,試做的可以跟 Yii Blog Book v1.1.pdf 的教程 。另外介紹下中文論壇。
本文內容,大部分來源官方文檔。