82
HTTP://SEODRUPAL.VN Lập trình Drupal, Zend Framework, Yii Framework Kiểm tra tương thích giữa Yii với máy chủ http://yourhostname/path_to_yii/requirements/index.php http://localhost/softvn/requirements/index.php Phần mềm chạy local: Xampp, Wamp, ko nên dùng appserv vì bị lỗi( nguyên nhân mình ko biết, tốt nhất nên tránh). Hoặc xài luôn host thật nếu nhà có điều kiện. 1. Chuẩn bị Trước tiên bạn phải cấu hình windows để sử dụng được php với cmd -Giả sử bạn cài apache mặc định trên WinXP (C:\xampp\htdocs). -Bạn thiết lập lại biến môi trường (Environment Variables) bằng cách vào: Start -> My Computer (right click!) -> Advanced Tab -> Environment Variables -> Click Path in System variables (windows 7 là Path) -> Edit. -Click vào biến PATH và chọn Edit. Lưu ý là đừng có xoá bỏ các đường dẫn đã tồn tại trong textbox mà ngăn cách chúng với nhau bằng dấu ";". -Tiếp đó bạn thêm vào những đường dẫn sau: "C:\xampp\php" và " C:\ xampp\htdocs\yii\framework". Lưu ý sửa đường dẫn cho phù hợp với máy bạn nha .

Vocabulary Yiiframework

Embed Size (px)

Citation preview

Page 1: Vocabulary Yiiframework

HTTP://SEODRUPAL.VNLập trình Drupal, Zend Framework, Yii Framework

Kiểm tra tương thích giữa Yii với máy chủhttp://yourhostname/path_to_yii/requirements/index.phphttp://localhost/softvn/requirements/index.phpPhần mềm chạy local: Xampp, Wamp, ko nên dùng appserv vì bị lỗi( nguyên nhân mình ko biết, tốt nhất nên tránh).Hoặc xài luôn host thật nếu nhà có điều kiện.

1. Chuẩn bịTrước tiên bạn phải cấu hình windows để sử dụng được php với cmd

-Giả sử bạn cài apache mặc định trên WinXP (C:\xampp\htdocs).

-Bạn thiết lập lại biến môi trường (Environment Variables) bằng cách vào: Start -> My Computer (right click!) -> Advanced Tab -> Environment Variables -> Click Path in System variables (windows 7 là Path) -> Edit.

-Click vào biến PATH và chọn Edit. Lưu ý là đừng có xoá bỏ các đường dẫn đã tồn tại trong textbox mà ngăn cách chúng với nhau bằng dấu ";".

-Tiếp đó bạn thêm vào những đường dẫn sau: "C:\xampp\php" và " C:\xampp\htdocs\yii\

framework". Lưu ý sửa đường dẫn cho phù hợp với máy bạn nha .

-Khởi động máy tính lại.2.Tạo ứng dụng Yii mới-YiiRoot là thư mục nơi bạn đã cài đặt Yii

Page 2: Vocabulary Yiiframework

-Webroot là thư mục góc chứa web-Từ dòng lệnh, đến webroot của bạn và thực hiện:C:\Cd\Cd C:\xampp\htdocs\C:\xampp\htdocs\>softvn/framework/yiic webapp demo[demo]-> Tên ứng dụng Create a Web application under '/Webroot/demo'? [Yes|No] Yes[y]Vậy là khung xương của Yii đã được tạo ra thành công

Trích dẫn:demo/ index.php file ứng dụng index-test.php file kiểm tra chức năng assets/ chứa tài nguyên ứng dụng css/ chứa CSS images/ chứa hình ảnh themes/ chứa giao diện protected/ chứa các file được bảo vệ

Bạn có thể truy cập vào ứng dụng từ trình duyệthttp://localhost/demo/index.phpcopy framework sang demo.Vào file index.php thay đổi đường dẫn thành : $yii=dirname(__FILE__).'/framework/yii.php';

III. Tạo controller-Vào thư mục ứng dụngMã:%cd /Webroot/demoC:/Cd C:/xampp/htdocs/demo

-Khởi động Yii ShellMã:%YiiRoot/framework/yiic shell

Cd C:/xampp/htdocs/demoC:/xampp/htdocs/demo> C:/xampp/htdocs/softvn/framework/yiic shell

Tạo thử controller tên message có hành động là helloWorldCú pháp: controller <controller-ID> [action-ID]VD: Mã:controller message helloWorld

-MessageController đã được tạo thành công ở thư mục: protected/controllers/-Bên cạnh đó nó cũng tạo ra view tại thư mục: protected\views\message-Chúng ta cũng có thể truy cập vào hành động helloWorld từ trình duyệtDefault: http://localhost/demo/index.php?r=message -> chạy vào indexhttp://localhost/demo/index.php?r=message/helloWorld

Page 3: Vocabulary Yiiframework

VIII. Tạo liên kết-Yii có hỗ trợ sẳn hàm tạo liên kết trong class CHtml-VD: Tạo liên kết tới View goodbyeMã:<p><?php echo CHtml::link("Goodbye",array('message/goodbye')); ?></p>Tạo liên kết tới View HelloMã:<p><?php echo CHtml::link("Hello",array('message/helloWorld')); ?></p>

IX.Cài đặt database1.Yii hỗ trợ các dalabase sau:-MySQL 4.1 or later-PostgresSQL 7.3 or later-SQLite 2 and 3-Microsoft SQL Server 2000 or later-Oracle2. Kết nối với database-Thực hiện ở file /protected/config/main.php-Mặc định nó đang kích hoạt đòng này là database của khung xương Yii

Mã:        'db'=>array(            'connectionString' => 'sqlite:'.dirname(__FILE__).'/../data/testdrive.db',        ),

- Giả sử ta có 1 bảng trong Mysql như sau:

Mã:CREATE TABLE IF NOT EXISTS `tbl_user` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `username` varchar(128) NOT NULL,  `password` varchar(128) NOT NULL,  `email` varchar(128) NOT NULL,  PRIMARY KEY (`id`));

- Chúng ta phải kích hoạt đòng sau trong /protected/config/main.php để kết nối với Mysql (bỏ /* */ và sửa lại cấu hình)

Mã:// uncomment the following to use a MySQL database                'db'=>array(            'connectionString' => 'mysql:host=localhost;dbname=db_yii',            'emulatePrepare' => true,            'username' => 'root',            'password' => '',            'charset' => 'utf8',        ),

-Ngoài ra ta có thể kết nối với cái database khác (thay đổi dòng 'connectionString')• SQLite: sqlite:/path/to/dbfile• MySQL: mysql:host=localhost;dbname=testdb

Page 4: Vocabulary Yiiframework

• PostgreSQL: pgsql:host=localhost;port=5432;dbname=testdb• SQL Server: mssql:host=localhost;dbname=testdb• Oracle: oci:dbname=//localhost:1521/testdb

XI. Tạo CRUD- CRUD là các chức năng create, read, update và delete 1 bảng trong database

1. Kích hoạt công cụ Gii- Gii hỗ trợ sinh mã tự động các chức năng như Controller, Crud, Form, Model, Module.- Để kích hoạt Gii ta vào file config /protected/config/main.php- Kích hoạt đoạn code sau

Mã:        // uncomment the following to enable the Gii tool        'gii'=>array(            'class'=>'system.gii.GiiModule',            'password'=>'123456',             // If removed, Gii defaults to localhost only. Edit carefully to taste.            'ipFilters'=>array('127.0.0.1','::1'),        ),

- Đổi password mới để đăng nhập Gii- Vào Gii thông qua url: http:// tên host/demo/index.php?r=gii

http://i12.photobucket.com/albums/a225/k...age023.pnghttp://i12.photobucket.com/albums/a225/k...age025.png

2. Tạo user Model-Vào mục Model Generator để tạo Model cho bảng user

http://i12.photobucket.com/albums/a225/k...age027.png

- Table Prefix: viết phần tiền tố của bảng (nếu có) vào đây, ở đây bảng của ta tên là tbl_user nên tiền tố sẽ là tbl_- Table Name: phần còn lại của tên bảng là user (ta có thể tạo tự động tất cả bảng bằng cách nhập dấu * vào đây)- Model Class: tên lớp của model là User (tự sinh ra)- Còn lại để mặc định và click Preview- Sau đó click Generate để tạo file Model của User tại thư mục /protected/models/User.php

3. Tạo CRUD:- Vào mục Crud Generator

http://i12.photobucket.com/albums/a225/k...age029.png

- Model Class: điền chính xác tên lớp Model vừa tạo là User- Controller ID: điền user (không viết hoa)- Còn lại để mặc định và click Preview- Sau đó click Generate để tạo Crud

4. Truy cập CRUD- Vào url: http://yourhostname/demo/index.php?r=user

Page 5: Vocabulary Yiiframework

- Click vào các chức năng như Create User, Manage User, nó sẽ bắt ta đăng nhập, ta có thể sử dụng user và pass sau: demo/demo (tài khoản bình thường) hay admin/admin (tài khoản admin)- Với tài khoản admin ta có thể truy cập vào trang quản lý sauhttp://yourhostname/demo/index.php?r=user/admin5. URL Thân thiệnVào protected/config/main.php bỏ comment urlManager…..$yii=dirname(__FILE__).'/framework/yii.php';

XII CÁC TRƯỜNG DỮ LIỆU TRONG FORM$this->pageTitle=”Thay đổi tiêu đề trang tại đây”;Cách 1: Dùng form bằng cách dùng widget.//Khởi tạo widget sử dụng Ajax cho Form Active

$form=$this->beginWidget('CActiveForm',array('id'=>'user-form','enableAjaxValidation'=>true,'enableClientValidation'=>true,'focus'=>array($model,'name')

));<?php //Kiểm tra đầu vào model đã đúng chưa ?

echo $form->errorSummary($model);?><div class="row">

<?php //Khởi tạo trường nameecho 'Tên truy cập:';echo $form->textField($model,'name');echo $form->error($model,'name');

?></div>

Thêm Captcha cho form-Nếu chưa bật "gd2" thì ta vào file php.ini rồi sữa lại dòng nàyMã PHP:extension=php_gd2.dll<?php $this->widget('CCaptcha',array(                                                    'buttonLabel'        =>    'Lấy code mới',                                                    'clickableImage'    =>    true,                                                    'imageOptions'        =>    array('id' => 'captchaimg')                                                    )); ?>RE: [Cơ Bản] Tạo form trong view Xem thêm các Method để add các Field khác cho form HereNgoài cách dùng 'CActiveForm' ta có thể dùng 'Chtml' dể tạo form: CHtml

Viết Lại form trên bằng cách dùng 'CHtml':Mã PHP:<div id='form'><?php     echo CHtml::beginForm();?>    <div id='row'>        <?php echo CHtml::activeLabel($model,'name');?>        <br/>        <?php echo CHtml::activeTextField($model,'name')?>    </div>    <div id='row'>        <?php echo CHtml::activeLabel($model,'email');?>        <br/>        <?php echo CHtml::activeTextField($model,'email')?>    </div>

Page 6: Vocabulary Yiiframework

    <div id='row'>        <?php echo CHtml::activeLabel($model,'pass');?>        <br/>        <?php echo CHtml::activePasswordField($model,'pass')?>    </div>    <div id='row'>        <?php echo CHtml::activeLabel($model,'repass');?>        <br/>        <?php echo CHtml::activePasswordField($model,'repass')?>    </div>    <div id='row'>        <?php echo CHtml::activeLabel($model,'date');?>        <br/>        <?php echo CHtml::activeTextField($model,'date')?>    </div>    <div id='send'>    <br/>        <?php echo CHtml::submitButton('Đăng Ký',array('id'=>'frmReg','name'=>'frmReg'));?>    </div><?php     echo CHtml::endForm();?></div> 

Sau khi tạo form xong thì tới bước tiếp theo là add các ràng buộc cho thông tin mà user nhập vào ví dụ như:

Các text box không được bỏ trống Email phài đúng dạng Pass phải lớn hơn 6 nhỏ hơn 15 Repass phài y chang Pass Date: phài hợp lệ theo kiểu (dd-mm-yyyy) hay (mm-dd-yyyy) Add thêm captcha chống đăng ký hàng loạt

Thêm Captcha cho form

-Yii có hỗ trợ sẵn thư viện captcha cho chúng ta, và captcha thì nhìn cũng rất là cool.

Test xem có thể render captcha hay không-Đầu tiên truy cập thử link này để test xem có captcha hay không cái đã.http://www.code.com/index.php?r=site/captcha nếu ra như vầy là ok

-Nếu nó không hiện captcha thì ta nên check lại xem đã load "gd2" hay chưa bằng cách chạy mục test của Yii

Page 7: Vocabulary Yiiframework

giống như hình là load rồi, nó vàng hay đỏ thì xem lại cấu hình webserver

-Nếu chưa bật "gd2" thì ta vào file php.ini rồi sữa lại dòng nàyMã PHP:extension=php_gd2.dllbỏ dấu ";" trước nó, mấy cái khác để defaut đừng táy máy, restar webserver và test lại, nếu vẫn lỗi --> thôi cài lại win cho nó lành 

-Để tạo captcha ta thêm vào phần view đoạn code sau:Mã PHP:<?php $this->widget('CCaptcha',array(                                                    'buttonLabel'        =>    'Lấy code mới',                                                    'clickableImage'    =>    true,                                                    'imageOptions'        =>    array('id' => 'captchaimg')                                                    )); ?>Với:

'buttonLabel' : hiển thị một link với nội dung mà ta set, khi click vào đó sẽ đỏi string cùa captcha 'clickableImage': khi click vào image sẽ đổi sang hình khác. 'imageOptions': set các thuộc tính Html của captcha

- Một captcha được rendered bởi một hành động của lớp CCaptchaAction, do đó nếu chỉ add bên view sẽ không hiển thị hình ảnh, vì captcha không được render. Do đó ta viết thêm bên Controller:Mã PHP:public function actions()    {            return array(            'captcha'    =>    array    (                                        'class'    =>    'CCaptchaAction',                                        'backColor'    =>'#fff

'                                    ),            );    } Với

'backColor': màu nền ảnh #fff là màu đen, 'foreColor': màu chử captcha. 'height': chiểu cao ành 'width': Chiểu rộng 'maxLength': chiều dài tối da của chử captcha 'minLength': độ dài tối thiểu của string. 'verifyCode': lấy giá trị mã xác nhận

Page 8: Vocabulary Yiiframework

Cuối cùng ra cái form như vầy:

-Để ràng buộc các thông tin mà ủe nhập vào ta viết một phương thức trong Model như sau:Mã PHP:public function rules()        {            return array    (                    array    ('code','captcha',                                    'allowEmpty'=>!CCaptcha::checkRequirements(),                                    'message'    =>    'Mã Xác Nhận Nhập Không Đúng'                                    ),                    array('email','email','message' =>'{attribute} không hợp lệ'),                    array('name,email,pass,repass,date,code','required','message'=>"{attribute} không được bỏ trống"),                    array('repass','compare','compareAttribute'=>'pass','message'=>"{attribute} phải chính xác"),                    array('pass','length','min'=>'6','message'=>"{attribute} không đủ độ dài "),                    array('date','date','format'=>'dd-mm-yyyy','message'=>"{attribute} phải chính xác dạng {dd-mm-yyyy}"),                            );                    } 

PHẦN I – XỬ LÝ NỘI TẠI WEBSITECác bước phân tích BackEnd (CMS) với dự án (PROJECT)TẠO BẢNG PROJECT

CREATE TABLE tbl_project (id INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT,name VARCHAR(128),description TEXT,create_time DATETIME,create_user_id INTEGER,update_time DATETIME,update_user_id INTEGER);

Page 9: Vocabulary Yiiframework

Sử dụng GII xây dựng Project AR classLưu ý: sau tên localhost là tên folder website của bạn, vui lòng thay thế cho đúng.http://localhost/trackstar/index.php?r=gii.

Tạo mới 1 class model tbl_project table, the Model Generator ->Generate.Navigate back to the main Gii menu located at http://localhost/trackstar/index.php?r=gii, and choose the Crud Generator ->Generate (Gõ tên bảng vào keyword tìm dữ liệu rồi nhấn Generate).Xem kết quả: http://localhost/trackstar/index.php?r=project). Tạo một vài dữ liệu để thực hiện việc xây dựng DB.

-Thiết kế giản đồ dữ liệu (database schema) và xây dựng đối tượng hỗ trợ các sản phẩm (issues) của dự án.- Tạo mô hình lớp(model class) Yii cho phép ứng dụng dễ dàng tương tác các bảng dữ liệu với nhau sau khi tạo.- Tạo lớp điều khiển (controller class) sẽ là không gian chứa các hàm cho phép chúng ta :

+ Tạo các sản phẩm (issues) mới.+ Tìm về một danh sách sản phẩm hiện hành trong phạm vi một dự án lấy từ database.+ Cập nhật/chỉnh sửa sản phẩm hiện hành.+ Xóa đi sản phẩm hiện hành.

- Tạo khung nhìn (view) để trả lại (render) cho giao diện người sử dụng các hành động ( có trước).

- THIẾT KẾ GIẢN ĐỒ (SCHEMA)

Chúng ta giả sử nó có một thuộc tính (type), bản thân (owner), một yêu cầu (requester), một trạng thái (status) , và miêu tả (description). Chúng ta sẽ tạo bảng (tbl_project) để thêm các thông tin cơ bản được kiểm tra với các bảng khác chúng ta tạo ngày( date), giờ(times) và người truy cập update bảng .

Tuy nhiên thuộc tính(types), bản thân(owner), người yêu cầu(requester) và trạng thái(status) là tự chúng.Bản thân chúng là thực thể. Để giữ cho mô hình mềm dẻo và dễ dàng mở rộng, chúng ta sẽ tạo nhiều mô hình (model) không dính dáng tới nhau. Bản thân (developer) (owner) và người yêu cầu (requester) là hai người sử dụng hệ thống được tham chiếu từ một hàng (row) trong bảng được gọi là (tbl_user).Chúng ta có thể bắt đầu giới thiệu ý tưởng về người sử dụng (user) trong bảng dự án (tbl_project) , chúng ta thêm cột (create_user_id) , (update_user_id) để nhận dạng đường đi của một người sử dụng lúc ban đầu họ tạo dự án, tương tự như vậy khi người sử dụng (user) cập nhật chi tiết dự án lần cuối cùng. Mặc dù chúng ta chưa giới thiệu bảng đó vào lúc này, có những trường dữ liệu được mô hình chuyển qua khóa ngoài tới một bảng dữ liệu khác để lưu trữ dữ liệu về người sử dụng (user data). Trường (owner_id) mã bản thân, (requester_id) mã người yêu cầu, trong bảng (tbl_issue) cũng sẽ được khóa ngoài liên kết trở lại với bảng (tbl_user).

ĐỊNH NGHĨA CÁC MỐI QUAN HỆ+Một dự án có thể có nhiều người sử dụng truy cập, và người truy cập có thể liên kết với nhiều

dự án chúng ta gọi đó là liên kết nhiều – nhiều (many – to – many ).+Cách thức tốt nhất để mô hình hóa quan hệ nhiều – nhiều (many-to-many) trong các dữ liệu

liên quan đó là sử dụng sự kết hợp (association) hoặc phân quyền cho bảng (table).Dưới đây là mô hình cơ bản thực thể quan hệ giữa người sử dụng (users),dự án(project), và

sản phẩm (issues). Một dự án có thể có hoặc không có nhiều người dùng,. Một người sử dụng cần phải kết hợp với ít nhất một dự án, hoặc có thể kết hợp với nhiều dự án. Sản phẩm sẽ chỉ thuộc về một và chỉ duy nhất một dự án. Khi đó một dự án có thể có không -> nhiều sản phẩm.

Page 10: Vocabulary Yiiframework

Một sản phẩm được phân quyền (hay được yêu cầu) bởi duy nhất 1 người dùng.

Exactly one: Chỉ duy nhất 1.1 or More : Một hoặc nhiều0 or More : Không hoặc nhiều.

Dịch : Project: Dự ánIssue: vấn đềUser: Người dùngOwner: Bản thân.XÂY DỰNG DATABASE VÀ CÁC MỐI QUAN HỆ

Tạo 3 bảng mới là: tbl_issue,tbl_user,tbl_project_user_assignment() ( bảng trung gian ).

CREATE TABLE IF NOT EXISTS 'tbl_issue' ( 'id' INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, 'name' varchar(256) NOT NULL, 'description' varchar(2000), 'project_id' INTEGER, 'type_id' INTEGER, 'status_id' INTEGER, 'owner_id' INTEGER, 'requester_id' INTEGER, 'create_time' DATETIME, 'create_user_id' INTEGER, 'update_time' DATETIME, 'update_user_id' INTEGER ) ENGINE = InnoDB;CREATE TABLE IF NOT EXISTS 'tbl_user' ( 'id' INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, 'email' Varchar(256) NOT NULL, 'username' Varchar(256), 'password' Varchar(256), 'last_login_time' Datetime, 'create_time' DATETIME, 'create_user_id' INTEGER,

Page 11: Vocabulary Yiiframework

'update_time' DATETIME, 'update_user_id' INTEGER) ENGINE = InnoDB;CREATE TABLE IF NOT EXISTS 'tbl_project_user_assignment'( 'project_id' Int(11) NOT NULL, 'user_id' Int(11) NOT NULL, 'create_time' DATETIME, 'create_user_id' INTEGER, 'update_time' DATETIME, 'update_user_id' INTEGER, PRIMARY KEY ('project_id','user_id')) ENGINE = InnoDB;

Tạo các mối quan hệ:-Tạo khóa ngoại giữa 2 bảng tbl_issue,tbl_project tham chiếu (id thuộc bảng tbl_project) nối với project_id trong bảng tbl_issue.ALTER TABLE 'tbl_issue' ADD CONSTRAINT 'FK_issue_project' FOREIGN KEY ('project_id') REFERENCES 'tbl_project' ('id') ON DELETE CASCADE ON UPDATE RESTRICT;-Tạo khóa ngoại giữa 2 bảng tbl_issue, tbl_user tham chiếu (id thuộc bảng tbl_user) nối với owner_id (khóa bản thân) trong bảng tbl_issue.ALTER TABLE 'tbl_issue' ADD CONSTRAINT 'FK_issue_owner' FOREIGN KEY ('owner_id') REFERENCES 'tbl_user' ('id') ON DELETE CASCADE ON UPDATE RESTRICT;

Tương tự với các khóa ngoại còn lại:ALTER TABLE 'tbl_issue' ADD CONSTRAINT 'FK_issue_requester' FOREIGN KEY

('requester_id') REFERENCES 'tbl_user' ('id') ON DELETE CASCADE ON UPDATE RESTRICT;

ALTER TABLE 'tbl_project_user_assignment' ADD CONSTRAINT 'FK_project_user' FOREIGN KEY ('project_id') REFERENCES 'tbl_project' ('id') ON DELETE CASCADE ON UPDATE RESTRICT;

ALTER TABLE 'tbl_project_user_assignment' ADD CONSTRAINT 'FK_user_project' FOREIGN KEY ('user_id') REFERENCES 'tbl_user' ('id') ON DELETE CASCADE ON UPDATE RESTRICT;

Tạo Active Record Model classes cho các bảng vừa tạo:-Tạo AR Model issues

Navigate to the Gii tool via http://localhost/trackstar/index.php?r=gii, and choose the Model Generator link. Leave the table prefix as tbl_. Fill in the Table Name field as tbl_issue, which will auto-populate the Model Class field as Issue.->preview->generate - Tạo Issues CRUD operation

Navigate to the Gii generator menu at http://localhost/trackstar/index.php?r=gii, and choose the Crud Generator link. Fill out the form using Issue as the value for the Model Class field. This will auto-populate the Controller ID to also be Issue. The Base Controller Class and Code Template fields can remain their predefined default values. Click the Preview -> Generate.

Thêm thuộc tính DropDown MenuMở model/Issue class: Ở đầu trang class Issue khai báo hằng các thuộc tính:

const TYPE_BUG=0;const TYPE_FEATURE=1;const TYPE_TASK=2;

Page 12: Vocabulary Yiiframework

Tạo hàm trả về mảng chứa các thuộc tính:

public function getTypeOptions(){ return array( self::TYPE_BUG=>'Bug', self::TYPE_FEATURE=>'Feature', self::TYPE_TASK=>'Task', );}

Thêm một filter (bộ lọc)Mở protected/controllers/IssueController.php thêm nội dung sau vào dưới lớp:

public function filterProjectContext($filterChain){ $filterChain->run(); }

Thêm cấu hình cho filter vào mảng cấu hình.Với filter mới được định nghĩa ta thử áp dụng với create action.(Hàm tạo).

public function filters(){ return array( 'accessControl', // perform access control for CRUD operations 'projectContext + create', //check to ensure valid project context );}

Phương thức trên sẽ trả về cấu hình cho filter projectContext cái mà chúng ta đã định nghĩa giống như một phương thức trong class và nó áp dụng cho actionCreate() method. Cú pháp cấu hình cho phép là : ‘+’ hoặc dấu ‘-‘ ký hiệu đặc biệt được sử dụng khi chúng ta muốn hoặc không muốn một filter nào đó được áp dụng hay không.

Ví dụ nếu chúng ta quyết định muốn áp dụng cho tất cả các action ngoại trừ actionUpdate() cập nhật, và actionView() (nhìn).Chúng ta thực hiện :

return array('projectContext - update, view' ,);Thêm một vài Filter Logic

Chúng ta vừa định nghĩa được filter mới và cấu hình nó thực hiện method actionCreate();Tuy nhiên chúng ta chưa thực hiện được sự logic cần thiết.Chúng ta muốn chắc chắn rằng văn

bản dự án được thực hiện trước khi các hành động (action) được kick hoạt.Chúng ta cần đặt filter logic trước khi gọi filterChain->run().Chúng ta sẽ sử dụng chuỗi từ khóa (querystring) là một tham biến ngoài URL được trình bày để nhận dạng các dự án (project).

Các pre-action của Filter sẽ kiểm tra để nhận biết.Nếu các thuộc tính của dự án hiện tại là NULL, chúng ta sẽ sử dụng chuỗi từ khóa(querystring) tham biến để kích hoạt sự lựa chọn các dự án cơ bản trong khóa chính được nhận dạng (Primary Key indentifier). Nếu thành công Action sẽ thực hiện, và nếu thất bại một lỗi ngoại lệ sẽ được hiện ra.

Chúng ta vào IssueController class:class IssueController extends CController{ ....

Page 13: Vocabulary Yiiframework

/** * @var private property containing the associated Project model instance. */ private $_project = null; /** * Protected method to load the associated Project model class * @project_id the primary identifier of the associated Project * @return object the Project data model based on the primary key */ protected function loadProject($project_id) { //if the project property is null, create it based on input id if($this->_project===null) { $this->_project=Issue::model()->findbyPk($project_id); if($this->_project===null) { throw new CHttpException(404,'The requested project does not exist.'); }} return $this->_project; } /** * In-class defined filter method, configured for use in the above filters() method * It is called before the actionCreate() action method is run in order to ensure a proper project context */ public function filterProjectContext($filterChain) { //set the project identifier based on either the GET or POST input //request variables, since we allow both types for our actions $projectId = null; if(isset($_GET['pid'])) $projectId = $_GET['pid']; else if(isset($_POST['pid'])) $projectId = $_POST['pid']; $this->loadProject($projectId); //complete the running of other filters and execute the requested action $filterChain->run(); } ...}

THÊM PROJECT ID

Liên kết( link) chúng ta cần điều chỉnh trong view file : /protected/views/issue/index.php.

Ở đầu trang chúng ta sẽ nhìn thấy link create new .

Page 14: Vocabulary Yiiframework

$this->menu=array( array('label'=>'Create Issue', 'url'=>array('create')), array('label'=>'Manage Issue', 'url'=>array('admin')),);

Chúng ta thêm trường pid vừa tạo :array('label'=>'Create Issue', 'url'=>array('create', 'pid'=>1)),

Truy cập lại vào admin và click vào link liên kết : http://localhost/demo/index.php?r=issue/create&pid=1. Ta đã thực hiện được.

Điều chỉnh chi tiết từng trang của dự án:Thêm mã dự án cho từng URL cho việc tạo mới sản phẩm là một giai đoạn khá tốt để chắc chắn rằng những điều chỉnh bên ngoài làm việc một cách hoàn hảo.Tuy nhiên, chúng ta có một vấn đề xảy ra với mã code là projectID luôn luôn =1 .Tất nhiên, điều này không phải là những gì chúng ta muốn.Chúng ta muốn có menu option cho việc tạo mới sản phẩm trong trang chi tiết của dự án.Nghĩa là , khi bạn lựa chọn một dự án từ trang danh sách chi tiết các dự án, mã dự án đặc biệt sẽ phải được hiểu và phải có mã dự án động . (dynamic project id).#1Mở chi tiết dự án trong : view, /protected/views/project/view.php. Trong phần đầu trong ta sẽ tìm và thêm pid như sau :

$this->menu=array( array('label'=>'List Project', 'url'=>array('index')), array('label'=>'Create Project', 'url'=>array('create')), array('label'=>'Update Project', 'url'=>array('update', 'id'=>$model->id)), array('label'=>'Delete Project', 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model->id),'confirm'=>'Are you sure you want to delete this item?')), array('label'=>'Manage Project', 'url'=>array('admin')), array('label'=>'Create Issue', 'url'=>array('issue/create', 'pid'=>$model->id)),);

Xóa bỏ các input form dự án (project).

Đầu tiên hãy chỉnh lại IssueController::actionCreate()

public function actionCreate(){ $model=new Issue; $model->project_id = $this->_project->id; ...}

Mở /protected/views/issue/_form.

Tìm trường: <div class="row"> <?php echo $form->labelEx($model,'project_id'); ?> <?php echo $form->textField($model,'project_id'); ?> <?php echo $form->error($model,'project_id'); ?></div>

Thay thế: <div class="row"> <?php echo $form->hiddenField($model,'project_id'); ?></div>

Quay lại việc bản thân (owner) và người yêu cầu (requester) dropdown.

Page 15: Vocabulary Yiiframework

Chúng ta đã thêm 2 user là :INSERT INTO 'tbl_user' ('email', 'username', 'password') VALUES ('[email protected]','Test_User_One', MD5('test1')), ('[email protected]','Test_User_Two', MD5('test2')) ;

Để tạo 2 user trong hệ thống với Id là 1, 2 ta thực hiện assign:INSERT INTO 'tbl_project_user_assignment' ('project_id', 'user_id') VALUES (1,1), (1,2);

Chúng ta có thể nhìn mối quan hệ giữa các table trong /protected/models/Issue.php.

public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'owner' => array(self::BELONGS_TO, 'User', 'owner_id'), 'project' => array(self::BELONGS_TO, 'Project', 'project_id'), 'requester' => array(self::BELONGS_TO, 'User', 'requester_id'), ); }

Chúng ta sẽ thêm quan hệ: Project::relations() method.

Mở: /protected/models/Project.php, và thay thế các thực thể trong relation() như sau:

/** * @return array relational rules. */ public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'issues' => array(self::HAS_MANY, 'Issue', 'project_id'), 'users' => array(self::MANY_MANY, 'User', 'tbl_project_user_assignment(project_id, user_id)'), ); }

Tạo Dữ liệu từ Dropdown MenuMở /issue/models/Issue.php, và thêm đoạn code sau vào dưới class:

public function getUserOptions()

{

$usersArray = CHtml::listData($this->users, 'id', 'username');

return $usersArray;

}}

Thêm User và ProjectUserAssignmentThêm đoạn sau vào dưới class của IssueController class:

Page 16: Vocabulary Yiiframework

/** * Returns the project model instance to which this issue belongs */public function getProject(){ return $this->_project;}

Mở /protected/views/issue/_form.php và tìm trong form các trường owner_id, requester_id

Thay thế: <?php //echo $form->textField($model,'owner_id'); ?>

thành

<?php echo $form->dropDownList($model,'owner_id',$model->project->getUserOptions()); ?>

Thực hiện thay thế:<?php echo $form->textField($model,'requester_id'); ?>

Trở thành:

<?php echo $form->dropDownList($model,'requester_id', $this->getProject()->getUserOptions()); ?>

Remove các trường sau:<div class="row">

<?php echo $form->labelEx($model,'create_time'); ?> <?php echo $form->textField($model,'create_time'); ?> <?php echo $form->error($model,'create_time'); ?> </div> <div class="row"> <?php echo $form->labelEx($model,'create_user_id'); ?> <?php echo $form->textField($model,'create_user_id'); ?> <?php echo $form->error($model,'create_user_id'); ?> </div> <div class="row"> <?php echo $form->labelEx($model,'update_time'); ?> <?php echo $form->textField($model,'update_time'); ?> <?php echo $form->error($model,'update_time'); ?> </div> <div class="row"> <?php echo $form->labelEx($model,'update_user_id'); ?> <?php echo $form->textField($model,'update_user_id'); ?> <?php echo $form->error($model,'update_user_id'); ?> </div>

Truy cập vào issue với acc:demo xem thử phần create action();

THAY ĐỔI PROJECT CONTROLLERTrước tiên điều chỉnh actionView() trong class Project Controller giống như chúng ta muốn trưng bày danh sách sản phẩm liên quan đến các dự án đặc biệt.Chúng ta có thể làm điều này trong một vài trang giống như trang chi tiết.Phương thức Action View() là method được dùng để hiển thị chi tiết sản phẩm.

Điều chỉnh method như sau:/**

Page 17: Vocabulary Yiiframework

* Displays a particular model. */ public function actionView() { $issueDataProvider=new CActiveDataProvider('Issue', array( 'criteria'=>array( 'condition'=>'project_id=:projectId', 'params'=>array(':projectId'=>$this->loadModel()->id), ), 'pagination'=>array( 'pageSize'=>1, ), )); $this->render('view',array( 'model'=>$this->loadModel(), 'issueDataProvider'=>$issueDataProvider, )); }

Tại đây chúng ta sử dụng CactiveDataProvider class trong framework để cung cấp dữ liệu trong object ActiveRecord. Nó sẽ sử dụng class Model AR liên quan để lấy dữ liệu từ database trong một các dễ dàng với Yii widget. ClistView để trưng bày item trong danh sách được render trong view file. Chúng ta có thể sử dụng criteria là điều kiện đặc biệt chỉ để lấy các vấn đề liên quan tới dự án được trưng bày.Chúng ta cũng có thể sử dụng pagination(Phân trang) để giới hạn danh sách sản phẩm trong một trang.

ĐIỀU CHỈNH Project View File Mở /protected/views/project/view.php

Thêm đoạn code sau vào dưới cùng file: <br><h1>Project Issues</h1><?php $this->widget('zii.widgets.CListView', array( 'dataProvider'=>$issueDataProvider, 'itemView'=>'/issue/_view',)); ?>

Ở đây chúng ta đang thiết lập thuộc tính dataProvider CListView được vấn đề cung cấp dữ liệu chúng ta đã vừa tạo. Sau đó chúng ta cấu hình nó để sử dụng trong protected/view/issue/_view.php giống như một template cho render item trong dữ liệu được cung cấp.File này đã được tạo cho chúng ta bởi Gii tool khi chúng ta generate trong CRUD của issues. Chúng ta chỉ sử dụng nó ở đây để trưng bày sản phẩm trong trang chi tiết của dự án.Chúng ta cũng phải thay đổi /protected/views/issue/_view.php sử dụng template layout cho sản phẩm khác. Điều chỉnh nội dung thực thể sau:

<div class="view"> <b><?php echo CHtml::encode($data->getAttributeLabel('name')); ?>:</b> <?php echo CHtml::link(CHtml::encode($data->name), array('issue/view', 'id'=>$data->id)); ?> <br /><b><?php echo CHtml::encode($data->getAttributeLabel('description')); ?>:</b> <?php echo CHtml::encode($data->description); ?> <br /> <b><?php echo CHtml::encode($data->getAttributeLabel('type_id')); ?>:</b>

Page 18: Vocabulary Yiiframework

<?php echo CHtml::encode($data->type_id); ?><br /> <b><?php echo CHtml::encode($data->getAttributeLabel('status_id')); ?:</b> <?php echo CHtml::encode($data->status_id); ?> </div>

Tại Project Controller Sửa đổi LoadModuleprivate $_model;

public function loadModel(){

if($this->_model===NULL) { if(isset($_GET['id']))

$this->_model=Project::model()->findByPk($_GET['id']);if($this->_model===null)

throw new CHttpException(404,'The requested page does not exist.'); }

return $this->_model;}

Thêm dữ liệu vào bên issue/create tạo mới 2 bản ghi.Kiểm tra kết quả : (http://localhost/tasctrak/index.php?r=project/view&id=1)

Hiển thị các Status và Type text trong ISSUEVào : /protected/models/Issue.php

public function getStatusText() { $statusOptions=$this->statusOptions; return isset($statusOptions[$this->status_id]) ? $statusOptions[$this->status_id] : "unknown status ({$this->status_id})"; } /** * @return string the type text display for the current issue */ public function getTypeText(){ $typeOptions=$this->typeOptions; return isset($typeOptions[$this->type_id]) ? $typeOptions[$this->type_id] : "unknown type ({$this->type_id})"; }

THÊM ĐOẠN HIỂN THỊ TEXT từ FormVào : /protected/views/issue/_view.php:

Thay đổi : <?php echo CHtml::encode($data->type_id); ?>thành<?php echo CHtml::encode($data->getTypeText()); ?>Và thay đổi<?php echo CHtml::encode($data->status_id); ?>this:<?php echo CHtml::encode($data->getStatusText()); ?>

THAY ĐỔI CHI TIẾT VIEW ISSUE

Page 19: Vocabulary Yiiframework

Mở : /protected/views/issue/view.php Thêm đoạn sau:<?php $this->widget('zii.widgets.CDetailView', array( 'data'=>$model, 'attributes'=>array( 'id', 'name', 'description', 'project_id', 'type_id', 'status_id', 'owner_id', 'requester_id','create_time', 'create_user_id', 'update_time', 'update_user_id', ),)); ?>

Thay đổi thành:<?php $this->widget('zii.widgets.CDetailView', array( 'data'=>$model, 'attributes'=>array( 'id', 'name', 'description', array( 'name'=>'type_id', 'value'=>CHtml::encode($model->getTypeText()) ), array( 'name'=>'status_id', 'value'=>CHtml::encode($model->getStatusText()) ), 'owner_id', 'requester_id', ),)); ?>

Bổ sung thêm project_id vào function Adminpublic function actionAdmin()

{$model=new Issue('search');$model->unsetAttributes(); // clear any default values

Page 20: Vocabulary Yiiframework

if(isset($_GET['Issue']))$model->attributes=$_GET['Issue'];

$model->project_id=$this->_project->id;$this->render('admin',array(

'model'=>$model,));

}

Định nghĩa CactiveDataProvider trong indexActionpublic function actionIndex()

{$dataProvider=new

CActiveDataProvider('Issue',array('criteria'=>array('condition'=>'project_id=:project_Id','params'=>array(':project_Id'=>$this->_project->id))));

$this->render('index',array('dataProvider'=>$dataProvider,

));}

Sử dụng quan hệ ARNhư issues và user là đại diện như những bảng dữ liệu riêng biệt, và liên quan đến quan hệ khóa ngoại, chúng ta thực sự truy cập vào owner và requester username trực tiếp từ $model trong view file. Bằng cách sử dụng sức mạnh của Yii AR mô hình quan hệ, trưng bày thuộc tính username của liên quan đến model User class.As we have mentioned, the model class Issue::relations() method is where the relationships are defined. If we take a peek at this method, we see the following:/** * @return array relational rules. */ public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'owner' => array(self::BELONGS_TO, 'User', 'owner_id'), //belong to là thuộc về'project' => array(self::BELONGS_TO, 'Project', 'project_id'), 'requester' => array(self::BELONGS_TO, 'User', 'requester_id'), ); }

Trưng bày Username của Owner và requester:Protected\view\issue\view.php<?php $this->widget('zii.widgets.CDetailView', array( 'data'=>$model, 'attributes'=>array( 'id', 'name', 'description', array( 'name'=>'type_id', 'value'=>CHtml::encode($model->getTypeText())

Page 21: Vocabulary Yiiframework

), array( 'name'=>'status_id', 'value'=>CHtml::encode($model->getStatusText()) ), array( 'name'=>'owner_id', 'value'=>CHtml::encode($model->owner->username) ), array( 'name'=>'requester_id', 'value'=>CHtml::encode($model->requester->username) ), ))); ?>Thực hiện một số điều chỉnh cuối cùng.Một điều chúng ta nhận ra là ứng dụng vẫn cho phép người dùng được điều hướng tới những danh sách của sản phẩm, cũng như tất cả dự án. Ví dụ trong một trang chi tiết sản phẩm, http://localhost/trackstar/index.php?r=issue/view&id=1,

Chúng ta nhìn thấy menu điều hướng bên phải, gồm có Danh sách sản phảm, và quản lý sản phẩm tương ứng : http://localhost/trackstar/index.php?r=issue/index and http://localhost/trackstar/index.php?r=issue/admin

Nhớ rằng để truy cập vào trang quản trị bạn cần vào với tài khoản admin/adminNhưng vẫn còn hiển thị tất cả các sản phẩm, trên tất cả các dự án. Vì vậy, chúng ta cần phải hạn chế danh sách này để có một dự án cụ thể.Có những liên kết hình thành từ trang chi tiết sản phẩm (issue) và đặc biệt sản phẩm đó có dự án liên quan, chúng ta có thể bắt đầu chỉnh lại liên kết được nhấn trong projectID và projectID này nằm trong IssueController::index và IssueController::actionAdmin method.

Mở đường dẫn: /protected/views/issue/view.php thay đổi cấu hình menu:

$this->menu=array( array('label'=>'List Issue', 'url'=>array('index', 'pid'=>$model->project->id)), array('label'=>'Create Issue', 'url'=>array('create', 'pid'=>$model->project->id)), array('label'=>'Update Issue', 'url'=>array('update', 'id'=>$model->id)), array('label'=>'Delete Issue', 'url'=>'#', 'linkOptions'=>array('submit'=>array('delete','id'=>$model->id),'confirm'=>'Are you sure you want to delete this item?')), array('label'=>'Manage Issue', 'url'=>array('admin', 'pid'=>$model->project->id)),);

Thay đổi cấu hình filter trong IssueController public function filters() { return array( 'accessControl', // perform access control for CRUD operations 'projectContext + create index admin', //perform a check to ensure valid project context ); }

Chỉnh lai method actionIndex()public function actionIndex()

Page 22: Vocabulary Yiiframework

{$dataProvider=new CActiveDataProvider('Issue', array( 'criteria'=>array( 'condition'=>'project_id=:projectId', 'params'=>array(':projectId'=>$this->_project->id), ), )); $this->render('index',array( 'dataProvider'=>$dataProvider, )); }

THAY ĐỔI DANH SÁCH TRANG ADMINĐiều chỉnh method admin:public function actionAdmin() { $model=new Issue('search'); if(isset($_GET['Issue'])) $model->attributes=$_GET['Issue']; $model->project_id = $this->_project->id; $this->render('admin',array( 'model'=>$model, )); }

Thêm các tiêu chuẩn mới vào Model/ Issue::search()public function search() { // Warning: Please modify the following code to remove attributes that // should not be searched. $criteria=new CDbCriteria; $criteria->compare('id',$this->id); $criteria->compare('name',$this->name,true); $criteria->compare('description',$this->description,true); $criteria->compare('type_id',$this->type_id); $criteria->compare('status_id',$this->status_id); $criteria->compare('owner_id',$this->owner_id); $criteria->compare('requester_id',$this->requester_id); $criteria->compare('create_time',$this->create_time,true); $criteria->compare('create_user_id',$this->create_user_id); $criteria->compare('update_time',$this->update_time,true); $criteria->compare('update_user_id',$this->update_user_id); $criteria->condition='project_id=:projectID'; $criteria->params=array(':projectID'=>$this->project_id); return new CActiveDataProvider(get_class($this), array( 'criteria'=>$criteria, )); }

CHƯƠNG 7 - QUẢN TRỊ NGƯỜI DÙNG VÀ Xác Thực QUYỀN TRUY CẬP(User Management and Authentication)

Page 23: Vocabulary Yiiframework

Khi chúng ta sử dụng công cụ yiic command, chúng ta nhận được hàm đăng nhập(login) mức cơ bản với công cụ tạo sẵn cho chúng ta. Trang đăng nhập cho phép người dùng truy nhập với 2 hình thức tài khoản (admin/admin) (demo/demo)Chúng ta cần làm một số thay đổi điều chỉnh sao cho chúng ta quản lý được nhiều người dùng.Điều này sẽ khiến ta phải mở rộng thêm bảng người dùng (table user) và thêm các chức năng cần thiết để quản lý.

TẠO CRUD của table User

Navigate to the Gii tool via http://localhost/trackstar/index.php?r=gii and choose the Model Generator link. Leave the table prefix as tbl. Fill in the Table Name field as tbl_user, which will auto-populate the Model Class name field as User .Click preview -> generate.

Navigate to the tool via http://localhost/trackstar/index.php?r=gii.

2. Choose the Crud Generator link from the list of available generators.

3. Type in User for the Model Class name field. The corresponding Controller ID will auto-populate with user.->preview->generate.

Gõ http://localhost/trackstar/index.php?r=user để xem kết quả hiển thị.

Cập nhật kiểm tra lịch sử các cột (columns).Như tất cả các thực thể của chúng tôi bảng tbl_project, tbl_issue, tbl_user có các cột tương tự quy định, chúng tôi sẽ thêm vào các logic cần thiết cho một lớp cơ sở chung và sau đó có mỗi của các lớp cá nhân AR mở rộng từ lớp cơ sở mới này.Lý do chúng ta đang tạo lớp mới này, thay vì chỉ cần thêm logic trực tiếp vào model class project, là bởi vì các class khác, model Issue và User, cũng cần logic này. Thay vì lặp lại trong các mã trong tất cả các lớp mô hình AR, cách tiếp cận này sẽ cho phép chúng tôi để thiết lập các lĩnh vực này cho tất cả các lớp mô hình AR chỉ trong một nơi. Chúng tôi cũng sẽ làm cho lớp trừu tượng mới, vì nó không nên được khởi tạo trực tiếp.Tạo file mới: trong protected/models/ tạo CheckUserActiveRecord.php

<?phpabstract class CheckUserActiveRecord extends CActiveRecord{ /** * Prepares create_time, create_user_id, update_time and update_user_id attributes before performing validation. */ protected function beforeValidate() { if($this->isNewRecord) { // set the create date, last updated date and the user doing the creating $this->create_time=$this->update_time=new CDbExpression('NOW()');$this->create_user_id=$this->update_user_id=Yii::app()->user->id; } else { //not a new record, so just set the last updated time and last updated user id $this->update_time=new CDbExpression('NOW()'); $this->update_user_id=Yii::app()->user->id; } return parent::beforeValidate(); }}

Page 24: Vocabulary Yiiframework

Ở đây chúng ta đang ghi đè phương thức CactiveRecord::beforeValidate().Đây là phương thức giúp người sử dụng có thể tùy biến quá trình truy cập.nếu bạn không thực hiện sai một tham số khi gọi phương thức save () trên một lớp AR, quá trình xác thực sẽ được kích hoạt. Quá trình này thực hiện xác thực theo quy định trong phương pháp rules () trong lớp AR. Có hai phương pháp tiếp xúc cho phép chúng ta để khai thác các công việc xác nhận và thực hiện bất kỳ logic cần thiết, hoặc ngay trước hoặc ngay sau khi xác nhận được thực hiện: beforeValidate () và afterValidate ().

Chú ý: Sử dụng NOW () trong mã trước đó là cụ thể cho MySQL. Điều này có thể làm việc nếu bạn đang theo cùng cách sử dụng một cơ sở dữ liệu khác nhau. Bạn luôn có thể có một cách tiếp cận khác nhau để thiết lập giá trị này. Ví dụ, bằng cách sử dụng chức năng thời gian PHP và định dạng nó một cách thích hợp cho loại dữ liệu của cột: $ this-> createTime = $ this-> updateTime = ngày ("Ymd H: i: s, time());

bây giờ chúng ta cần phải thay đổi 3 class hiện có của AR là -Project.php, User.php, và Issue.php để mở rộng từ lớp trừu tượng hơn là trực tiếp từ CActiveRecord.3 class này nằm trong protected/models/.Chúng ta thay thế :

class Project extends CActiveRecord{

Thay đổi thành

class Project extends CheckUserActiveRecord{

Tương tự với 2 class user và issue.Định nghĩa lần lượt các trường dữ liệu trong form nằm trong : protected/views/project/_form.php và protected/views/user/_form.php protected/views/issue/_form.php,

Loại bỏ các trường dữ liệu như sau:

<div class="row"> <?php echo $form->labelEx($model,'create_time'); ?> <?php echo $form->textField($model,'create_time'); ?> <?php echo $form->error($model,'create_time'); ?> </div> <div class="row"> <?php echo $form->labelEx($model,'create_user_id'); ?> <?php echo $form->textField($model,'create_user_id'); ?> <?php echo $form->error($model,'create_user_id'); ?> </div> <div class="row"> <?php echo $form->labelEx($model,'update_time'); ?> <?php echo $form->textField($model,'update_time'); ?> <?php echo $form->error($model,'update_time'); ?> </div> <div class="row"> <?php echo $form->labelEx($model,'update_user_id'); ?> <?php echo $form->textField($model,'update_user_id'); ?> <?php echo $form->error($model,'update_user_id'); ?> </div>

Từ form user trong : protected/views/user/_form.php chúng ta xóa bỏ thuộc tính last login time

Page 25: Vocabulary Yiiframework

<div class="row"> <?php echo $form->labelEx($model,'last_login_time'); ?> <?php echo $form->textField($model,'last_login_time'); ?> <?php echo $form->error($model,'last_login_time'); ?></div>

chúng ta cũng nên loại bỏ các quy tắc xác nhận quy định cho các trường này trong các method quy tắc liên quanTrong method User::rules() method, xóa đi 2 rules sau:

array('create_user_id, update_user_id', 'numerical', 'integerOnly'=>true),array('last_login_time, create_time, update_time', 'safe'),

Làm tương tự với 2 model còn lại là :project, issue. Xóa bỏ các trường liên quan tới dữ liệu vừa xóa.

Thêm trường xác thực mật khẩu:Thêm lên bên đầu trang user:

public $password_repeat;

User::rules() method thêm :

array('password', 'compare'),

array('password_repeat', 'safe'),

Vào protected/views/user/_form thêm trường nhập lại mật khẩu :

<div class="row"> <?php echo $form->label($model,'password_repeat'); ?> <?php echo $form->passwordField($model,'password_repeat',array('size'=>60,'maxlength'=>256)); ?> <?php echo $form->error($model,'password_repeat'); ?></div>

Mã hóa mật khẩu:Mở CheckUserActiveRecord trong protected/models/ và thực hiện:

/** * perform one-way encryption on the password before we store it in the database */ protected function afterValidate() { parent::afterValidate(); $this->password = $this->encrypt($this->password); } public function encrypt($value) { return md5($value); }

XÁC THỰC USER sử dụng DATABASEGiới thiệu Yii authentication modellà một thành phần ứng dụng, người sử dụng, trong đó, trong trường hợp chung nhất, là một đối tượng thực hiện giao diện IWebUser. Các lớp học cụ thể được sử dụng bằng cách thực hiện mặc định của chúng tôi là lớp khung, CWebUser. Thành phần này người sử dụng đóng gói tất cả các thông tin nhận dạng cho người sử dụng hiện tại của ứng dụng. Thành phần này đã được cấu hình cho chúng ta như là một phần của mã ứng dụng tự động tạo ra khi chúng tôi bước đầu tạo ra ứng dụng của chúng tôi sử dụng công cụ yiic. Cấu hình có thể được nhìn thấy trong các tập tin được protected / config / main.php'user'=>array( // enable cookie-based authentication 'allowAutoLogin'=>true,

Page 26: Vocabulary Yiiframework

),

Vì nó là cấu hình như một thành phần ứng dụng, với key(user) , chúng ta có thể truy cập nó ở bất kỳ nơi nào trong suốt ứng dụng của chúng tôi bằng cách sử dụng Yii:: app () -> user.Chúng ta thấy rằng allowAutoLogin, đang được thiết lập ở đây là khá ổn. Thiết lập này là false theo mặc định, nhưng việc thiết lập nó là true cho phép thông tin người dùng được lưu trữ trong các cookie của trình duyệt liên tục. Những thông tin này sau đó được sử dụng để tự động xác thực người dùng khi lần ghé thăm sau này. Đây là những gì sẽ cho phép chúng ta có một tài khoản Ghi nhớ hộp kiểm trên các hình thức đăng nhập để, nếu người dùng lựa chọn, họ có thể được tự động đăng nhập vào ứng dụng khi lần ghé thăm sau để vào trang web.Khung xác thực Yii định nghĩa một thực thể riêng biệt để nhà logic thẩm định thực tế. Điều này được gọi là một lớp học nhận dạng, và trong hình thức chung nhất của nó là một lớp mà thực hiện các giao diện IUserIdentity. Một trong những vai trò chính của lớp này là để đóng gói logic xác thực dễ dàng cho phép triển khai khác nhau. Tùy thuộc vào yêu cầu ứng dụng, chúng tôi có thể cần phải xác nhận một tên người dùng và mật khẩu đối với giá trị được lưu trữ trong một cơ sở dữ liệu, hoặc cho phép người dùng đăng nhập với OpenID thông tin của họ, hoặc tích hợp với một phương pháp tiếp cận LDAP hiện có. Tách logic đó là cụ thể phương pháp xác thực từ phần còn lại của quá trình đăng nhập ứng dụng cho phép chúng ta dễ dàng chuyển đổi giữa hiện thực như vậy.

Vào protected/components/UserIdentity.php

Xem qua nội dung của Identity ta thấy việc thực hiện này chỉ đơn giản là sử dụng tên đăng nhập / mật khẩu mã hóa cứng các giá trị của bản demo / demo và quản trị admin /. Nó kiểm tra các giá trị đối với tên người dùng và các thuộc tính của lớp mật khẩu (tài sản quy định tại các lớp cha mẹ, CUserIdentity) và nếu họ không phù hợp, nó sẽ thiết lập và trả về một mã lỗi thích hợp.Mô hình hoạt động của quá trình đăng nhập được mô tả như sau:

Để hiểu rõ hơn về những mảnh phù hợp với toàn bộ quá trình xác thực end-to-end, chúng ta hãy đi qua các logic bắt đầu với hình thức đăng nhập. Nếu chúng ta điều hướng đến trang đăng nhập: http://localhost/demo/index.php?r=site/login, chúng ta thấy một hình thức đơn giản cho phép đầu

Page 27: Vocabulary Yiiframework

vào của một tên người dùng, mật khẩu và tùy chọn hộp kiểm cho các tài khoản Ghi nhớ Thời gian Tiếp theo chức năng mà chúng tôi thảo luận trước khi. Trình đơn này gọi logic trong SiteController:: actionLogin () phương pháp. Sơ đồ trình tự sau đây mô tả sự tương tác lớp xảy ra trong quá trình đăng nhập thành công từ thời điểm này dưới hình thứcđược gửi.

Quá trình bắt đầu với việc thiết lập các thuộc tính lớp học về mô hình hình thức, LoginForm, với các giá trị hình thức trình. LoginForm-> phương thức validate () sau đó được gọi, trong đó xác nhận các giá trị thuộc tính dựa trên các quy tắc quy định trong phương pháp quy định (). Phương pháp này được quy định như sau:

public function rules()

{

return array(

// username and password are required

array('username, password', 'required'),

// rememberMe needs to be a boolean

array('rememberMe', 'boolean'),

// password needs to be authenticated

array('password', 'authenticate'),

);

}

Cuối cùng của các quy tắc này quy định rằng thuộc tính mật khẩu được xác nhận bằng cách sử dụng các tùy chỉnh phương pháp authenticate (), cũng được định nghĩa trong lớp LoginForm như sau:

/**

* Authenticates the password.

* This is the 'authenticate' validator as declared in rules().

*/

public function authenticate($attribute,$params)

{

$this->_identity=new UserIdentity($this->username,$this->password);

if(!$this->_identity->authenticate())

$this->addError('password','Incorrect username or password.');

}

Tiếp tục thực hiện theo các sơ đồ trình tự, xác nhận mật khẩu trong LoginForm cuộc gọi authenticate () phương pháp trong cùng một lớp. Phương pháp này tạo ra một thể hiện mới của lớp danh tính xác thực được sử dụng, trong trường hợp này là / protected/ component/ UserIdentity.php bảo vệ, và sau đó gọi xác thực của nó authenticate (). UserIdentity :: authenticate () như sau:

/**

* Authenticates the password.

* This is the 'authenticate' validator as declared in rules().

*/

Page 28: Vocabulary Yiiframework

public function authenticate($attribute,$params)

{

if(!$this->hasErrors()) // we only want to authenticate when no

input errors

{

$identity=new UserIdentity($this->username,$this->password);

$identity->authenticate();

switch($identity->errorCode)

{

case UserIdentity::ERROR_NONE:

$duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days

Yii::app()->user->login($identity,$duration);

break;

case UserIdentity::ERROR_USERNAME_INVALID:

$this->addError('username','Username is incorrect.');

break;

default: // UserIdentity::ERROR_PASSWORD_INVALID

$this->addError('password','Password is incorrect.');

break;

}

}

}

Điều này được thực hiện để sử dụng tên người dùng và mật khẩu để thực hiện xác thực của nó. Trong việc thực hiện này, miễn là sự kết hợp tên người dùng / mật khẩu là một trong hai bản demo / demo hoặc admin / admin, phương pháp này sẽ trở lại đúng sự thật. Khi chúng ta đang đi qua một đăng nhập thành công, chứng thực thành công và đăng nhập () phương pháp trên các thành phần ứng dụng người dùng.

THAY ĐỔI QUÁ TRÌNH THỰC HIỆN XÁC THỰC

Bây giờ chúng ta hiểu toàn bộ quá trình xác thực, chúng ta có thể dễ dàng nhìn thấy nơi mà chúng ta cần phải thực hiện thay đổi để sử dụng bảng tbl_user của chúng tôi để xác nhận tên người dùng và các thông tin mật khẩu được cung cấp theo hình thức đăng nhập. Chúng ta có thể thay đổi authenticate() trong class Useridentity để xác minh sự tồn tại của một hàng phù hợp với tên người dùng cung cấp và giá trị mật khẩu. Kể từ khi, vào lúc này, có không có gì khác trong class UserIdentity.php ngoại trừ authenticate method, chúng ta hãy thay thế hoàn toàn các nội dung của tập tin này với các mã sau đây:

<?php/** * UserIdentity represents the data needed to identity a user. * It contains the authentication method that checks if the provided

Page 29: Vocabulary Yiiframework

* data can identify the user. */class UserIdentity extends CUserIdentity{ private $_id; /** * Authenticates a user using the User data model. * @return boolean whether authentication succeeds. */

public function authenticate() { $user=User::model()->findByAttributes(array('username'=>$this->username)); if($user===null) { $this->errorCode=self::ERROR_USERNAME_INVALID; } else { if($user->password!==$user->encrypt($this->password)) { $this->errorCode=self::ERROR_PASSWORD_INVALID; } else { $this->_id = $user->id; if(null===$user->last_login_time) { $lastLogin = time(); }else { $lastLogin = strtotime($user->last_login_time); } $this->setState('lastLoginTime', $lastLogin); $this->errorCode=self::ERROR_NONE; } } return !$this->errorCode; } public function getId() { return $this->_id; }}

Chúng ta đã thiết lập một thuộc tính mới vào class UserIdentity cho ID người dùng. Việc thực hiện mặc định trong các lớp cha mẹ là để trả lại tên người dùng cho ID. Như chúng ta đang sử dụng một cơ sở dữ liệu, và có các phím số tiểu nhận dạng người dùng duy nhất, chúng ta phải chắc chắn rằng ID số này là những gì được thiết lập và trả lại trong suốt các ứng dụng khi các ID người dùng được yêu cầu. Đó là, khi các mã: Yii:: app () -> user-> id được thực thi, chúng ta phải đảm bảo rằng ID duy nhất từ cơ sở dữ liệu được trả về, không phải tên người dùng.

KẾ THỪA Ứng dụng các thuộc tính User

Page 30: Vocabulary Yiiframework

Điều thứ hai xảy ra ở đây là các thiết lập của một thuộc tính trên User Identity là thời gian đăng nhập cuối cùng trở về từ cơ sở dữ liệu. Thành phần ứng dụng người dùng, CWebUser, có nguồn gốc thuộc tính người dùng ID rõ ràng và các thuộc tính tên được định nghĩa trong class indentity , và sau đó từ tên => cặp giá trị trong mảng được gọi từ state identity.

chúng tôi đã thiết lập các thuộc tính có tên là lastLoginTime là giá trị của trường last_login_time trong cơ sở dữ liệu. Bằng cách này, ở bất kỳ nơi nào trong ứng dụng, thuộc tính này có thể được truy cập thông qua:Yii:: app () -> user-> lastLoginTime;Khi các hàng người dùng ban đầu vào bảng với các giá trị null cho thời gian đăng nhập cuối cùng,có một kiểm tra nhanh chóng cho null để chúng tôi có thể lưu trữ một thời điểm thích hợp khingười sử dụng các bản ghi trong thời gian đầu tiên.Với những thay đổi này tại chỗ, bây giờ bạn sẽ cần phải cung cấp đúng tên và mật khẩu kết hợp cho một người dùng được xác định trong bảng tbl_user trong cơ sở dữ liệu. Sử dụng demo / demo hoặc admin / quản trị sẽ, tất nhiên, công việc không còn.Hãy cho nó một thử. Bạn có thể đăng nhập như bất kỳ một trong những người sử dụng mà bạn đã tạo ra trước đó trong chương này. Nếu bạn làm theo và có các dữ liệu người dùng như chúng tôi, các thông tin sau đây nên làm việc:Tên đăng nhập: Test_User_OneMật khẩu: test1

CẬP NHẬT NGƯỜI DÙNG CÓ THỜI GIAN ĐĂNG NHẬP CUỐI CÙNGNhư chúng ta đã đề cập trước đó trong chương này, chúng tôi loại bỏ thời gian đăng nhập cuối cùng như một trường đầu vào của người dùng tạo ra các hình thức, nhưng chúng tôi vẫn cần thêm logic để cập nhật lĩnh vực này. Như chúng ta đang theo dõi thời gian đăng nhập cuối cùng trong bảng cơ sở dữ liệu tbl_user, chúng ta cần phải cập nhật lĩnh vực này cho phù hợp sau khi đăng nhập thành công. Khi đăng nhập thực tế xảy ra trong LoginForm:: login () phương pháp trong lớp mô hình hình thức, chúng ta hãy cập nhật giá trị này. Thêm các dòng sau đây nhấn mạnh đến LoginForm:: login () method:

/** * Logs in the user using the given username and password in the model. * @return boolean whether login is successful */ public function login() { if($this->_identity===null) { $this->_identity=new UserIdentity($this->username,$this->password); $this->_identity->authenticate(); } if($this->_identity->errorCode===UserIdentity::ERROR_NONE) { $duration=$this->rememberMe ? 3600*24*30 : 0; // 30 days Yii::app()->user->login($this->_identity,$duration); User::model()->updateByPk($this->_identity->id, array('last_login_time'=>new CDbExpression('NOW()'))); return true; } else return false; }

Page 31: Vocabulary Yiiframework

Ở đây chúng ta đang kêu gọi updateByPk () phương pháp như là một cách tiếp cận hiệu quả để chỉ đơn giản là cập nhật hồ sơ User, chỉ định khóa chính cũng như một loạt các tên => cặp giá trị cho các cột mà ta muốn cập nhật.

Hiển thị lần đăng nhập cuối cùng ngoài trang chủMở : protected/views/site/index.php <h1>Welcome to <i><?php echo CHtml::encode(Yii::app()->name); ?></i></h1><?php if(!Yii::app()->user->isGuest):?><p> You last logged in on <?php echo date( 'l, F d, Y, g:i a', Yii::app()->user->lastLoginTime ); ?>. </p><?php endif;?>

CHƯƠNG 8 : ĐIỀU KHIỂN Sự Truy Cập của Người DùngCó hai phương pháp có liên quan đến kiểm soát truy cập của người dùng ví dụ trong ProjectController :, ProjectController:: filter () và ProjectController:: accessRules (). Các mã cho phương pháp đầu tiên được liệt kê như sau:/** * @return array action filters */public function filters(){ return array( 'accessControl', // thực hiện điều khiển truy cập cho CRUD operations );}

Phương thức thứ 2 được sử dụng như sau:/** * Specifies the access control rules. * This method is used by the 'accessControl' filter. * @return array access control rules

Page 32: Vocabulary Yiiframework

*/ public function accessRules() { return array( array('allow', // cho phép người dùng thực hiện 'index' and 'view' actions 'actions'=>array('index','view'), 'users'=>array('*'), ), array('allow', // cho phép chứng thực người dùng với 'create' and 'update' actions 'actions'=>array('create','update'), 'users'=>array('@'), ), array('allow', // cho phép admin user thực hiện 'admin' and 'delete' actions

'actions'=>array('admin','delete'), 'users'=>array('admin'), ), array('deny', // Từ chối truy cập 'users'=>array('*'), ), ); }

Method filter () đã quen thuộc với chúng ta. Nó là nơi mà chúng ta xác định tất cả các filter được sử dụng trong lớp điều khiển. Trong trường hợp này, chúng tôi đã chỉ có một, accessControl, trong đó đề cập đến một bộ lọc được cung cấp bởi khung Yii. Bộ lọc này sử dụng phương pháp khác, accessRules (), trong đó xác định các quy tắc điều khiển hạn chế truy cập.

Trong phương pháp accessRules () đã đề cập trước đây, có bốn quy tắc quy định. Mỗi quy tắc được thể hiện như là một mảng (array) . Yếu tố đầu tiên của mảng có thể cho phép (allow) hoặc từ chối (deny). Chỉ ra việc cấp hoặc từ chối truy cập. Phần còn lại của mảng bao gồm tên => cặp giá trị quy định cụ thể các thông số còn lại của quy tắc.

Quy tắc truy cập có thể được định nghĩa bằng cách sử dụng một số các thông số bối cảnh. Các quy tắc được đề cập trước đó xác định những hành động và người sử dụng để tạo ra bối cảnh quy tắc, nhưng có một số người khác được liệt kê như sau:• Controller: Quy tắc này quy định cụ thể một mảng của các ID controller các quy tắc áp dụng.• Roles: Quy tắc này quy định cụ thể danh sách các item ủy quyền (roles,operation,premission) mà rule áp dụng. Điều này làm cho sử dụng các tính năng RBAC chúng tôi sẽ được thảo luận trong phần tiếp theo.• Ips: Quy tắc này quy định cụ thể danh sách các địa chỉ client IP mà rule này được áp dụng.• Verbs: Quy tắc này quy định cụ thể các loại yêu cầu HTTP (GET, POST, và như vậy) áp dụng cho quy tắc này.• Expression: Quy tắc này quy định cụ thể một biểu thức PHP có giá trị cho thấy có hay không có quy tắc nên được áp dụng.• Action: Quy tắc này quy định cụ thể các phương thức hành động, bằng cách sử dụng ID hành động tương ứng, mà nguyên tắc phải phù hợp với.Users : Quy tắc này quy định cụ thể người sử dụng các quy tắc áp dụng. Thuộc tính tên người sử dụng ứng dụng hiện tại được sử dụng cho phù hợp. Ba ký tự đặc biệt cũng có thể được sử dụng ở đây:° *: bất kỳ người dùng°: vô danh người dùng° @: xác thực người sử dụng

Page 33: Vocabulary Yiiframework

Thay đổi ứng dụng của chúng ta để từ chối các user vô danh truy cập vào tất cả các project,issue,User chức năng liên quan là một snap. Tất cả chúng ta phải làm là thay đổi '*' ký tự đặc biệt của người sử dụng mảng giá trị ký tự đặc biệt của '@'. Điều này chỉ sẽ cho phép xác thực người dùng truy cập vào các hành động điều khiển các actionIndex () và ActionView (). Tất cả các hành động khác đã được hạn chế cho người sử dụng chứng thực.Hãy làm cho thay đổi này trong tất cả các bộ điều khiển của chúng tôi. Mở tất cả các ba của các tập tin sau đây: ProjectController.php, IssueController.php, và các tập tin UserController.php và thay đổi rule đầu tiên trong các quy tắc kiểm soát truy cập được:

array('allow', // allow only authenticated users to perform 'index' and 'view' actions 'actions'=>array('index','view'), 'users'=>array('@'),),

Sau khi thực hiện những thay đổi này, ứng dụng sẽ yêu cầu đăng nhập trước khi truy cập vào bất kỳ dự án, vấn đề của chúng tôi, hoặc chức năng của người sử dụng. Chúng tôi vẫn cho phép người dùng truy cập vô danh với phương pháp hành động SiteController lớp học, chúng tôi lưu giữ bởi vì đây là nơi hành động của mình đăng nhập.

VAI TRÒ KIỂM SOÁT TRUY NHẬPBây giờ chúng ta đã sử dụng các bộ lọc accessControl đơn giản như một nét rộng để hạn chế truy cập cho người sử dụng chứng thực, chúng ta cần để biến tập trung để đáp ứng một số nhu cầu kiểm soát truy cập chi tiết hơn của ứng dụng. Như chúng ta đã đề cập, người dùng sẽ đóng vai trò nhất định trong một dự án. Dự án sẽ có người sử dụng của chủ sở hữu loại, những người có thể được dùng như các quản trị viên dự án. Họ sẽ được cấp tất cả các truy cập để thao tác các dự án. Dự án cũng sẽ có người sử dụng loại thành viên, những người sẽ được cấp một số chức năng dự án, nhưng một tập hợp con của những chủ sở hữu có thể thực hiện. Cuối cùng, dự án có thể có người sử dụng loại đầu đọc, những người chỉ có thể xem nội dung dự án liên quan và không làm thay đổi nó bằng bất cứ cách nào. Để đạt được điều này loại mô hình truy cập dựa trên vai trò của một người sử dụng, chúng tôi lần lượt các tính năng RBAC của Yii.RBAC là một cách tiếp cận được thành lập trong hệ thống an ninh máy tính để quản lý các quyền truy cập của người sử dụng chứng thực. Trong ngắn hạn, các phương pháp tiếp cận RBAC xác định vai trò trong một ứng dụng. Quyền sử dụng để thực hiện một số hoạt động cũng được xác định và sau đó kết hợp với vai trò. Người dùng sau đó được giao cho một vai trò và thông qua các hiệp hội vai trò, có được các điều khoản quy định cho vai trò đó. Có rất nhiều tài liệu có sẵn cho người đọc tò mò về các khái niệm RBAC nói chung và phương pháp tiếp cận. Một nguồn thông tin tốt là Wikipedia: http://en.wikipedia.org/wiki/Role-based_access_control. Chúng tôi sẽ tập trung vào các chi tiết cụ thể thực hiện Yii của RBAC.Thực hiện Yii của RBACYii thực hiện các RBAC là đơn giản, thanh lịch, và mạnh mẽ. Tại nền tảngcủa RBAC trong Yii là ý tưởng của các item ủy quyền. Các item uỷ quyền chỉ đơn giản là một sự cho phép làm những việc trong ứng dụng. Các điều khoản có thể được phân loại như vai trò, nhiệm vụ, hoặc các hoạt động, và như vậy, tạo thành một hệ thống phân cấp cho phép. Vai trò có thể bao gồm các nhiệm vụ (hoặc các vai trò khác), nhiệm vụ có thể bao gồm các hoạt động (hoặc các nhiệm vụ khác) và các hoạt động là mức độ cho phép tiết nhất.Ví dụ, trong ứng dụng TrackStar của chúng tôi, chúng ta cần một vai trò kiểu của chủ sở hữu. Vì vậy, chúng ta sẽ tạo ra một mục ủy quyền về vai trò của loại với tên chủ sở hữu. Vai trò này sau đó có thể bao gồm các nhiệm vụ như một "quản lý người dùng" và "quản lý vấn đề". Những nhiệm vụ này có thể sau đó tiếp tục bao gồm các hoạt động nguyên tử tạo nên những công việc này. Ví dụ, các nhiệm vụ

Page 34: Vocabulary Yiiframework

quản lý người sử dụng có thể bao gồm các hoạt động tạo người dùng mới, người sử dụng chỉnh sửa, và xóa người sử dụng. Hệ thống cấp bậc này cho phép kế thừa các điều khoản như vậy đó, đưa ra ví dụ này, nếu người dùng được phân công vai trò chủ sở hữu, họ thừa hưởng được sự cho phép để thực hiện tạo, chỉnh sửa, và xóa các hoạt động người dùng.Dịch văn bản hoặc trang webĐiển hình trong RBAC, bạn chỉ định một người sử dụng một hoặc nhiều vai trò và người sử dụng kế thừa các quyền đã được giao cho những vai trò. Điều này đúng cho RBAC trong Yii là tốt. Tuy nhiên, trong mô hình này, chúng tôi có thể kết hợp người dùng cho bất kỳ mục ủy quyền, không chỉ những kiểu vai trò. Điều này cho phép chúng ta sự linh hoạt để kết hợp một sự cho phép người dùng ở bất kỳ mức độ granularity. Nếu chúng ta chỉ muốn cấp các hoạt động người sử dụng xóa một người dùng cụ thể, và không cung cấp cho họ tất cả các truy cập vào một vai trò chủ sở hữu sẽ có,chúng tôi chỉ đơn giản là có thể kết hợp người sử dụng này hoạt động nguyên tử. Điều này làm cho RBAC trong Yii rất linh hoạt.

CẤU HÌNH QUẢN LÝ ỦY QUYỀNTrước khi chúng ta có thể thiết lập một hệ thống phân cấp ủy quyền, phân công người sử dụng các vai trò, và thực hiện kiểm tra sự cho phép truy cập, chúng ta cần phải cấu hình ứng dụng các thành phần ủy quyền quản lý, authManager. Thành phần này có trách nhiệm lưu trữ các dữ liệu cho phép và quản lý các mối quan hệ giữa quyềncũng như cung cấp các phương pháp kiểm tra có hay không một người dùng không có quyền truy cậpđể thực hiện một hoạt động cụ thể. Yii cung cấp hai loại của các nhà quản lý uỷ quyền: CPhpAuthManager và CDbAuthManager. CPhpAuthManager sử dụng một tập tin script PHP để lưu trữ các dữ liệu cho phép. CDbAuthManager, như bạn có thể đoán, lưu trữ dữ liệu ủy quyền trong một cơ sở dữ liệu. AuthManager được cấu hình như một thành phần ứng dụng. Cấu hình quản lý uỷ quyền bao gồm đơn giảnchỉ định của hai loại sử dụng và sau đó thiết lập ban đầu giá trị tài sản lớpNhư chúng ta đã sử dụng một cơ sở dữ liệu trong các ứng dụng TrackStar, nó làm cho cho chúng tôi sử dụng CDbAuthManager. Để thực hiện cấu hình này, mở file cấu hình chính protected/config/main.php và thêm dòng sau vào component array:

'authManager'=>array( 'class'=>'CDbAuthManager', 'connectionID'=>'db',),

Thiết lập thành phần ứng dụng mới có tên là authManager, quy định cụ thể thuộc tính của class là CdbAuthManager,thiết lập connectionID là thành phần kết nối tới CSDL Bây giờ chúng ta có thể truy cập này bất cứ nơi nàoứng dụng của chúng ta bằng cách sử dụng Yii:: app () -> authManager.

TẠO BẢNG CSDL RBAC (Lưu ý..Tạo cả 3 table vào trong database CSDL) Như đã đề cập, lớp CDbAuthManager sử dụng các bảng cơ sở dữ liệu để lưu trữ các dữ liệu cho phép. Nó là tiêu chuẩn lược đồ đặc biệt. Đó là sơ đồ được xác định trong tập tin khuôn khổ YiiRoot / framework / web / auth / schema.sql. Nó là một sơ đồ đơn giản bao gồm ba bảng, AuthItem, AuthItemChild, và AuthAssignment. Bảng AuthItem giữ thông tin xác định mục ủy quyền, đó là vai trò, nhiệm vụ hoặc hoạt động. Bảng AuthItemChild nhà các mối quan hệ cha / con hình thành hệ thống phân cấp của

Page 35: Vocabulary Yiiframework

chúng ta về các item ủy quyền. Cuối cùng, bảng AuthAssignment là một bảng liên kết giữ mối liên hệ giữa một người sử dụng và một mục cho phép. Các báo cáo DDL cơ bản cho các bảng như sau:(Lưu ý đây là lược đồ mặc định đã được tạo sẵn khi thực hiện tạo khung) Để dễ dàng chúng ta thực hiện luôn với các table đã có sẵn.

TẠO HỆ THỐNG PHÂN CẤP ỦY QUYỀN RBACSau khi thêm các bảng đã đề cập _dev và _test các cơ sở dữ liệu, chúng ta cần phải phổ biến chúng với vai trò và quyền truy cập. Chúng ta sẽ làm điều này bằng cách sử dụng API được cung cấp bởi authManager. Để giữ cho mọi thứ đơn giản, chúng ta sẽ chỉ xác định vai trò và hoạt động cơ bản.Chúng ta sẽ không thiết lập bất kỳ nhiệm vụ RBAC nào chính thức cho bây giờ. Hình dưới đây hiển thị hệ thống cấp bậc cơ bản chúng ta xác định:

Người chủ(Admin,Developer)Create user (tạo mới người sử dụng)Update user(cập nhật người sử dụng)

Delete user(xóa bỏ người sử dụng)Update project (cập nhật dự án)

Delete project (xóa dự án)(thừa hưởng sự cho phép từ cả 2 thành viên và độc giả).

(inherits permission from both member and reader)

||||\/

Thành viênCreate Issue (Tạo mới sản phẩm)Update Issue(Cập nhật sản phẩm)Delete Issue (Xóa bỏ sản phẩm)(Thừa hưởng quyền truy cập từ độc giả).

||||

\/Độc giảRead member (Đọc được danh sách thành viên)Read Project (Đọc được các dự án)Read Issue (Đọc được các sản phẩm).

Page 36: Vocabulary Yiiframework

Chủ sở hữu có tất cả các quyền được liệt kê, cộng với họ thừa hưởng tất cả các quyền từ thành viên và vai trò đọc. Tương tự như vậy, thành viên được thừa hưởng quyền truy cập từ Reader. Những gì chúng tôi bây giờ cần phải làm là thiết lập hệ thống phân cấp trong ứng dụng cho phép này. Như đã đề cập trước đó, cách tốt nhất để làm điều này là để viết mã để sử dụng các API authManager. Ví dụ, các mã sau đây tạo ra một vai trò mới và hoạt động mới và sau đó cho biết thêm các mối quan hệ giữa vai trò và sự cho phép:$auth=Yii::app()->authManager; $role=$auth->createRole('owner'); $auth->createOperation('createProject','create a new project'); $role->addChild('createProject');

Thêm vai trò RBAC cho các dự ánBây giờ chúng ta có một mô hình RBAC ủy quyền cơ bản tại chỗ, nhưng những mối quan hệ này áp dụng đối với các ứng dụng như một toàn thể. Nhu cầu của chúng tôi cho các ứng dụng TrackStar là hơi phức tạp hơn. Chúng ta cần xác định vai trò trong bối cảnh của dự án, không chỉ trên toàn cầu qua các ứng dụng. Chúng ta cần phải cho phép người sử dụng trong vai trò khác nhau, tùy thuộc vào dự án. Ví dụ, người dùng có thể được trong vai trò người đọc của một dự án, thành viên của một dự án thứ hai, và chủ sở hữu của một số dự án thứ ba. Người dùng có thể được liên kết với nhiều dự án, và vai trò mà họ được giao nhiệm vụ cần phải được cụ thể cho dự án.

Page 37: Vocabulary Yiiframework

Các mô hình RBAC chỉ nhằm mục đích thiết lập các mối quan hệ giữa các vai trò và quyền truy cập. Nó không biết (và cũng không nên nó) bất cứ điều gì về các dự án TrackStar của chúng tôi. Để đạt được điều này kích thước thêm hệ thống phân cấp ủy quyền của chúng tôi, chúng tôi sẽ tạo ra một bảng cơ sở dữ liệu riêng biệt để duy trì mối quan hệ giữa người sử dụng, vai trò và một dự án. Các khởi tạo DDL cho bảng này là như sau: phi vào (/webroot/framework/web/auth/schema-mysql.sql)create table tbl_project_user_role( project_Id INTEGER NOT NULL, user_Id INTEGER NOT NULL, role VARCHAR(64) NOT NULL, primary key (project_Id,user_Id,role), foreign key (project_Id) references tbl_project (id), foreign key (user_Id) references tbl_user (id), foreign key (role) references AuthItem (name));

Thêm các quy tắc kinh doanh RBACMặc dù các bảng cơ sở dữ liệu trước đó sẽ tổ chức các thông tin cơ bản để trả lời các câu hỏi như liệu người dùng được giao cho một vai trò trong bối cảnh của một dự án cụ thể, chúng ta vẫn cần hệ thống phân cấp ủy quyền RBAC của chúng tôi để trả lời các câu hỏi liên quan đến user có quyền hay không thực hiện chức năng nhất định. Mặc dù mô hình RBAC trong Yii không thiết lập về các dự án TrackStar của chúng tôi, nó có một tính năng rất mạnh mẽ mà chúng ta có thể tận dụng lợi thế. Khi bạn tạo các ủy quyền hoặc phân công một mục cho người sử dụng, bạn có thể kết hợp một đoạn mã PHP sẽ được thực hiện gọi Yii:: app() -> user-> checkAccess (). Khi định nghĩa, bit của mã này phải trả lại true trước khi user được cấp phép.Một ví dụ về tính hữu ích của tính năng này là trong bối cảnh của các ứng dụng cho phép người sử dụng để duy trì thông tin hồ sơ cá nhân. Thông thường trong trường hợp này, các ứng dụng muốn đảm bảo rằng một người sử dụng có sự cho phép cập nhật thông tin hồ sơ cá nhân của riêng mình và không ai khác. Trong trường hợp này chúng ta có thể tạo ra một mục ủy quyền được gọi là updateProfile, và sau đó kết hợp một quy tắc kinh doanh để kiểm tra xem ID của người sử dụng hiện tại cũng giống như ID người sử dụng kết hợp với thông tin hồ sơ.Trong trường hợp này, chúng ta sẽ kết hợp một quy tắc kinh doanh với sự phân công vai trò. Khi chúng ta chỉ định một người sử dụng có một vai trò cụ thể, chúng ta cũng sẽ liên kết một quy tắc kinh doanh kiểm tra các mối quan hệ trong bối cảnh của dự án. CheckAccess () phương pháp cũng cho phép chúng ta vượt qua trong một loạt các thông số bổ sung cho các quy tắc kinh doanh sử dụng để thực hiện logic của nó. Chúng tôi sẽ sử dụng điều này để vượt qua trong bối cảnh dự án hiện tại để các quy tắc kinh doanh có thể gọi một phương thức trên lớp các dự án AR để xác định có hay không sử dụng được giao cho vai trò đó trong dự án đó. Nguyên tắc kinh doanh chúng ta sẽ tạo ra phân quyền cho từng vai trò khác nhau. Ví dụ một người dùng sau khi được phân quyền là owner (bản thân) có vai trò giống như sau: $bizRule='return isset($params["project"]) && $params["project"]->isUserInRole('owner');';Một member(thành viên) hay một reader(độc giả) cũng thực hiện tương tự.Chúng tôi cũng sẽ phải hoàn thành trong văn cảnh dự án khi chúng ta gọi checkAccess (). Vì vậy, bây giờ khi kiểm tra nếu người dùng đã truy cập vào, ví dụ, operation createIssue ta sử dụng: $params=array('project'=>$project); if(Yii::app()->user->checkAccess('createIssue',$params)){ //tạo ra truy cập với issue logic

Page 38: Vocabulary Yiiframework

}

Thực hiện method Project AR mới

Điều chỉnh Project::associateUserToRole() method để có các thông số, và luôn luôn thêm một hàng (row) tới tbl_project_user_role table:

public function associateUserToRole($role, $userId){ $sql = "INSERT INTO tbl_project_user_role (project_Id, user_Id, role) VALUES (:projectId, :userId, :role)"; $command = Yii::app()->db->createCommand($sql); $command->bindValue(":projectId", $this->id, PDO::PARAM_INT); $command->bindValue(":userId", $userId, PDO::PARAM_INT); $command->bindValue(":role", $role, PDO::PARAM_STR); return $command->execute;}

Ở đây chúng ta đang sử dụng class Yii khung CDbCommand để thực hiện một câu lệnh SQL đối với cơ sở dữ liệu. một thể hiện của CDbCommand là những gì được trả về từ hàm gọi createCommand () kết nối cơ sở dữ liệu. Chúng ta cũng sử dụng các giá trị ràng buộc của tham số của chúng ta bằng cách sử dụng bindValue () phương pháp trên các CDbCommand. Đây là một thực hành tốt có thể làm giảm nguy cơ các cuộc tấn công SQL injection cũng như giúp cải thiện hiệu suất của các câu lệnh SQL được thực hiện nhiều lần.

Tiếp đến là : loại bỏ một mối liên hệ giữa các dự án, người sử dụng và vai trò của người sử dụng trong dự án.public function removeUserFromRole($role, $userId) { $sql = "DELETE FROM tbl_project_user_role WHERE project_Id=:projectId AND user_Id=:userId AND role=:role"; $command = Yii::app()->db->createCommand($sql); $command->bindValue(":projectId", $this->id, PDO::PARAM_INT); $command->bindValue(":userId", $userId, PDO::PARAM_INT); $command->bindValue(":role", $role, PDO::PARAM_STR); return $command->execute(); }Điều này chỉ đơn giản là xóa các hàng từ bảng nhà mối liên hệ giữavai trò, người sử dụng và dự án. Nó sẽ trả lại số hàng bị ảnh hưởng, trong đó,nếu nó thành công trong việc xóa một hàng.

Bây giờ chúng ta cần phải thực hiện logic thích hợp để xem nếu một liên kết tồn tại. Thay đổi phương thức này trong các class Project AR public function isUserInRole($role) { $sql = "SELECT role FROM tbl_project_user_role WHERE project_id=:projectId AND user_id=:userId AND role=:role"; $command = Yii::app()->db->createCommand($sql); $command->bindValue(":projectId", $this->id, PDO::PARAM_INT);

Page 39: Vocabulary Yiiframework

$command->bindValue(":userId", Yii::app()->user->getId(), PDO::PARAM_INT); $command->bindValue(":role", $role, PDO::PARAM_STR); return $command->execute()==1 ? true : false; }

THÊM NGƯỜI DÙNG từ Dự án (project)Chúng ta đã có thể tạo được người dùng trong ứng dụng tuy nhiên chúng ta chưa có cách gán cho người dùng một dự án cụ thể.Và hơn thế nữa vai trò của chúng trong ứng dụng.Bây giờ chúng ta tiếp cận vị trí của RBAC chúng ta cần xây một hàm mới.Hoàn thành các mục đích chúng ta sẽ thực hiện sau đây:+ Sử dụng phương pháp đầu tiên : thêm method public static getUserRoleOptions() từ Project model class trả lại danh sách hợp lệ vai trò cấu hình sử dụng quản lý quyền truy cập getRoles() method. Chúng ta sẽ sử dụng phổ biến một vai trò lựa chọn dropdown field trong form cho việc thêm user của một dự án (project).+ thêm mới method public associateUserToProject($user) từ project model class để liên kết một người sử dụng với 1 dự án.Thêm đường dẫn tới table tbl_project_user_assignment để tạo một sự liên kết giữa user và project.+ Thêm mới method public isUserInProject($user) từ Project model class để quyết định nếu người dùng bắt đầu liên kết với project. Chúng ta sẽ sử dụng điều đó trong một quy tắc phù hợp từ form để ra quyết định chúng ta không kích hoạt thêm một bản sao người dùng đã có trong dự án.+ THêm mới một form model class ProjectUserForm mở rộng từ CformModel cho input form model mới. Thêm mô hình class form này có 3 thuộc tính :$username,$role,$project .Cũng thêm các quy tắc phù hợp để chắc chắn rằng cả username và role là được yêu cầu input field và người sử dụng sẽ được xác nhận là khách hàng hợp lệ verify() class. Verify() method sẽ thực hiện : Kích hoạt tạo mới User AR class đưa việc tìm kiếm user nối với input username.Nếu kích hoạt thành công nó sẽ tiếp tục liên kết user với project sử dụng method mới là :associateUserToProject($user) . Nếu không có user được tìm thấy nó sẽ trả về thông báo lỗi .

+ Thêm views/project/adduser.php trưng bày form cho việc thêm user tới project.Form này chỉ cần 2 trường là :username và role với thuộc tính là dropdown danh sách.+ THêm mới controller action method gọi là actionAdduser() từ ProjectController class và chỉnh sửa accessRules() method để xác thực thành viên (member). Action mới này xử lý cho biểu diễn view mới được hiển thị từ form và điều khiển post quay lại khi form được submit.THỰC HIỆN: Điều chỉnh lại Project Model Class

Page 40: Vocabulary Yiiframework

/** * Returns an array of available roles in which a user can be placed when being added to a project */ public static function getUserRoleOptions() { return CHtml::listData(Yii::app()->authManager->getRoles(), 'name', 'name'); } /** * Makes an association between a user and a the project */ public function associateUserToProject($user) { $sql = "INSERT INTO tbl_project_user_assignment (project_id, user_id) VALUES (:projectId, :userId)"; $command = Yii::app()->db->createCommand($sql);$command->bindValue(":projectId", $this->id, PDO::PARAM_INT); $command->bindValue(":userId", $user->id, PDO::PARAM_INT); return $command->execute(); } /* * Determines whether or not a user is already part of a project */ public function isUserInProject($user) { $sql = "SELECT user_id FROM tbl_project_user_assignment WHERE project_id=:projectId AND

user_id=:userId"; $command = Yii::app()->db->createCommand($sql); $command->bindValue(":projectId", $this->id, PDO::PARAM_INT); $command->bindValue(":userId", $user->id, PDO::PARAM_INT); return $command->execute()==1 ? true : false; }

Thêm mới form model class ProjectUserForm Chỉ được dùng giống như form đăng nhập chúng ta đang tạo một form model class mới như là một

trung tâm lưu trữ form input các tham số và tập trung lại các user hợp lệ. Đây là một class đơn giản kế thừa từ Yii class Cform Model và có thuộc tính giống form input Chúng ta cần ngữ cảnh dự án có thể thêm user từ project :

<?php/** * ProjectUserForm class. * ProjectUserForm is the data structure for keeping * the form data related to adding an existing user to a project. It is used by the 'Adduser' action of

'ProjectController'. */class ProjectUserForm extends CFormModel{ /** * @var string username of the user being added to the project */

Page 41: Vocabulary Yiiframework

public $username; /** * @var string the role to which the user will be associated within the project */ public $role; /** * @var object an instance of the Project AR model class */ public $project; /** * Declares the validation rules. * The rules state that username and password are required, * and password needs to be authenticated using the verify() method */ public function rules() { return array( // username and password are required array('username, role', 'required'),// password needs to be authenticated //array('username', 'verify'), array('username', 'exist', 'className'=>'User'), array('username', 'verify'), ); } /** * Authenticates the existence of the user in the system. * If valid, it will also make the association between the user, role and project * This is the 'verify' validator as declared in rules(). */ public function verify($attribute,$params) { if(!$this->hasErrors()) // we only want to authenticate when no other input errors are present { $user = User::model()->findByAttributes(array('username'=>$this->username)); if($this->project->isUserInProject($user)) { $this->addError('username','This user has already been added to the project.'); } else { $this->project->associateUserToProject($user); $this->project->associateUserToRole($this->role, $user->id); $auth = Yii::app()->authManager; $bizRule='return isset($params["project"]) && $params["project"]->isUserInRole("'.$this->role.'");'; $auth->assign($this->role,$user->id, $bizRule); } } }}

Page 42: Vocabulary Yiiframework

Thêm mới action method từ project controllerChúng ta cần một controller action điều khiển quá trình tải các yêu cầu để hiển thị form thêm user tới

một project .Thêm actionAdduser() vào Project Controller:

public function actionAdduser() { $form=new ProjectUserForm; $project = $this->loadModel(); // collect user input data if(isset($_POST['ProjectUserForm'])) { $form->attributes=$_POST['ProjectUserForm']; $form->project = $project; // validate user input and set a sucessfull flassh message if valid if($form->validate()) { Yii::app()->user->setFlash('success',$form->username . " has been added to the project." ); $form=new ProjectUserForm; } } // display the add user form $users = User::model()->findAll(); $usernames=array(); foreach($users as $user) { $usernames[]=$user->username; } $form->project = $project; $this->render('adduser',array('model'=>$form, 'usernames'=>$usernames)); }

Một thay đổi nữa ta phải làm với ProjectController class, đó là thêm action method mới để truy cập các quy tắc cơ bản để user được phép truy cập vào action này :

public function accessRules() { return array( array('allow', // allow all users to perform 'index' and 'view' actions 'actions'=>array('index','view', 'adduser'), 'users'=>array('@'), ), …

Thêm file mới trong view hiển thị FormTạo : protected/views/project/adduser.php

<?php$this->pageTitle=Yii::app()->name . ' - Add User To Project';$this->breadcrumbs=array( $model->project->name=>array('view','id'=>$model->project->id), 'Add User',

Page 43: Vocabulary Yiiframework

);$this->menu=array( array('label'=>'Back To Project', 'url'=>array('view','id'=>$model->project->id)),);?><h1>Add User To <?php echo $model->project->name; ?></h1><?php if(Yii::app()->user->hasFlash('success')):?> <div class="successMessage"> <?php echo Yii::app()->user->getFlash('success'); ?> </div><?php endif; ?><div class="form"><?php $form=$this->beginWidget('CActiveForm'); ?> <p class="note">Fields with <span class="required">*</span> are required.</p> <div class="row"> <?php echo $form->labelEx($model,'username'); ?> <?php $this->widget('CAutoComplete', array( 'model'=>$model, 'attribute'=>'username', 'data'=>$usernames, 'multiple'=>false, 'htmlOptions'=>array('size'=>25), )); ?> <?php echo $form->error($model,'username'); ?> </div> <div class="row"> <?php echo $form->labelEx($model,'role'); ?> <?php echo $form->dropDownList($model,'role', Project::getUserRoleOptions()); ?> <?php echo $form->error($model,'role'); ?> </div> <div class="row buttons"> <?php echo CHtml::submitButton('Add User'); ?> </div><?php $this->endWidget(); ?></div>

KIỂM TRA MỨC ĐỘ ỦY QUYỀNĐiều cuối cùng chúng ta cần phải làm là kiểm tra thêm uỷ quyền cho các chức năng khác nhau .Trước đó trong chương này, chúng ta đã phác thảo và sau đó thực hiện hệ thống phân cấp ủy quyền RBAC cho các vai trò khác nhau chúng ta có. Tất cả mọi thứ được đặt ra để cho phép hoặc từ chối truy cập đến các chức năng dựa trên các điều khoản đã được cấp cho người sử dụng trong các dự án, với một ngoại lệ. Chúng tôi chưa thực hiện kiểm tra truy cập cần thiết khi cố gắng để yêu cầu chức năng. Các ứng dụng vẫn còn sử dụng bộ lọc truy cập đơn giản được định nghĩa trên mỗi dự án, phát hành và người sử dụng bộ điều khiển của chúng tôi. Chúng tôi sẽ làm điều này cho một trong các điều khoản của chúng tôi và sau đó để thực hiện còn lại như một bài tập cho người đọc.

Tại Protected/views/project/view.php thêm vào sau danh sách menu ta có :if(Yii::app()->user->checkAccess('admin',array('project'=>$model))){

$this->menu[] = array('label'=>'Add User To Project', 'url'=>array('adduser', 'id'=>$model->id));}

Page 44: Vocabulary Yiiframework

Lưu ý quyền truy cập admin lấy từ authitem table .Tất cả các member được admin cấp phép đều có thể vào được.Tiếp theo để ngăn chặn việc user vào bằng navigate ta thêm hàm kiểm tra vào actionAdduser() :

public function actionAdduser() { $project = $this->loadModel(); if(!Yii::app()->user->checkAccess('createUser', array('project'=>$project))) { throw new CHttpException(403,'You are not authorized to per-form this action.'); } $form=new ProjectUserForm; // collect user input data …

CHƯƠNG 9 Thêm User Comment (Lời nhắn user).Việc đầu tiên của các tính năng mà chúng tôi sẽ giải quyết là

khả năng cho người dùng để lại ý kiến về các vấn đề của dự án.Khả năng cho người dùng tham gia vào một cuộc đối thoại về các vấn đề của dự án là một phần quan trọng của bất kỳ công cụ theo dõi vấn đề cung cấp. Một cách để đạt được điều này là cho phép người dùng để lại ý kiến trực tiếp về các vấn đề. Các ý kiến sẽ hình thành một cuộc trò chuyện về vấn đề này và cung cấp một ngay lập tức, cũng như bối cảnh lịch sử để giúp theo dõi tuổi thọ của bất kỳ vấn đề nào. Chúng tôi cũng sẽ sử dụng để chứng minh sử dụng Yii vật dụng và thiết lập một mô hình portlet cung cấp nội dung cho người sử dụng (để biết thêm thông tin về Portlet, hãy truy cập http://en.wikipedia.org/wiki/Portlet).

Kế Hoạch:Khi một người dùng đang xem các chi tiết của bất kỳ vấn đề dự án, họ sẽ có thể đọc tất cả các ý kiến

trước đây đã được thêm vào như là cũng như tạo ra một nhận xét mới về vấn đề này. Chúng tôi cũng muốnthêm một mảnh nhỏ của nội dung, portlet, trang dự án niêm yết có hiển thịmột danh sách các ý kiến gần đây còn lại trên tất cả các vấn đề. Đây sẽ là một cách tốt đẹp để cung cấpmột cửa sổ vào hoạt động người dùng gần đây và cho phép dễ dàng truy cập đến các vấn đề mới nhất có cuộc trò chuyện hoạt động.

Sau đây là một danh sách các task (nhiệm vụ ) mà chúng ta sẽ cần phải hoàn thành để đạt được những mục tiêu:• Thiết kế và tạo ra một bảng cơ sở dữ liệu mới để hỗ trợ ý kiến• Tạo class AR Yii liên quan với bảng thảo luận mới của chúng tôi• Thêm một form trực tiếp đến trang chi tiết sản phẩm để cho phép người sử dụnggửi ý kiến• Hiển thị một danh sách của tất cả các ý kiến liên kết với một sản phẩm trực tiếp trên các trang chi tiết các vấn đề.• Tận dụng lợi thế của widget Yii để hiển thị một danh sách các ý kiến gần đây nhất trên trang danh sách các dự án (project).

Tạo mô hìnhTạo table vào database :

Page 45: Vocabulary Yiiframework

CREATE TABLE tbl_comment( `id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, `content` TEXT NOT NULL, `issue_id` INTEGER, `create_time` DATETIME, `create_user_id` INTEGER, `update_time` DATETIME, `update_user_id` INTEGER )

Những lời comment được xác định trong từng trang cụ thể ta xác định tại trang sản phẩm với issue_id và nó được viết bởi một người sử dụng cụ thể nên tạo create_user_id và xác định các quan hệ khóa chính khóa ngoại.

ALTER TABLE `tbl_comment` ADD CONSTRAINT `FK_comment_issue` FOREIGN KEY (`issue_id`) REFERENCES `tbl_issue` (`id`);ALTER TABLE `tbl_comment` ADD CONSTRAINT `FK_comment_author` FOREIGN KEY (`create_user_id`) REFERENCES `tbl_user` (`id`);

Xây dựng mô hình trong Gii / Model Generator và gọi class comment.->click preview->generate.

khi chúng ta đã tạo ra model class cho comment , chúng ta sẽ cần thêm một cách rõ ràng mối quan hệ từ class model Issue (sản phẩm) cho comment. Chúng ta cũng sẽ thêm một mối quan hệ như là một truy vấn thống kê để dễ dàng lấy số lượng các ý kiến liên kết với một vấn đề được đưa ra (giống như chúng ta đã làm trong class Project cho Issue.).

Điều chỉnh Issue::relation() (quan hệ):

public function relations(){ return array( 'requester' => array(self::BELONGS_TO, 'User', 'requester_id'), 'owner' => array(self::BELONGS_TO, 'User', 'owner_id'), 'project' => array(self::BELONGS_TO, 'Project', 'project_id'), 'comments' => array(self::HAS_MANY, 'Comment', 'issue_id'), 'commentCount' => array(self::STAT, 'Comment', 'issue_id'), );}

Ngoài ra, chúng ta cần phải thay đổi class Comment AR được mở rộng tùy chỉnh từ TrackStarActiveRecord class base , để thuận lợi chúng ta đặt trong beforeValidate () method . Đơn giản chỉ cần thay đổi đầu của định nghĩa lớp như vậy:

<?php /** * This is the model class for table "tbl_comment".

Page 46: Vocabulary Yiiframework

*/class Comment extends TrackStarActiveRecord (cũng có thể là CheckUserActiveRecord) .{

Chúng ta sẽ thay đổi nhỏ để các định nghĩa trong Comment::relation() method. Các thuộc tính quan hệ được đặt tên cho chúng ta khi class model được tạo ra. Chúng ta hãy thay đổi một trong những tên createUser là author , vì điều này liên quan đến người sử dụng không đại diện cho tác giả của bình luận. Đây chỉ là một sự thay đổi ngữ nghĩa, nhưng sẽ giúp đỡđể làm cho mã của chúng tôi dễ dàng hơn để đọc và hiểu. Thay đổi method trong Comment::relation:

/** * @return array relational rules. */ public function relations() { // NOTE: you may need to adjust the relation name and the related // class name for the relations automatically generated below. return array( 'author' => array(self::BELONGS_TO, 'User', 'create_user_id'), 'issue' => array(self::BELONGS_TO, 'Issue', 'issue_id'), ); }

Creating the Comment CRUD Vào gii thực hiện với comment và click preview->generate.

Sau khi chúng ta đăng nhập , chúng ta sẽ có thể xem các lời comment trình autogenerated thông qua URL sau:

http://localhost/trackstar/index.php?r=comment/createNhư chúng ta đã thấy nhiều lần trước đây, chúng ta thường phải thực hiện điều chỉnh mã

autogenerated scaffolding để đáp ứng các yêu cầu cụ thể của ứng dụng. Đối với một, hình thức autogenerated của chúng tôi để tạo ra một nhận xét mới có một trường đầu vào cho mỗi cột duy nhất được xác định trong bảng cơ sở dữ liệu tbl_comment.

Chúng ta không thực sự muốn tất cả các trường DL hiện ra trong biểu mẫu. Trong thực tế, chúng ta cần làm đơn giản hóa form này chỉ có một lĩnh vực đầu vào duy nhất cho nội dung bình luận (content comment) . Hơn nữa, chúng ta không muốn người dùng truy cập các hình thức thông qua các URL trên, nhưng thay vì chỉ cần truy cập vào trang chi tiết sản phẩm . Người dùng sẽ thêm ý kiến trên cùng một trang mà họ đang xem thông tin chi tiết về sản phẩm này. Chúng ta cần xây dựng hướng tới một cái gì đó tương tự như những gì được mô tả trong các ảnh chụp màn hình sau đây:

Page 47: Vocabulary Yiiframework

Để thực hiện được điều này, ta sẽ điều chỉnh Issue controller class để xử lý các comment cũng như thay đổi chi tiết sản phẩm hiển thị các lời comment hiện có và tạo comment mới từ form.Ngoài ra lời comment sẽ chỉ được tạo trong văn cảnh của sản phẩm chúng ta sẽ thêm mới một method vào class model Issue để tạo mới commment.

Thêm một lời commentThêm method trong Issue AR (model)

/** * Adds a comment to this issue */public function addComment($comment){ $comment->issue_id=$this->id; return $comment->save();}

Phương pháp này đảm bảo các thiết lập phù hợp của các ID vấn đề bình luận trước khi lưu các bình luận mới. Khởi động thử nghiệm một lần nữa để đảm bảo nó ngay bây giờ đi.

Chúng ta muốn tạo comment form để hiển thị và gửi dữ liệu trở lại IssueController::actionView() method , chúng ta sẽ cần điều chỉnh method. Chúng ta cũng thêm mới method protected điều khiển form POST request. Đầu tiên, chỉnh lại actionView() method :

public function actionView(){ $issue=$this->loadModel();

Page 48: Vocabulary Yiiframework

$comment=$this->createComment($issue); $this->render('view',array( 'model'=>$issue, 'comment'=>$comment, ));}

Tạo function createComment:protected function createComment($issue){ $comment=new Comment; if(isset($_POST['Comment'])) { $comment->attributes=$_POST['Comment']; if($issue->addComment($comment)) { Yii::app()->user->setFlash('commentSubmitted',"Your comment has been added." ); $this->refresh(); } } return $comment;}

createComment () chịu trách nhiệm xử lý các yêu cầu POST để tạo ra một bình luận mới dựa trên đầu vào người sử dụng. Nếu comment tạo ra thành công, trang sẽ được làm mới hiển thị các nhận xét mới được tạo ra. Các thay đổi được thực hiện để IssueController:: ActionView () chịu trách nhiệm cho cuộc gọi phương pháp mới này và cũng có thể cho ăn các trường hợp nhận xét mới để xem.

Hiển thị Form Bây giờ ta cần chỉnh lại view. Ta phải tạo file view mới render hiển thị những lời comment và

comment input form.Tạo file _comments.php vào protected/view/issue/ :

<?php foreach($comments as $comment): ?><div class="comment"> <div class="author"> <?php echo $comment->author->username; ?>: </div> <div class="time"> on <?php echo date('F j, Y \a\t h:i a',strtotime($comment->create_time)); ?> </div> <div class="content"><?php echo nl2br(CHtml::encode($comment->content)); ?> </div> <hr></div><!-- comment --><?php endforeach; ?>

Mở protected/view/issue/view.php thêm vào cuối file :

<div id="comments"> <?php if($model->commentCount>=1): ?>

Page 49: Vocabulary Yiiframework

<h3> <?php echo $model->commentCount>1 ? $model->commentCount . ' comments' : 'One comment'; ?> </h3> <?php $this->renderPartial('_comments',array( 'comments'=>$model->comments, )); ?> <?php endif; ?> <h3>Leave a Comment</h3> <?php if(Yii::app()->user->hasFlash('commentSubmitted')): ?> <div class="flash-success"> <?php echo Yii::app()->user->getFlash('commentSubmitted'); ?> </div> <?php else: ?> <?php $this->renderPartial('/comment/_form',array( 'model'=>$comment, )); ?> <?php endif; ?></div>

Mở protected/views/comment/_form.php và chỉnh sửa :

<div class="form"><?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'comment-form', 'enableAjaxValidation'=>false,)); ?> <p class="note">Fields with <span class="required">*</span> are required.</p> <?php echo $form->errorSummary($model); ?> <div class="row"> <?php echo $form->labelEx($model,'content'); ?> <?php echo $form->textArea($model,'content',array('rows'=>6, 'cols'=>50)); ?> <?php echo $form->error($model,'content'); ?> </div> <div class="row buttons"> <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?> </div><?php $this->endWidget(); ?></div>

Tạo một comments widget gần đây.

Bây giờ chúng ta có khả năng để lại ý kiến trong sản phẩm, chúng ta sẽ tập trung vào mục tiêu thứ 2. Chúng ta muốn để hiển thị cho người dùng một danh sách của tất cả các ý kiến gần đây đã được đăng trong các trang sản phẩm khác nhau trên tất cả các dự án. Điều này sẽ cung cấp liên kết tốt các hoạt động truyền thông người dùng trong ứng dụng. Chúng tôi cũng muốn xây dựng khối nhỏ của nội dung này trong một cách mà sẽ cho phép tái sử dụng tại các địa điểm khác nhau trong trang web. Điều này là rất nhiều trong phong cách của các ứng dụng cổng thông tin web như diễn đàn tin tức, các ứng dụng báo cáo thời tiết và các trang web như Yahoo và iGoogle. Những đoạn nhỏ của nội dung thường được gọi là portlet, và đây là lý do tại sao chúng tôi gọi xây dựng một kiến trúc portlet đầu lặp đi lặp lại này. Một lần nữa, bạn có thể tham khảohttp://en.wikipedia.org/wiki/Portlet cho biết thêm thông tin về chủ đề này

Page 50: Vocabulary Yiiframework

Giới thiệu CWidgetChúng tôi sẽ sử dụng một widget Yii để xây dựng một ý kiến gần đây của portlet và hiển thị nó trên trang chính của dự án chi tiết để chúng ta có thể thấy hoạt động của bình luận trên tất cả các vấn đề liên quan đến dự án. Để chứng minh sự dễ dàng tái sử dụng, chúng tôi sẽ mang nó một bước xa hơn và cũng có thể hiển thị một danh sách các dự án cụ thể ý kiến về trang chi tiết dự án.

Tạo hàm :Tìm comment gần đây: Trong Comment::findRecentComment.

public static function findRecentComments($limit=10, $projectId=null){ if($projectId != null) { return self::model()->with(array( 'issue'=>array('condition'=>'project_id='.$projectId)))->findAll(array( 'order'=>'t.create_time DESC', 'limit'=>$limit, )); } else { //get all comments across all projects return self::model()->with('issue')->findAll(array( 'order'=>'t.create_time DESC', 'limit'=>$limit, )); }}

Method trê n có 2 tham số $limit để hạn chế số lượng, $projectId xác định id dự án mà các comment nằm trong đó. Tham số thứ 2 sẽ giúp cho widget sử dụng hiển thị tất cả comment trong 1 dự án. Vì vậy, nếu id đầu vào dự án đã được chỉ định, nó hạn chế các kết quả trả về chỉ những ý kiến liên kết với dự án, nếu không, tất cả các ý kiến trên tất cả các các dự án được trả lại.

Thêm chi tiết về các truy vấn AR quan hệ trong YiiHai truy vấn trên quan hệ AR một chút mới cho chúng tôi. Chúng tôi đã không được sử dụng

rất nhiều các tùy chọn này trong các truy vấn trước đó của chúng tôi. Trước đây, chúng tôi đã được sử dụng phương pháp đơn giản nhất để thực hiện các truy vấn quan hệ:1. Tải instance AR.2. Truy cập thuộc tính quan hệ được định nghĩa trong method relation ().

Ví dụ, nếu chúng ta muốn truy vấn cho tất cả các sản phẩm (Issue) liên quan tới dự án(Project) có id # 1, chúng tôi sẽ thực hiện hai dòng mã sau đây:

// retrieve the project whose ID is 1$project=Project::model()->findByPk(1);// retrieve the project's issues: a relational query is actually being performed behind the scenes here$issues=$project->issues;

Đây là một phương thức hơi chậm tại vì nó còn chờ có mã id hợp lệ mới thực hiện.Nếu như có quá nhiều dự án cần tải tương ứng với quá nhiều id cần nạp điều này sẽ gây ra việc chậm trễ. Vì thế chúng ta cần phải dùng giải pháp tốt hơn.

Eager Loading là một giải pháp truy xuất vào quan hệ của AR cài đặt cùng một time như trong trường hợp AR chính được yêu cầu. Điều này được dùng với with() method kết hợp cả find() hoặc findAll() method cho AR query. Ta thực hiện như sau :

//retrieve all project AR instances along with their associated issue AR instances

Page 51: Vocabulary Yiiframework

$projects = Project::model()->with('issues')->findAll();

Trong Comment::findRecentComments() ta có :return self::model()->with('issue')->findAll(array('order'=>'t.create_time DESC','limit'=>$limit,));chúng ta chỉ định t.create_time cho biết ta muốn sử dụng cột của bảng chính. Nếu chúng ta muốn thay

vì để các cột create_time issue , chúng tôi sẽ thay đổi, truy vấn thứ hai ví dụ, như sau:return Comment::model()->with('issue')->findAll(array( 'order'=>'issue.create_time DESC', 'limit'=>$limit,));

Để hoàn thành những gì ta đang thực hiện ta mở IssueController::loadModel() method :

public function loadModel($withComments=false) { if($this->_model===null) { if(isset($_GET['id'])) { if($withComments) { $this->_model=Issue::model()->with(array( 'comments'=>array('with'=>'author'))) ->findbyPk($_GET['id']); } else{ $this->_model=Issue::model()->findbyPk($_GET['id']); } } if($this->_model===null) throw new CHttpException(404,'The requested page does not exist.'); } return $this->_model; }

Thay đổi IssueController::actionView(), as such:

public function actionView() { $issue=$this->loadModel(true)

Thực hiện tạo WidgetBây giờ chúng ta đã sẵn sàng để tạo ra các widget mới của chúng tôi sử dụng phương pháp

mới của chúng tôi để hiển thị comment recent của chúng tôi.Như chúng ta đã đề cập một widget trong Yii là một class extend từ CWidget framework . Chúng ta sẽ thêm widget mới của chúng tôi để được protected / component / , như các nội dung của thư mục này đã được quy định trong các file cấu hình chính để tự động tải về ứng dụng. Bằng cách này, chúng tôi sẽ không phải nhập khẩu một cách rõ ràng lớp mỗi lần chúng tôi muốn sử dụng nó. Chúng ta sẽ đặt tên RecentComments widget của chúng tôi, vì vậy chúng tôi cần thêm một tập tin php cùng tên thư mục. Thêm định nghĩa class RecentComment.php đến tập tin mới được tạo ra như sau:

protected / component / RecentComments.php

<?php/**

Page 52: Vocabulary Yiiframework

* RecentComments is a Yii widget used to display a list of recent comments */class RecentComments extends CWidget{ private $_comments; public $displayLimit = 5; public $projectId = null; public function init(){ $this->_comments = Comment::model() ->findRecentComments($this->displayLimit, $this->projectId); } public function getRecentComments() { return $this->_comments; } public function run() { // this method is called by CController::endWidget() $this->render('recentComments'); }}

Công việc chính khi tạo ra một widget mới là để ghi đè lên init () và run () lớp cơ sở. (method ) init khởi tạo các widget và được gọi là thuộc tính của nó đã được khởi tạo. Phương thức run () thực hiện các widget. Trong trường hợp này, chúng tôi chỉ cần khởi tạo các widget bằng cách yêu cầu ý kiến gần đây dựa trên $ displayLimit và projectId thuộc tính. Thực hiện của widget chỉ đơn giản là làm cho tập tin xem có liên quan đến viewfile , mà chúng ta vẫn chưa tạo ra. các tập tin xem, theo quy ước, được đặt trong view / directly trong cùng một thư mục widget cư trú, và có tên tương tự như widget, nhưng bắt đầu với một lá thư chữ thường. Tạo tập tin trong protecd/component / views / recentComments.php.

<ul> <?php foreach($this->getRecentComments() as $comment): ?> <div class="author"> <?php echo $comment->author->username; ?> added a comment. </div> <div class="issue"> <?php echo CHtml::link(CHtml::encode($comment->issue->name), array('issue/view', 'id'=>$comment-

>issue->id)); ?> </div> <?php endforeach; ?></ul>

Mở protected/views/project/index.php. Thêm vào cuối trang<?php $this->widget('RecentComments'); ?>

Giới thiệu Cportlet:CPortlet là một phần của zii, mở rộng lớp thư viện chính thức đóng gói đi kèm với Yii. Nó cung cấp một lớp cơ sở tốt đẹp cho tất cả các vật dụng theo phong cách portlet. Nó sẽ cho phép chúng ta làm cho một tiêu đề tốt đẹp cũng như phù hợp HTML đánh dấu, vì vậy tất cả các portlet trên các ứng dụng có thể dễ dàng theo kiểu một cách tương tự. Một khi chúng ta có một tiện ích làm cho nội dung (như phụ tùng RecentComments của chúng tôi), chúng tôi chỉ đơn giản là có thể sử dụng nội dung trả lại

Page 53: Vocabulary Yiiframework

của các phụ tùng của chúng tôi như nội dung cho CPortlet, mà bản thân nó là một tiện ích, như nó cũng mở rộng từ CWidget. Chúng ta có thể làm điều này bằng cách đặt cuộc gọi của chúng tôi để các widget RecentComments giữa một beginWidget () và một endWiget () gọi cho CPortlet, như vậy:Thay thế vào protected/project/index

<?php $this->beginWidget('zii.widgets.CPortlet', array( 'title'=>'Recent Comments',)); $this->widget('RecentComments');$this->endWidget(); ?>Thêm widget vào trang khác :Add the following to the bottom of the protected/views/project/view.php file:<?php $this->beginWidget('zii.widgets.CPortlet', array( 'title'=>'Recent Project Comments',)); $this->widget('RecentComments', array('projectId'=>$model->id));$this->endWidget(); ?>

CHƯƠNG 10: Thêm một RSS web FeedCài Zend_Framework down: http://framework.zend.com/download/latest. Ta chỉ cần sử dụng gói nhỏ

(minimal).Giải nén và lấy Zend từ library : library/zend/feed. Chép vào Yii FM với đường dẫn ; protected/vendors/Zend/Feed.php

Sử dụng Zend_FeedOpen up CommentController.php and add the following public method:public function actionFeed(){ if(isset($_GET['pid'])) $projectId = intval($_GET['pid']); else $projectId = null; $comments = Comment::model()->findRecentComments(20, $projectId); //convert from an array of comment AR class instances to an name=>value array for Zend $entries=array(); foreach($comments as $comment) { $entries[]=array( 'title'=>$comment->issue->name, 'link'=>CHtml::encode($this->createAbsoluteUrl('issue/view',array('id'=>$comment->issue->id))), 'description'=> $comment->author->username . ' says:<br>' . $comment->content, 'lastUpdate'=>strtotime($comment->create_time), 'author'=>$comment->author->username, );

Page 54: Vocabulary Yiiframework

} //now use the Zend Feed class to generate the Feed // generate and render RSS feed $feed=Zend_Feed::importArray(array( 'title' => 'Trackstar Project Comments Feed', 'link' => $this->createUrl(''), 'charset' => 'UTF-8', 'entries' => $entries, ), 'rss'); $feed->send(); }

Bạn có thể nhớ rằng phương pháp này trả về một mảng các trường hợp Bình luận lớp AR. Chúng tôi lặp qua mảng này quay trở lại và chuyển đổi dữ liệu vào định dạng dự kiến bởi các thành phần Zend_Feed. Zend_Feed dự kiến sẽ một mảng đơn giản có chứa các yếu tố là mảng có chứa các dữ liệu cho mỗi mục nhận xét. Mỗi nhập cá nhân là một mảng kết hợp đơn giản của tên => cặp giá trị. Để thực hiện theo quy định với các định dạng RSS cụ thể, mỗi mục cá nhân của chúng tôi tối thiểu phải có tiêu đề, liên kết, và mô tả. Chúng tôi cũng đã bổ sung thêm hai lĩnh vực tùy chọn, một gọi là lastUpdate, Zend_Feed dịch lĩnh vực RSS pubDate, và một để xác định tác giả.Có thêm một vài phương pháp giúp đỡ chúng tôi tận dụng lợi thế để có được các dữ liệutrong định dạng đúng. Đối với một, chúng tôi sử dụng createAbsoluteUrl của các bộ điều khiển () phương pháp, chứ không phải chỉ createUrl () để tạo ra một URL đầy đủ.

Tạo /vendors/Zend/Feed.php

TẠO URL Thân thiện với người dùng.

Sử dụng UrlManager:

Được xây dựng trong quản lý URL trong Yii là một thành phần ứng dụng có thể được cấu hình trong tập tin được bảo vệ / config / main.php. Hãy mở tập tin đó và thêm một tuyên bố thành phần URL mới quản lý mảng các thành phần:'urlManager' => array ('urlFormat' => 'đường dẫn',),Miễn là chúng ta gắn bó với urlManager nó mặc định và tên, chúng tôi không cần phải xác định lớp của các thành phần bởi vì nó là trước khi kê khai để được CUrlManager.php trong lớp khuôn khổ CWebApplication.php.URL của chúng ta đang tìm kiếm tốt hơn, nhưng chúng ta vẫn có kịch bản nhập cảnh, index.php, quy định và chúng ta không có thể nối thêm hậu tố. Xml vào cuối URL cấp dữ liệu của chúng tôi. Vì vậy, chúng ta sẽ ẩn index.php như là một phần của URL, và cũng có thể thiết lập các yêu cầu định tuyến để hiểu rằng một yêu cầu cho commentfeed.xml thực sự có nghĩa là một yêu cầu cho actionFeed () trong lớp CommentController.php. Chúng ta hãy thực sự giải quyết vấn đề thứ hai đầu tiên.

Cấu Hình các quy tắc định tuyến (route).

Quản lý URL Yii cho phép chúng ta xác định quy tắc để xác định URL được phân tích cú pháp và tạo ra. Một nguyên tắc bao gồm xác định một tuyến đường và một mô hình. Mô hình này được sử dụng để phù hợp với trên một phần thông tin đường dẫn URL để xác định quy tắc được sử dụng để phân tích hoặc tạo ra các URL. Các mô hình có thể chứa các thông số được đặt tên bằng cách sử dụng các ParamName cú pháp: RegExp. Khi phân tích một URL, một quy tắc phù hợp sẽ trích xuất các thông số này được đặt tên từ các thông tin đường dẫn và đặt chúng vào biến $ _GET. Khi một URL được tạo ra bởi các ứng dụng, một quy tắc phù hợp sẽ trích xuất các thông số được đặt tên từ $ _GET và

Page 55: Vocabulary Yiiframework

đặt chúng vào phần thông tin đường dẫn URL được tạo ra. Nếu một mô hình kết thúc với'/*', nó có nghĩa là các tham số thêm GET có thể được nối thêm vào phần thông tin đường dẫn của URL.

Ta định tuyến vào UrlManager như sau:

'urlManager'=>array('urlFormat'=>'path','rules'=>array(

'<controller:\w+>/<id:\d+>'=>'<controller>/view','<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>','<controller:\w+>/<action:\w+>'=>'<controller>/<action>',

),

),

Loại bỏ các script từ URLBây giờ chúng ta chỉ cần loại bỏ index.php từ các URL. Điều này được thực hiện theo hai bước:1. Thay đổi cấu hình máy chủ web để định tuyến lại tất cả các yêu cầu không tương ứng với tập tin hoặc thư mục hiện có để index.php.2. Thiết lập thuộc tính showScriptName của UrlManager false.

Tạo htdocs/webroot/.htaccess :Options +FollowSymLinksIndexIgnore */*RewriteEngine on# if a directory or a file exists, use it directlyRewriteCond %{REQUEST_FILENAME} !-fRewriteCond %{REQUEST_FILENAME} !-d# otherwise forward it to index.phpRewriteRule . index.php

CHƯƠNG 11 :Làm thiết kế(design), trình bày(layout),giao diện(themes) tốt hơnTạo một chủ đề mới cho các ứng dụng của chúng tôi bằng cách tạo ra bố trí mới, CSS và các tập tin tài sản khác để cung cấp các ứng dụng với một thiết kế phía trước kết thúc mới

Page 56: Vocabulary Yiiframework

• Sử dụng các tính năng quốc tế và nội địa hoá của Yii dịchmột phần của ứng dụng của chúng tôi đến một ngôn ngữ mớiLoad CSS:<link rel="stylesheet" type="text/css" href="<?php echo Yii::app()->request->baseUrl; ?>/css/main.css" />Tiêu đề trang : <title><?php echo CHtml::encode($this->pageTitle); ?></title>

Creating a breadcrumb navigation

Ta có thể xem ví dụ này:<?php$this->breadcrumbs=array( 'Projects'=>array('index'), $model->name=>array('view','id'=>$model->id), 'Update',);

Chuyển dịch web sang một ngôn ngữ khác

Nó cung cấp dữ liệu miền địa phương cho gần như mọi ngôn ngữ và khu vựcNó cung cấp các dịch vụ hỗ trợ trong bản dịch của tin nhắn văn bản và tập tinNó cung cấp cho miền địa phương phụ thuộc vào ngày và thời gian định dạngNó cung cấp cho miền địa phương phụ thuộc vào định dạng số

Định nghĩa vùng miền(locate) và ngôn ngữ(language).Miền địa phương dùng để chỉ một tập hợp các thông số để xác định ngôn ngữ của người sử dụng, quốc gia, và sở thích giao diện người sử dụng nào khác có thể có liên quan đến vị trí của người dùng. Nó thường được xác định bởi một ID tổng hợp bao gồm một định danh ngôn ngữ và nhận dạng một khu vực. Ví dụ, một ID miền địa phương của vi là viết tắt của ngôn ngữ tiếng Anh và khu vực của Hoa Kỳ. Để thống nhất, tất cả các ID miền địa phương trong Yii được chuẩn hóa với định dạng hoặc LanguageID hoặc LanguageID_RegionID trong trường hợp thấp hơn (ví dụ, en hoặc en_us).Yii, miền địa phương dữ liệu được biểu diễn như là một thể hiện của lớp CLocale, một lớp con của chúng. Nó cung cấp thông tin miền địa phương cụ thể bao gồm cả biểu tượng tiền tệ và số tiền tệ, số, ngày, và các định dạng thời gian, tên liên quan đến ngày tháng như tháng, ngày trong tuần, và như vậy. Với một ID miền địa phương, người ta có thể có được thể hiện tương ứng CLocal bằng cách sử dụng các CLocal phương pháp tĩnh:: getInstance ($ localeID) hoặc sử dụng ứng dụng. Các mã ví dụ sau đây tạo ra một thể hiện mới dựa trên định danh địa phương en_us bằng cách sử dụng các thành phần ứng dụng:Yii::app()->getLocale(‘vi_vn’);Yii đi kèm với dữ liệu miền địa phương cho gần như mọi ngôn ngữ và khu vực. Dữ liệu đến từ các Repository Locale dữ liệu chung (CLDR) (http://cldr.unicode.org/) và được lưu trữ trong các tập tin được đặt tên theo id miền địa phương của mình trong Yii framework framework/i18n/data /. Vì vậy, trong ví dụ trên tạo ra một thể hiện mới CLocale, dữ liệu được sử dụng để đưa vào các thuộc tính từ framework/i18n/data/en_us.php tập tin. Nếu bạn nhìn dưới thư mục này, bạn sẽ thấy các tập tin dữ liệu cho các ngôn ngữ khác và khu vực.

THỰC HIỆN DỊCH NGÔN NGỮThực hiện dịch một thông điệp :t(string $category, string $message, array $params=array ( ), string $source=NULL, string $language=NULL)

Page 57: Vocabulary Yiiframework

CPhpMessageSource: Đây là nguồn thông điệp mặc định. Các bản dịch tin nhắn được lưu trữ như các cặp giá trị quan trọng trong một mảng PHP. Các thông báo ban đầu là chìa khóa và tin nhắn dịch là giá trị. Mỗi mảng đại diện cho các bản dịch cho một thể loại đặc biệt của tin nhắn vàlưu trữ trong một tập tin kịch bản riêng biệt của PHP có tên là tên loại.Các file PHP dịch cho cùng một ngôn ngữ được lưu trữ theocùng một thư mục có tên là ID miền địa phương. Tất cả các thư mục này đều nằm trongthư mục theo quy định của basePath.• CGettextMessageSource: Các bản dịch tin nhắn được lưu trữ như các tập tin gettext GNU.• CDbMessageSource: Các bản dịch tin nhắn được lưu trữ trong các bảng cơ sở dữ liệu.

Một nguồn message được nạp như một thành phần ứng dụng. Yii trước khi nhận dạng một thành phần ứng dụng có tên message để lưu trữ các tin nhắn được sử dụng trong một ứng dụng sử dụng. Theo mặc định, các loại nguồn tin nhắn này là CPhpMessageSource và con đường cơ sở để lưu trữ các tập tin bản dịch PHP là :protected/messages.Say đây là một ví dụ sẽ đi một chặng đường dài để giúp mang lại tất cả những điều này với nhau. Hãy dịch nhãn trường biểu mẫu đăng nhập của chúng tôi vào một ngôn ngữ giả tưởng chúng ta sẽ gọi VietNam. VietNam được viết bằng cách lấy một từ hoặc cụm từ tiếng Anh và viết nó theo chiều ngược lại. Vì vậy, đây là bản dịch field nhãn VietNam .

English VietNam

Username TenDangNhap

Password MatKhau

Remember me next time Ghi nho tai khoan

Chúng tôi sẽ sử dụng việc thực hiện CPhpMessageSource mặc định để nhà dịch tin nhắn của chúng tôi. Vì vậy, điều đầu tiên chúng ta cần làm là tạo ra một tập tin PHP có chứa các bản dịch của chúng tôi. Chúng ta sẽ tạo ID local là ‘vi’ và chúng ta sẽ gọi là "mặc định" danh mục cho bây giờ. Vì vậy, chúng ta cần tạo một file mới trong thư mục base message theo định dạng / localeID CategoryName.php /. Vì vậy, đối với ví dụ này, chúng ta cần để tạo ra một tập tin mới được đặt vào / protected / languages / vi / default.php, và sau đó thêm các mảng dịch thuật sau đây:

<?phpreturn array( 'Username' => 'Emanresu', 'Password' => 'Drowssap', 'Remember me next time' => 'Emit txen em rebmemer',);

Điều tiếp theo chúng ta cần làm để thiết lập chuyển ngôn ngữ sang tiếng Việt Nam.Ta có thể làm điều này trong file cấu hình,do đó nó sẽ tác động tới toàn bộ trang web.Tuy nhiên chúng ta chỉ có bản dịch mẫu của chúng ta,ta chỉ cần thiết lập nó trong SiteController::actionLogin() method,do đó nó chỉ áp dụng khi render cho login().Mở tập tin và thiết lập ngôn ngữ bắt đầu với method:

Page 58: Vocabulary Yiiframework

public function actionLogin(){ Yii::app()->language = 'vi';

Bây giờ, điều cuối cùng chúng ta cần làm là thực hiện gọi tới Yii:: t () để những trường (field) label được gửi thông qua bản dịch. Những field label vực được quy định tại các LoginForm:: attributeLabels () phương pháp. Thay thế phương pháp toàn bộ như sau:

/** * Declares attribute labels. */ public function attributeLabels() { return array( 'rememberMe'=>Yii::t('default','Remember me next time'), 'username'=>Yii::t('default', 'Username'), 'password'=>Yii::t('default', 'Password'), ); }

Thực hiện dịch tập tin:Yii cũng cung cấp khả năng sử dụng các tập tin khác nhau dựa trên Local ID. Dịch tập tin được thực hiện bằng cách gọi method CApplication:: findLocalizedFile (). Phương pháp này có trong đường dẫn vào một tập tin và phương pháp này sẽ tìm kiếm một tập tin có cùng tên, nhưng dưới một thư mục cùng tên với ID miền địa phương mục tiêu quy định hoặc như là đầu vào cho phép phương pháp, hoặc những gì được quy định cụ thể trong ứng dụng cấu hình.Tất cả chúng ta thực sự cần phải làm là tạo ra các tập tin bản dịch thích hợp. Chúng tôi sẽ gắn bó với dịch dưới hình thức đăng nhập. Vì vậy, tạo ra một tập tin views mới / protected / views / site / vi / login.php và thêm các nội dung sau đã được dịch sang Tiếng việt:

<?php$this->pageTitle='Nigol';$this->breadcrumbs=array( 'Dang nhap',);?><h1>Dang nhap</h1><p>Vui long dien day du thong tin:</p><div class="form"><?php $form=$this->beginWidget('CActiveForm', array( 'id'=>'login-form', 'enableAjaxValidation'=>true,)); ?> <p class="note">Vui long dien day du thong tin voi dau <span class="required">*</span> yeu cau.</p> <div class="row"> <?php echo $form->labelEx($model,'username'); ?> <?php echo $form->textField($model,'username'); ?> <?php echo $form->error($model,'username'); ?> </div> <div class="row"><?php echo $form->labelEx($model,'password'); ?><?php echo $form->passwordField($model,'password'); ?><?php echo $form->error($model,'password'); ?>

Page 59: Vocabulary Yiiframework

<p class="hint"><tt>nimda\nimda</tt> ro <tt>omed\omed</tt> htiw nigol yam uoy :tnih</p></div><div class="row rememberMe"><?php echo $form->checkBox($model,'rememberMe'); ?><?php echo $form->label($model,'rememberMe'); ?><?php echo $form->error($model,'rememberMe'); ?></div><div class="row buttons"><?php echo CHtml::submitButton('Nigol'); ?></div><?php $this->endWidget(); ?></div><!-- form -->

Thêm tin nhắn mở rộng từ hệ thóng

Tạo bảng databaseBạn tạo một bảng mới như sau chứ a thông tin tin nhắn từ hệ thống:

CREATE TABLE `tbl_sys_message` ( `id` INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, `message` TEXT NOT NULL, `create_time` DATETIME, `create_user_id` INTEGER, `update_time` DATETIME, `update_user_id` INTEGER )

Tạo modle CRUD scaffoldingSau khi đã có bảng database bạn thêm vào sql để tạo bảng và thực hiện bởi , the Gii code generator. Chúng ta bắt đầu sử dụng Model Generator option để tạo các class model và sau đó Crud Generator tạo cơ bản scaffolding nhanh chóng với model. Go ahead and navigate to the Gii tool form for creating a new model. This time, as we are doing this within the context of a module, we need to explicitly specify the model path. Fill out the form with the values depicted as shown in the following screenshot (though, of course, your Code Template path value should be specific to your local setup):

Page 60: Vocabulary Yiiframework

Tạo CRUD scaffolding in the same way. Again, the only real difference between what we have done previously and what we are doing now is our specification that the location of the model class is in the admin module. After choosing the Crud Generator option from the Gii tool, fill out the Model Class and Controller ID form fields as shown in the following screenshot: (Nhìn hình và đừng lo về mấy từ tiếng anh, k ảnh hưởng đến việc học đâu, lười ko muốn dịch =.=, dùng CRUD chán roài còn ko làm đc thì bó tay =.=)

This alerts the tool to the fact that our model class is under the admin module and that our controller class, as well as all other files related to this code generation should be placed within the admin module as well.

Hoàn thành bạn click vào Preview button, và sau đó là Generate. The following is a list of all of the files that are created by this action:

Page 61: Vocabulary Yiiframework

THêm link vào hàm mớiMở file chứa main menu chính từ, /protected/modules/admin/views/layouts/main.php, và thêm đoạn array sau vào menu widget:array('label'=>'System Messages', 'url'=>array('/admin/sysMessage/index')),

1. copy 2 bảng layout từ ngoài main application tới module: Đó là: copy /protected/views/layouts/column2.php tới /protected/modules/admin/views/layouts/column2.php.2. Xóa /layouts/main là input từ beginContent() method gọi trước dòng bạn vừa copied là column2.php file.3. Điều chỉnh SysMessage model class được extend (kế thừa) TrackstarActiveRecord (Nếu nó gọi lại, thêm code được tự động update ngoài create_time/user và update_time/user properties. Điều chỉnh SysMessageController controller class để sử dụng column column2.php layout file từ không chỉ 1 module folder từ main application. The autogenerated code has specified $layout='application.views.layouts.column2', but we need this to be simply $layout='column2'.4. Chúng ta được kế thừa từ TrackstarActiveRecord, chúng ta có thể xóa những field không cần thiết khi project tự sinh ra autogenerated sys messages creation form và xóa rules liên quan đến chúng (associated rules) from the model class. Xóa 2 rules sau từ SysMessage::rules() method: array('create_user, update_user', 'numerical', 'integerOnly'=>true), and array('create_time, update_time', 'safe').

One last change we should make is to update our simple access rules to reflect the requirement that only users in the admin role can access our action methods. This is mostly for illustrative purposes as we already took care of the access using our RBAC model approach in the AdminModule::beforeControlerAction method itself. We could actually just remove the accessRules entirely. However, let's just update them to reflect the requirement so you can see how that would work using the access rule approach. In the SysMessageController::accessRules() method, change the entire contents to the following:

public function accessRules(){ return array( array('allow', // allow only users in the 'admin' role access to our actions 'actions'=>array('index','view', 'create', 'update', 'admin', 'delete'), 'roles'=>array('admin'), ), array('deny', // deny all users

Page 62: Vocabulary Yiiframework

'users'=>array('*'), ), );}

Mở trình duyệt gõ: http://localhost/demo/admin/sysMessage/create, we are presented with something similar to the following screenshot:

Điền vào form message Hello Users! This is your admin speaking... và click Submit. The application will redirect you to the details listing page for this newly created message as shown in the following screenshot:

Displaying the message to users

Importing the new model class for application-wide accessIn order to access the newly created model from anywhere in our application, we need to import it as a part of the application configuration. Alter protected/config/main.php to include the new admin module models folder:

// autoloading model and component classes'import'=>array( 'application.models.*', 'application.components.*',

'application.modules.admin.models.*',

Page 63: Vocabulary Yiiframework

),

Selecting the most recently updated messageWe'll restrict the display to just one message, and we'll choose the most recently updated message, based on the update_time column in the table. As we want to add this to the main projects listing page, we need to alter the ProjectController::actionIndex() method. Alter that method by adding the following highlighted code:

public function actionIndex() { $dataProvider=new CActiveDataProvider('Project'); Yii::app()->clientScript->registerLinkTag( 'alternate', 'application/rss+xml', $this->createUrl('comment/feed'));

//get the latest system message to display based on the update_time column $sysMessage = SysMessage::model()->find(array( 'order'=>'t.update_time DESC', )); if($sysMessage != null) $message = $sysMessage->message; else $message = null;

$this->render('index',array( 'dataProvider'=>$dataProvider,

'sysMessage'=>$message, )); }

Now we need to alter our view file to display this new bit of content. Add the following to views/project/index.php, just above the <h1>Projects</h1> header text:

<?php if($sysMessage != null):?> <div class="sys-message"> <?php echo $sysMessage; ?> </div><?php endif; ?>

Now when we visit our projects listing page (that is, our application's home page) we can see it display as shown in the following screenshot:

BONUS Chờ đợi bản dịch tiếp theo với ebook:Yii 1.1 ApplicationDevelopment Cookbook

Page 64: Vocabulary Yiiframework

( Phát triển ứng dụng Yii 1.1 )http://www.seodrupal.vn