yii 1.1 development cookbook - vietnamese

179
153 [YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012 Yii 1.1 Application Development Cookbook Public: packpub Year : 2011 http://www.seodrupal.vn Translate by : longt8x email : [email protected] Everything you want supported please send request to email or yahoo : [email protected] , thank you! Bạn vào trang chủ : http://www.yiiframework.com/download/ Download phiên bản mới nhất về sau đó giải nén (extract here), sau đó rename lại là cookbook, copy folder cookbook mới giải nén vào C:\xampp\htdocs\, bạn phải down xampp về rồi cài đặt setup thành công thì chạy xampp center thiết lập apache và mysql running. http://localhost/cookbook/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. http://www.seodrupal.vn | Learn Drupal Online

Upload: badboyst

Post on 30-Oct-2014

274 views

Category:

Documents


3 download

TRANSCRIPT

Page 1: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Yii 1.1 Application Development Cookbook

Public: packpub

Year : 2011

http://www.seodrupal.vn

Translate by : longt8x email : [email protected]

Everything you want supported please send request to email or yahoo : [email protected], thank you!

Bạn vào trang chủ : http://www.yiiframework.com/download/

Download phiên bản mới nhất về sau đó giải nén (extract here), sau đó rename lại là cookbook, copy folder cookbook mới giải nén vào C:\xampp\htdocs\, bạn phải down xampp về rồi cài đặt setup thành công thì chạy xampp center thiết lập apache và mysql running.

http://localhost/cookbook/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\

cookbook\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

http://www.seodrupal.vn | Learn Drupal Online

Page 2: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

-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: Vào start -> run->cmd

C:\

Cd\

Cd C:\xampp\htdocs\

C:\xampp\htdocs\>cookbook/framework/yiic webapp skybook

Nếu không được thì gõ tiếp cd cookbook

Gõ tiếp cd framework -> gõ yiic webapp skybook.

[skybook]-> Tên ứng dụng Create a Web application under '/Webroot/skybook'? [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:skybook/

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ệ

Vào cookbook/framework/ chuyển folder mới tạo là skybook ra ngoài folder website C:/xampp/htdocs. Đường dẫn mới của app là C:/xampp/htdocs/skybook.

copy folder framework của cookbook sang skybook.

Vào file index.php thay đổi đường dẫn thành : $yii=dirname(__FILE__).'/framework/yii.php';

Bạn có thể truy cập vào ứng dụng từ trình duyệt

http://localhost/skybook/index.php

http://www.seodrupal.vn | Learn Drupal Online

Page 3: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Ok, hoàn tất cấu hình để tiến hành coder.

CHƯƠNG 1 - Giới thiệu về Yii framework

1 – Sử dụng getter and setter ( Hàm nhận và hàm thiết lập).

PHP cũng giống như các công nghệ khác như Java, C# , đều có cấu trúc lập trình hướng đối tượng và xây dựng công nghệ theo các class(lớp), yii framework được xây dựng trên nền php cũng không ngoại lệ, tuy nhiên điều khác biệt là nó kế thừa từ Ccomponent (class ảo cho bất kỳ class nào trong Yii).

Cách thực hiện:

Chúng ta theo dõi định nghĩa lớp trong php với hàm thiết lập (setter) và hàm nhận lại (getter)

class MyClass{private $property;

// ham nhan lay giá trịpublic function getProperty(){return $this->property;}// ham khởi tạo giá trịpublic function setProperty($value){$this->property = $value;}}// tạo mới đối tượng$object = new MyClass();// thiết lập đối tượng$object->setProperty('value');// trả về giá trịecho $object->getProperty();

Trong Yii chúng ta thực hiện nhờ kế thừa từ Ccomponent như sau :

// extending CComponent is necessaryclass MyClass extends CComponent{

private $property;public function getProperty(){return $this->property;}

http://www.seodrupal.vn | Learn Drupal Online

Page 4: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public function setProperty($value){$this->property = $value;}}$object = new MyClass();$object->property = 'value'; // cũng như php : $object->setProperty('value');echo $object->property; // cũng như $object->getProperty();Ngoài ra Yii còn hỗ trợ các hàm sau thực hiện việc thiết lập và nhận giá trị : __get, __set, __isset, và __unset

Cách dùng như sau : vdpublic function __get($name){$getter='get'.$name;if(method_exists($this,$getter))return $this->$getter();

}

2 – Sử dụng Yii Event ( Các sự kiện trong Yii)

Hầu hết các class đều được kế thừa từ Yii Component (Ccomponent) vì thế nên chúng ta có thể sử lý tốt các sự kiện từ ứng dụng. Một sự kiện tương ứng là một lời nhắn, một thông điệp tới ứng dụng để yêu cầu thực hiện công việc nào đó, chúng ta có thể đăng ký nhiều sự kiện xử lí để thực hiện tùy theo loại sự kiện, một hàm xử lý có thể nhận được các tham số từ các sự kiện với các tham số được định nghĩa, Sử dụng các sự kiện cho phép đạt được sự linh hoạt trong ứng dụng.

Cách thực hiện thế nào ?Để định nghĩa một sự kiện trong lớp con của Ccomponent, bạn sẽ thêm phương thức (method) với tên bắt đầu bằng từ “on”, ví dụ nếu bạn thêm onRegister method , bạn sẽ nhận được tương ứng một sự kiện bạn đã khai báo.

Các loại sự kiện được sử dụng giống như :- Định nghĩa một sự kiện được thêm tuơng ứng một phương thức,- Kích hoạt một hay nhiều sự kiện xử lý.- Thành phần nâng cao (raise) của một sự kiện được sử dụng bởi

Ccomponent ::raiseEvent method - Tất cả các thể hiện xử lý được gọi tự động.Hãy nhìn vào cách chúng ta có thể kích hoạt một sự kiện xử lý từ một sự kiện.Chúng ta sử dụng Ccomponent::attachEventHandler method.Nó chấp nhận các tham số sau đây:$name : Tên sự kiện.

http://www.seodrupal.vn | Learn Drupal Online

Page 5: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$handler: Xử lý sự kiện,yêu cầu của bạn trước mỗi sự kiện thường là một hàm tiêu chuẩn gọi lại (standard function callback) php để sử dụng.Bạn có thể thực hiện hàm gọi lại như sau : Sử dụng hàm cục bộ (global function) và chỉ nhận tên giống như các chuỗi ví dụ “ my_function”.Sử dụng các phương thức tĩnh từ lớp (static class method).Bạn sẽ chỉ trả về giá trị array(‘Tên lớp (Name class)’,’Tên phương thức tĩnh(static method Name)’).Sử dụng object method : array($object,’object method’)Tạo và nhận hàm định danh sử dụng create_function như sau:Trước tiên định nghĩa componentpublic function init() {                parent::init();                  $component = Yii::app()->{$this->component};                      }$component->attachEventHandler(‘onClick’,create_function(‘$event’,’echo “click!”));

Với phiên bản PHP 5.3 trở lên bạn chỉ cần viết:$component->attachEventHandler(‘onclick’,function($event){echo ‘click’;});

Để code ngắn hơn bạn chỉ cần viết như sau : $component->onClick=$handler; hoặc$component->onClick->add($handler);

Để quản lý việc xử lý sự kiện bạn sử dụng hàm get handler list (Clist) trong Ccomponent::getEventHandlers và làm việc với nó.Ví dụ : $component->getEventHandlers(‘onClick’)->add($handler);

Để thêm một xử lý vào đầu danh sách các xử lý ta viết:$component->getEventHandlers(‘onClick’)->insertAt(0,$handler);

Để xóa một xử lý bạn sử dụng Ccomponent::detachEventHandler:$component->detachEventHandler(‘onClick’,$handler);

Yii application có 2 sự kiện được sử lý trong các trường hợp sau ;Capplication::onBeginRequest và Capplication::onEndRequest hãy sử dụng chúng .Đặt cấu hình thiết lập như sau vào file index.php trước khi chạy ứng dụng:

http://www.seodrupal.vn | Learn Drupal Online

Page 6: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

require_once($yii);$app = Yii::createWebApplication($config);// Kích hoạt sử lý trước khi bắt đầu ứng dụngYii::app()->onBeginRequest = function($event){// starting output buffering with gzip handlerreturn ob_start("ob_gzhandler");};// Kích hoạt sử lý sau khi kết thúc ứng dụngYii::app()->onEndRequest = function($event){// releasing output bufferreturn ob_end_flush();};$app->run();

Comment là một tiêu chuẩn của AR model generate với Gii, Post là một phương thức ngoại lệ trong Gii-generated model. Chúng ta sẽ custom sự kiện NewCommentEvent để thực hiện cả post và comment model và sử lý class Notifier làm việc:

Bắt đầu vào protected/components/ tạo NewCommentEvent.php

class NewCommentEvent extends CModelEvent {

public $comment;

public $post;

}

Rất đơn giản chỉ bao gồm 2 thuộc tính.

Bây giờ bạn di chuyển tới protected/models/Post.php. Tất cả tiêu chuẩn AR method được xây dựng như sau:

class Post extends CActiveRecord {

function addComment(Comment $comment){

$comment->post_id = $this->id;

http://www.seodrupal.vn | Learn Drupal Online

Page 7: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

// tạo mới sự kiện từ class trước

$event = new NewCommentEvent($this);

$event->post = $this;

$event->comment = $comment;

// kích hoạt sự kiện mới

$this->onNewComment($event);

return $event->isValid;

}

// định nghĩa sự kiện onNewComment

public function onNewComment($event) {

$this->raiseEvent('onNewComment', $event);

}

}

Tiếp theo tạo trong protected/components/ file Notifier.php

class Notifier {

function comment($event){

$text = "Có một comment mới từ {$event->comment->author} trong post {$event->post->title}";

mail('[email protected]', 'New comment', $text);

}

}

Tiếp theo vào trong protected/controllers/ tạo file PostController.php

Class PostController extends Ccontroller

http://www.seodrupal.vn | Learn Drupal Online

Page 8: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{ // tạo action thêm comment

function actionAddComment()

{

$post = Post::model()->findByPk(10);

$notifier = new Notifier();

// kích hoạt sử lý sự kiện

$post->onNewComment = array($notifier, 'comment');

// dữ liệu thật được dưới dạng request $_POST

$comment = new Comment();

$comment->author = 'Sam Dark';

$comment->text = 'Yii events are amazing!';

// thêm comment

$post->addComment($comment);

}

}

Như vậy là bạn đã biết cách kích hoạt và sử lý một sự kiện , tuy nhiên nhiều trường hợp không nhất thiết phải kích hoạt sử lý sự kiện mà chúng ta cũng có thể kích hoạt sử lý sự kiện từ các component đã tồn tại và chúng ta chỉ cần overriding các class cơ bản đó . Ví dụ chúng ta có form model UserForm sử dụng để thu thập thông tin của người dùng và chúng ta cần hiển thị đầy đủ họ tên của user.

Thật may, Cmodel class cơ bản trong Yii model có thể mở rộng form models.

Cmodel::afterValidate được gọi sau khi form được submit thành công.

Ta vào protected/models/ tạo file UserForm.php

class UserForm extends CFormModel

http://www.seodrupal.vn | Learn Drupal Online

Page 9: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

public $firstName; //tên

public $lastName; //họ

public $fullName; //tên đầy đủ

public function rules()

{

return array(

//tập hợp quy tắc : firstname,lastname được yêu cầu (k rỗng)

array('firstName, lastName', 'required'),

);

}

// $event ở đây được thiết lập từ CEvent

// tạo ra và thiết lập một sự kiện( event) khi method được gọi .

// CModel::afterValidate().

function afterValidate()

{

//Nếu phương thức được gọi thì sự kiện sẽ tự động nạp dữ liệu sau:

$this->fullName = $this->firstName.' '.$this->lastName;

// điều quan trọng là nó phải được gọi lại từ lớp cha (parent class)

// đó là điều giúp các sử lý sự kiện khác được gọi lại.

return parent::afterValidate();

}

}

http://www.seodrupal.vn | Learn Drupal Online

Page 10: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Chúng ta cần gọi lại từ lớp cha (parent class) của afterValidate() vì hàm định nghĩa onAfterValidate() thực chất là raiseEvent:

Protected function afterValidate()

{

$this->onAfterValidate(new CEvent($this));

}

2. Sử dụng import và autoloadingKhi lập trình với php hầu hết các class và hàm tạo đều được load bởi hai phương thức là : “include” và “require”. Tuy nhiên bạn cũng có thể sử dụng loader nhờ SPL class, yii sử dụng công nghệ này vào Yii Base và việc xây dựng các lớp tiêu chuẩn trong yii CdbCriteria. Mặc định autoloader (YiiBase::autoload) sẽ được sử dụng.Hầu hết tất cả các lớp được load khi cần including hoặc importing . Yii hoàn tất bởi YiiBase::$_coreClasses map, vì thế mà việc load trong Yii rất nhanh.Zii class cũng như Cmenu, extension class hoặc class của bạn định nghĩa cũng được tự động load.

3. Cấu hình Component(Thành phần)Yii là một framework custom, hầu như mọi thứ đều có thể custom một cách dễ dàng đó là ưu điểm của yii, trước tiên chúng ta tìm hiểu file config của Yii trong protected/con fig /main.phpĐể có thể sử dụng database kết nối mysql ta chỉ cần bỏ 2 dòng /* ---- */ để array dưới đây được kích hoạt.return array(…'components'=>array('db'=>array('class'=>'system.db.CDbConnection','connectionString'=>'mysql:host=localhost;dbname=database_name','username'=>'root','password'=>'','charset'=>'utf8',),…),…);

http://www.seodrupal.vn | Learn Drupal Online

Page 11: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Khi đã có thể kết nối tới database rồi bạn chỉ cần khai báo Yii::app()->db; là ta đã có thể làm việc trực tiếp với CSDL.

Một số component trong Yii bạn nên biết :

http://www.seodrupal.vn | Learn Drupal Online

Page 12: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

4: Làm việc với Request

Với yii bạn có thể trả về dữ liệu dưới dạng request mà php đưa ra như $_SERVER,$_GET,$_POST, nhưng tốt hơn bạn nên làm theo việc sử dụng của Yii là :ChttpRequest class , lớp này giải quyết những ngoại lệ từ server, quản lý cookies,cung cấp thêm vấn đề bảo mật,và đặc biệt là hướng đối tượng .

Bạn có thể truy nhập request component trong yii bằng việc sử dụng : Yii::app()->getRequest(). Vì thế nên xem một số hàm hữu ích , các method trả về khác biệt từ URL :

Để chắc chắn các request được truyền đúng ta có thêm các hàm kiểm tra : IsPostRequest (Kiểm tra hàm post), getIsAjaxRequest (kiểm tra ajax loader), getRequestType (kiểm tra request thuộc loại get hay post hay ajax).

Ví dụ chúng ta muốn kiểm tra xem aJax đã được load hay chưa ta xem ví dụ sau :

class TestController extends CController

{

http://www.seodrupal.vn | Learn Drupal Online

Page 13: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public function actionIndex()

{

if(Yii::app()->request->isAjaxRequest)s

$this->renderPartial('test');

else

$this->render('test');

}

}

Ngoài ra bạn cũng có thể dùng các hàm thiết lập thông dụng của PHP để kiểm tra như isset, ispost ….

class TestController extends CController

{

public function actionIndex()

{

$request = Yii::app()->request;

$param = $request->getParam('id', 1);

// equals to

$param = isset($_REQUEST['id']) ? $_REQUEST['id'] : 1;

$param = $request->getQuery('id');

// equals to

$param = isset($_GET['id']) ? $_GET['id'] : null;

$param = $request->getPost('id', 1);

// equals to

$param = isset($_POST['id']) ? $_POST['id'] : 1;

}

}

http://www.seodrupal.vn | Learn Drupal Online

Page 14: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Điều cuối cùng chúng tôi muốn bạn biết thêm trong chương 1 này chính là hàm getCookies, nó trả về từ CcookieCollection class cho phép chúng ta làm việc với cookie, Vì CcookieCollection được kế thừa từ Cmap nên chúng ta có thể sử dụng method sau:

class TestController extends CController

{

public function actionIndex()

{

$request = Yii::app()->request;

// nhận giá trị của cookie

$cookie = $request->cookies['test'];

if($cookie)

// in giá trị cookie

echo $cookie->value;

else {

// tạo mới cookie

$cookie=new CHttpCookie('test','I am a cookie!');

$request->cookies['test'] = $cookie;

}

}

Nếu bạn làm việc với nhiều giá trị của cookie , bạn muốn code của mình ngắn gọn hãy sử dụng class sau:

class Cookie

{

public static function get($name)

{

$cookie=Yii::app()->request->cookies[$name];

if(!$cookie)

http://www.seodrupal.vn | Learn Drupal Online

Page 15: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

return null;

return $cookie->value;

}

public static function set($name, $value, $expiration=0)

{

$cookie=new CHttpCookie($name,$value);

$cookie->expire = $expiration;

Yii::app()->request->cookies[$name]=$cookie;

}

}

Bạn thay đổi code trong TestController như sau:

class TestController extends CController

{

public function actionIndex()

{

$cookie = Cookie::get('test');

if($cookie)

echo $cookie;

else

Cookie::set('test','I am a cookie!!');

}

}

Lưu ý, chương một với các bạn mới học sẽ không thể làm thử được vì không có database để thử, xin vui lòng down source code bản English để test app của họ.

http://www.seodrupal.vn | Learn Drupal Online

Page 16: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

CHƯƠNG 2 : ROUTER (Định tuyến), Controller (Điều khiển), and views (khung nhìn)

Trong chương này bạn sẽ được học:

Cấu hình quy tắc url,

Generating Url by path

Sử dụng biểu thức quy tắc (regular expression) trong URL rules

Tạo url rules cho các trang tĩnh.

Cung cấp url rules ở mỗi thời điểm.

Sử dụng controller cơ bản

Sử dụng action cơ bản

Hiển thị trang động với CViewAction

Sử dụng flash messages ( Cờ thông điệp)

Sử dụng controller context trong view

Sử dụng clips

Sử dụng decorator

Định nghĩa nhiều layout (giao diện)

Paginating and sorting data (Phân trang và sắp xếp dữ liệu)

1. Cấu hình quy tắc URL

Trước tiên bạn vào protected/config/main.php

Tìm dòng sau:

// application components

'components'=>array(

// uncomment the following to enable URLs in path-formathttp://www.seodrupal.vn | Learn Drupal Online

Page 17: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

/*

'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>',

),

),

Bỏ hai dấu /* và */ sau đó xóa mọi thứ trong rules để ta bắt đầu thực hành. 'urlManager'=>array(

'urlFormat'=>'path',

'rules'=>array(

),

),

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

Vào protected/controllers tạo websiteController.php với dòng code sau:

class WebsiteController extends CController

{

public function actionIndex()

{

echo "index";

}

http://www.seodrupal.vn | Learn Drupal Online

Page 18: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public function actionPage($alias)

{

echo "Page is $alias.";

} }

Thay đổi file .htaccess trong protected như sau :

Options +FollowSymLinks

IndexIgnore */*

RewriteEngine on

# if a directory or a file exists, use it directly

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php

RewriteRule . index.php

Thêm đoạn sau vào main.php như sau:

'urlManager'=>array(

'urlFormat'=>'path',

'rules'=>array(

'home' => 'website/index',

'<alias:about>' => 'website/page',

'page/<alias>' => 'website/page',

),

),

Lần lượt gõ vào trình duyệt các đường dẫn sau:

http://localhost/skybook/index.php/page/test

http://localhost/skybook/index.php/home

http://www.seodrupal.vn | Learn Drupal Online

Page 19: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

http://localhost/skybook/index.php/about

http://localhost/skybook/index.php/page/about

Bạn sẽ thấy biến alias trong action page sẽ thay đổi tùy theo đường dẫn thứ 2 sau page bạn điền vào, đây chính là url định danh (url alias).

Thực tế điều gì đã xảy ra:

Với quy tắc : ‘home’=>’website/index’ , trong Yii mỗi controller và action đều có một quy tắc chung mặc định là moduleId (tên module)/controllerID(tên controller)/actionID(tên action). Ví dụ trong trường hợp home đó là module : default, controller website, và action là index.

‘page/<alias>’=>’website/page’,

Ở đây , chúng ta định nghĩa một alias parameter ( tham số định danh) đặc biệt trong Url sau /page/. Nó có thể nhận về các tham số ảo từ tham số $alias trong action Page của website controller.

Ở đây bạn định nghĩa trả về tham số cho nó bằng việc thiết lập quy tắc:

‘<alias:about>’=>’website/page’, đồng nghĩa với việc tham số $alias sẽ chỉ nhận được tham số ảo là about.

2. Generating Url By Path

Khi chúng ta cần generate Url của index và page action trong website controller.Quyết định nơi chúng ta cần nó,có những cách làm khác nhau nhưng cơ bản hãy nhìn một số phương thức generate url sau:

http://www.seodrupal.vn | Learn Drupal Online

Page 20: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

CHtml::link(), và một số phương thức CHtml như form,refresh và ajaxLink tất cả chấp nhận url và thuộc tính sử dụng trong views. Định dạng chung cho việc trả về dữ liệu như sau:

Url string: Trả về đường dẫn url dạng kí tự.

Array(quy tắc cục bộ,tham số=>giá trị, tham số => giá trị…). Một số trường hợp url sẽ được generated.

Định dạng của quy tắc vẫn theo thứ tự : modulesID/controllerID/actionId.

Tham số là biến $_GET sẽ nhận một action với định tuyến đặc biệt, cho ví dụ nếu chúng ta muốn tạo một url từ websitecontroller ::actionIndex và nhận tham số $_GET[‘name’] ta chỉ cần làm như sau:

echo CHtml::link('Click me!', array('website/index',

'name' => 'Đệt cụ bọn tàu khựa đã làm ra Yii (Quiang Xue)'));

URl rất hữu ích khi sử dụng controller . Trong controller bạn có thể sử dụng createUrl để tạo mới url và createAbsoluteUrl để hiển thị thong tin về url:

class WebsiteController extends CController

{

public function actionTest()

{

echo $this->createUrl('website/page', 'alias' => 'about');

echo $this->createAbsoluteUrl('website/page',

'alias' => 'test');

}

// the rest of the methods

}

Khi bạn không muốn hiện khởi tạo của controller , khi bạn thực thi ứng dụng bạn có thể sử dụng method sau:

echo Yii::app()->createUrl('website/page', 'alias' => 'about');

http://www.seodrupal.vn | Learn Drupal Online

Page 21: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

echo Yii::app()->createAbsoluteUrl('website/page', 'alias' => 'test');

3.Sử dụng biểu thức quy tắc trong Url rules

Ngựa quen đường cũ và gà lại thèm rượu nên ta xóa dữ liệu trong rules array().

Tiếp theo vào protected/controllers tạo file PostController.php mới với dòng sau:

class PostController extends CController

{

public function actionView($alias)

{

echo "Showing post with alias $alias.";

}

public function actionIndex($order = 'DESC')

{

echo "Showing posts ordered $order.";

}

public function actionHello($name)

{

echo "Hello, $name!";

}

}

Cấu hình lại .htaccess trong protected như sau:

Options +FollowSymLinks

IndexIgnore */*

RewriteEngine on

http://www.seodrupal.vn | Learn Drupal Online

Page 22: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

# if a directory or a file exists, use it directly

RewriteCond %{REQUEST_FILENAME} !-f

RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php

RewriteRule . index.php

Tiếp theo thay đổi lại trong main.php phần rules như sau:

'urlManager'=>array(

'urlFormat'=>'path',

'rules'=>array(

'post/<alias:[-a-z]+>' => 'post/view',

'(posts|archive)' => 'post/index',

'(posts|archive)/<order:(DESC|ASC)>' => 'post/index',

'sayhello/<name>' => 'post/hello',

),

),

Sau đó vào trình duyệt tự sướng:

http://localhost/skybook/index.php/post/test-post thành công

http://localhost/skybook/index.php/post/test-9 hi sinh (vì hàm ngoại lệ yêu cầu dạng kí tự k phải dạng số)

http://localhost/skybook/index.php/achive hi sinh vì index thuộc dạng số không thuộc kí tự

http://localhost/skybook/index.php/posts/ASC thành công

http://www.seodrupal.vn | Learn Drupal Online

Page 23: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

4.Tạo Url rules cho trang tĩnh

Một website chứa các thuộc tính tĩnh thường là :/about,/contact,/tos, lệnh sử lý đến trang đó chỉ đơn giản là controller action. Ta sẽ tìm một cách để tạo ra Url rules cho các thuộc tính của trang.

Lại vào main.php phần rules để hót phân chó (xóa toàn bộ mọi thứ trong array của rules).

Thay đổi lại như sau:

'<alias:about>' => 'website/page',

'<alias:contact>' => 'website/page',

'<alias:tos>' => 'website/page',

'<alias:(about|contact|tos)>' => 'website/page',

'tos' => array('website/page', 'defaultParams' => array('alias' =>

'terms_of_service')),

6. Sử dụng controller cơ bản

Đầu tiên ta vào protected/components tạo SecureController.php

<?php

class SecureController extends Controller

{

public function filters()

http://www.seodrupal.vn | Learn Drupal Online

Page 24: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

return array(

'accessControl',

);

}

public function accessRules()

{

return array(

array('allow',

'users'=>array('@'),

),

array('deny',

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

),

);

}

}

Vào protected/config/ main.php tìm đoạn

/*

'gii'=>array(

'class'=>'system.gii.GiiModule',

'password'=>'Enter Your Password Here',

// If removed, Gii defaults to localhost only. Edit carefully to taste.

'ipFilters'=>array('127.0.0.1','::1'),

http://www.seodrupal.vn | Learn Drupal Online

Page 25: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

),

*/

Bỏ 2 dòng check và điền password cho gii (generated database)

'gii'=>array(

'class'=>'system.gii.GiiModule',

'password'=>'1111',

'ipFilters'=>array('127.0.0.1','::1'),

),

Tiếp theo vào http://localhost/skybook/index.php/gii/default/login

Điền mật khẩu là 1111

Tiếp theo chọn Controller Generator gõ SecureController

http://www.seodrupal.vn | Learn Drupal Online

Page 26: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Nhấn generate để tạo controller và action index

Địt mẹ máy như lồn, gõ nhanh quá word báo : please slow character @@

Generate xong đồng nghĩa với việc bạn đã tạo xong controller SecureController , bạn có thể vào protected/controllers để tìm thấy file này và trong views.

Thật nhanh chóng đúng không ? ta không cần phải mất công tạo tuy nhiên @@ không khuyến khích vì các dự lớn đòi hỏi khả năng custom cao vì thế nên chỉ generate models cho chóng xong, còn controller thì tốt nhất tự tạo file .

Cấu trúc của YII vẫn tuân thủ MVC, (model/views/controller) .

7. Sử dụng cơ bản Action

Vào protected/config/main.php tìm đoạn sau:

'db'=>array(

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

),

// uncomment the following to use a MySQL database

'db'=>array(

'connectionString' => 'mysql:host=localhost;dbname=testdrive',

'emulatePrepare' => true,

'username' => 'root',

'password' => '',

'charset' => 'utf8',

),

Thay thế bằng skybook hoặc bạn để nguyên, vào localhost/phpmyadmin tạo table testdrive nếu bạn để nguyên, hoặc nếu thay thế = skybook thì tạo bảng skybook.

Vào phpmyadmin với table mới tạo với query:

CREATE TABLE `post` (

http://www.seodrupal.vn | Learn Drupal Online

Page 27: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

`id` int(10) unsigned NOT NULL auto_increment,

`created_on` int(11) unsigned NOT NULL,

`title` varchar(255) NOT NULL,

`content` text NOT NULL,

PRIMARY KEY (`id`)

);

CREATE TABLE `user` (

`id` int(10) unsigned NOT NULL auto_increment,

`username` varchar(200) NOT NULL,

`password` char(40) NOT NULL,

PRIMARY KEY (`id`)

);

http://www.seodrupal.vn | Learn Drupal Online

Page 28: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Nhấn go để query được thực hiện.

Tiếp theo vào GII generated 2 bảng mới tạo bằng cách chọn model generated

Gõ lần lượt Post và User trong table Name rồi generated

Nếu nó báo override thì vẫn generated

Để kiểm tra vào protected/models sẽ tìm thấy 2 file mới tạo.

Tiếp theo vào PostController viết lại như sau:

class PostController extends CController

{

function actionIndex()

{

$posts = Post::model()->findAll();

http://www.seodrupal.vn | Learn Drupal Online

Page 29: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

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

'posts' => $posts,

));

}

function actionDelete($id)

{

$post = Post::model()->findByPk($id);

if(!$post)

throw new CHttpException(404);

if($post->delete())

$this->redirect('post/index');

throw new CHttpException(500);

}

}

Tiếp theo vào protected/components tạo file DeleteAction.php

class DeleteAction extends CAction

{

function run()

{

if(empty($_GET['id']))

throw new CHttpException(404);

$post = Post::model()->findByPk($_GET['id']);

if(!$post)

throw new CHttpException(404);

if($post->delete())

http://www.seodrupal.vn | Learn Drupal Online

Page 30: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$this->redirect('post/index');

throw new CHttpException(500);

}

}

Hãy sử dụng component mới này trong PostController ở actionDelete

class PostController extends CController

{

function actions()

{

return array(

'delete' => 'DeleteAction',

);

}

}

OK.chúng ta sử dụng delete action trong component cho post controller nhưng vẫn còn user controller, ta custom lại delete action:

class DeleteAction extends CAction

{

public $pk = 'id';

public $redirectTo = 'index';

public $modelClass;

http://www.seodrupal.vn | Learn Drupal Online

Page 31: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

function run()

{

if(empty($_GET[$this->pk]))

throw new CHttpException(404);

$model = CActiveRecord::model($this->modelClass)

->findByPk($_GET[$this->pk]);

if(!$model)

throw new CHttpException(404);

if($model->delete())

$this->redirect($this->redirectTo);

throw new CHttpException(500);

}

}

Bây giờ chúng ta có thể sử dụng action cho cả 2 controller .Với post controller ta làm như sau:

class PostController extends CController

{

function actions()

{

return array(

'delete' => array(

'class' => 'DeleteAction',

'modelClass' => 'Post',

);

);

http://www.seodrupal.vn | Learn Drupal Online

Page 32: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

}

Với user controller ta cũng khai báo action mới trong component

class UserController extends CController

{

function actions()

{

return array(

'delete' => array(

'class' => 'DeleteAction',

'modelClass' => 'User',

);

);

}

}

Với cách này ta có thể tiết kiệm thời gian xây dựng hàm với những hàm có cấu trúc giống nhau.

8. Sử dụng Flash Messages

Khi bạn chỉnh sửa model với form,hay xóa item trong models hoặc làm với những thao tác user, bạn luôn luôn phải đưa ra lời thong báo tới user công việc đó đã thực hiện xong chưa hay đã hoàn thành,…Flash messages sẽ giúp hiển thị những lời thong báo ví dụ :”xóa thành công, cập nhật thành công,…”

Trở lại protected/controllers/websitecontroller viết lại như sau:

http://www.seodrupal.vn | Learn Drupal Online

Page 33: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

class WebsiteController extends CController

{

function actionOk()

{

Yii::app()->user->setFlash('success', 'Everything went

fine!');

$this->redirect('index');

}

function actionBad()

{

Yii::app()->user->setFlash('error', 'Everything went wrong!');

$this->redirect('index');

}

function actionIndex()

{

$this->render('index');

}

}

Vào protected/views/website tạo index.php

<?php if(Yii::app()->user->hasFlash('success')):?>

<div class="flash-notice">

<?php echo Yii::app()->user->getFlash('success')?>

</div>

<?php endif?>

<?php if(Yii::app()->user->hasFlash('error')):?>

http://www.seodrupal.vn | Learn Drupal Online

Page 34: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<div class="flash-error">

<?php echo Yii::app()->user->getFlash('error')?>

</div>

<?php endif?>

Vào trình duyệt http://localhost/skybook/index.php/website/ok

http://localhost/skybook/index.php/website/bad

9. Sử dụng controller context trong views

Tạo controller sau:

class WebsiteController extends CController

{

function actionIndex()

{

$this->pageTitle = 'Controller context test';

$this->render('index');

http://www.seodrupal.vn | Learn Drupal Online

Page 35: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

function hello()

{

if(!empty($_GET['name']))

echo 'Hello, '.$_GET['name'].'!';

}

}

Tạo views :

<h1><?php echo $this->pageTitle?></h1>

<p>Hello call. <?php $this->hello()?></p>

<?php $this->widget('zii.widgets.CMenu',array(

'items'=>array(

array('label'=>'Home', 'url'=>array('index')),

array('label'=>'Yiiframework home',

'url'=>'http://yiiframework.ru/',

),

))?

10. Sử dụng lại views với partial

class WebsiteController extends CController

{

function actionIndex()

{

$this->render('index');

}http://www.seodrupal.vn | Learn Drupal Online

Page 36: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

Tạo protected/views/common/youtube.php

<object width="480" height="385"><param name="movie"

value="http://www.youtube.com/v/S6u7ylr0zIg?fs=1 "></

param><param name="allowFullScreen" value="true"></

param><param name="allowscriptaccess" value="always"></

param><embed src="http://www.youtube.com/v/S6u7ylr0zIg?fs=1"

type="application/x-shockwave-flash" allowscriptaccess="always"

allowfullscreen="true" width="480" height="385"></embed></object>

Chỉnh sửa lại :

<object width="<?php echo!empty($width) ? $width : 480?>"

height="<?php echo!empty($height) ? $height: 385?>"><param

name="movie" value="http://www.youtube.com/v/<?php echo

$id?>?fs=1 "></param><param name="allowFullScreen" value="true"></

param><param name="allowscriptaccess" value="always"></

param><embed src="http://www.youtube.com/v/<?php echo $id?>?fs=1"

type="application/x-shockwave-flash" allowscriptaccess="always"

allowfullscreen="true" width="<?php echo !empty($width) ? $width

: 480?>" height="<?php echo !empty($height) ? $height: 385?>"></

embed></object>

http://www.seodrupal.vn | Learn Drupal Online

Page 37: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Tạo protected/website/index.php

<?php $this->renderPartial('////common/youtube', array(

'id' => '8Rp-CaIKvQs', // you can get this id by simply looking

at video URL

'width' => 320,

'height' => 256,

))?>

Giờ ta sẽ thử gửi email ,them mới action trong website controller

class WebsiteController extends CController

{

function actionSendmails()

{

$users = User::model->findAll();

foreach($users as $user)

{

$this->sendEmail('welcome', $user->email, 'Welcome to the website!', array('user' => $user));

}

echo 'Emails were sent.';

}

function sendEmail($template, $to, $subject, $data)

{

mail($to, $subject, $this->renderPartial

('//email/'.$template, $data, true));

}

http://www.seodrupal.vn | Learn Drupal Online

Page 38: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

Tiếp theo tạo protected/views/email/welcome.php:

Hello <?php echo $user->name?>,

Welcome to the website!

You can go check our new videos section. There are funny raccoons.

Yours,

Website team.

11 . Sử dụng clip

Khi chúng ta cần định nghĩa 2 vị trí trong layout : trước content và footer, mở protected/views/layouts/main.php them đoạn sau trước output (<?php echo $content;?>)

<?php if(!empty($this->clips['beforeContent'])) echo

$this->clips['beforeContent']?>

Và them đoạn sau trước footer

<?php if(!empty($this->clips['footer']))

Echo $this->clips['footer']; ?>

Bây giờ chúng ta cần điền vào vị trí của chúng, mở controller action cho beforeContent region. Mở protected/controllers/SiteController.php và them đoạn sau vào actionIndex:

$this->beginClip('beforeContent');

echo 'Your IP is '.Yii::app()->request->userHostAddress;

$this->endClip();

Tiếp theo mở protected/views/site/index.php và them đoạn sau:

<?php $this->beginClip('footer')?>

Ứng dụng được xây dựng bởi Tàu khựa.

<?php $this->endClip()?>

http://www.seodrupal.vn | Learn Drupal Online

Page 39: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Hoàn tất bạn có thể mở index bạn sẽ thấy địa chỉ IP và “ứng dụng…” ở gần footer.

12 . Định nghĩa nhiều Layout.

Hầu hết ứng dụng sử dụng một layout duy nhất cho tất cả khung nhìn,tuy nhiên nhiều dự án đòi hỏi cấu hình và thẩm mỹ khác nhau dẫn tới có nhiều layout khác nhau vì thế nên yii cho phép tạo dựng nhiều layout một cách chuyên biệt và hiệu quả.

Ta tạo 2 layout trong protected/views/layouts: blog và articles. Blog chứa đựng nội dung sau:

<?php $this->beginContent('//layouts/main')?>

<div>

<?php echo $content?>

</div>

<div class="sidebar tags">

<ul>

<li><a href="#php">PHP</a></li>

<li><a href="#yii">Yii</a></li>

</ul>

</div>

<div class="sidebar links">

<ul>

<li><a href="http://yiiframework.com/">Yiiframework</a></li>

<li><a href="http://php.net/">PHP</a></li>

</ul>

</div>

<?php $this->endContent()?>

http://www.seodrupal.vn | Learn Drupal Online

Page 40: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Article chứa nội dung sau:

<?php $this->beginContent('//layouts/main')?>

<div>

<?php echo $content?>

</div>

<div class="sidebar toc">

<ul>

<li><a href="#intro">1. Introduction</a></li>

<li><a href="#quick-start">2. Quick start</a></li>

</ul>

</div>

<?php $this->endContent()?>

Tạo 3 controller là BlogController,ArticleController và PorfolioController với indexAction

class BlogController extends Controller

{

function actionIndex()

{

$this->layout = 'blog';

$this->render('//site/index');

}

}

class ArticleController extends Controller

{

http://www.seodrupal.vn | Learn Drupal Online

Page 41: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

function actionIndex()

{

$this->layout = 'articles';

$this->render('//site/index');

}

}

class PortfolioController extends Controller

{

function actionIndex()

{

$this->render('//site/index');

}

}

Giờ hãy thử vào http://localhost/skybook/index.php/blog, http://localhost/skybook/index.php/article and

http://localhost/skybook/index.php/portfolio.

Chúng ta vừa định nghĩa 2 layout cho blog và articles. Nếu chúng ta không muốn copy-pase một phần của layout chính,chúng ta thử them layout được định nghĩa bằng cách sử dụng $this->beginContent và this->endContent; thể hiện ở hình dưới đây:

http://www.seodrupal.vn | Learn Drupal Online

Page 42: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

13. Phân trang và sắp xếp dữ liệu

Trước khi kết thúc chương 2 ta sẽ đi vào tìm hiểu ActiveRecord với cơ chế phân trang , sắp xếp dữ liệu theo tiêu chuẩn.

Vào protected/controllers/PostController.php

class PostController extends Controller

{

function actionIndex()

{

$criteria = new CDbCriteria();

$count=Post::model()->count($criteria);

$pages=new CPagination($count);

// elements per page

$pages->pageSize=5;

$pages->applyLimit($criteria);

// sorting

$sort = new CSort('Post');

http://www.seodrupal.vn | Learn Drupal Online

Page 43: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$sort->attributes = array(

'id',

'title',

);

$sort->applyOrder($criteria);

$models = Post::model()->findAll($criteria);

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

'models' => $models,

'pages' => $pages,

'sort' => $sort,

));

}

}

Tiếp theo xây dựng views: protected/views/post/index.php

<p><?php echo $sort->link('id')?></p>

<p><?php echo $sort->link('title')?></p>

<ol>

<?php foreach($models as $model):?>

<li>

<h2><?php echo $model->id?> - <?php echo $model->title?></h2>

</li>

<?php endforeach?>

</ol>

<?php $this->widget('CLinkPager', array(

'pages' => $pages,

http://www.seodrupal.vn | Learn Drupal Online

Page 44: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

))?>

Để thực hiện kiểm tra bạn vào phpmyadmin và thêm vào bảng post khoảng 20 item, sau đó vào trình duyệt xem kết quả: http://localhost/skybook/post

CHƯƠNG 3 AJAX Và jQuery

Trong chương này bạn sẽ khám phá:

Tải một block với AJAX

Quản lý asserts

Including resources với page

Làm việc với JSON

Nhận thiết lập từ PHP và Javascript

Xử lý biến số của input

1. Tải một Block với AJAX

http://www.seodrupal.vn | Learn Drupal Online

Page 45: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Tạo một controller mới trong protected/controllers tên QuoteController

: <?php

class QuoteController extends Controller

{

private $quotes = array(

array('Walking on water and developing software from a

specification are easy if both are frozen.', 'Edward V Berard'),

array('It always takes longer than you expect, even when you

take into account Hofstadter&rsquo;s Law.', 'Hofstadter&rsquo;s

Law'),

array('Always code as if the guy who ends up maintaining

your code will be a violent psychopath who knows where you live.',

'Rick Osborne'),

array('I have always wished for my computer to be as easy to

use as my telephone; my wish has come true because I can no longer

figure out how to use my telephone.', 'Bjarne Stroustrup'),

array('Java is to JavaScript what Car is to Carpet.', 'Chris

Heilmann'),

);

private function getRandomQuote()

{

return $this->quotes[array_rand($this->quotes, 1)];

}

http://www.seodrupal.vn | Learn Drupal Online

Page 46: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

function actionIndex()

{

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

'quote' => $this->getRandomQuote()

));

}

//ajax callback

function actionGetQuote()

{

$this->renderPartial('_quote', array(

'quote' => $this->getRandomQuote(),

));

}

}

Tiếp theo tạo views : protected/views/quote/index.php

<h2>Quote of the day</h2>

<div id="quote-of-the-day">

<?php $this->renderPartial('_quote', array(

'quote' => $quote,

))?>

</div>

<?php echo CHtml::ajaxLink('Next quote', array('getQuote'),

http://www.seodrupal.vn | Learn Drupal Online

Page 47: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

array('update' => '#quote-of-the-day'))?>

Tạo views thứ 2 là protected/views/quote/_quote.php

&ldquo;<?php echo $quote[0]?>&rdquo;, <?php echo $quote[1]?>

Vào trình duyệt gõ : http://localhost/skybook/index.php/quote/index

Để có thể xem cấu hình ajax tạo ra bạn dùng firebug trỏ vào vùng next quote sẽ hiển thị javascript tạo ra ajax từ Chtml::ajaxLink.

2. Quản lý Assert

Một trong những khả năng tuyệt vời của Yii là có thể bảo vệ tài sản (mã nguồn) một cách hiệu quả

Khi thực thi một extension được kích hoạt javascript,css,images thì folder gốc không thể truy nhập được từ trình duyệt.

Khi bạn cần truy nhập lại tài sản (css,js,image) của bạn chỉ cần combine javascript

Khi bạn sử dụng assert nhiều lần trong phân trang và tránh trùng lặp

Hãy bắt đầu kế hoạch trước, bạn có thể thay đổi widgets tới bất kì thư mục nào, nó nằm trong protected/components. Nó chấp nhận có một hoặc 2 class trong đó, nhưng khi số lượng class tăng lên, nó sẽ tạo ra vấn đề,Tạo một assert trong widget với protected/extensions/facebook_events.và đặt trong đó ajax-loader.gif bạn vui lòng download tại http://ajaxload.info . Tiếp theo tạo facebook_event.css và facebook_event.js

Tạo EFacebookEvents.php trong folder facebook_events

http://www.seodrupal.vn | Learn Drupal Online

Page 48: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php

class EFacebookEvents extends CWidget

{

public $keyword;

private $loadingImageUrl;

protected $url = "https://graph.facebook.com/search?q=%s&type=

event&callback=?";

protected function getUrl()

{

return sprintf($this->url, urlencode($this->keyword));

}

public function init()

{ // khoi tao duong dan file assets

$assetsDir = dirname(__FILE__).'/assets';

$cs = Yii::app()->getClientScript();

$cs->registerCoreScript("jquery");

// thiet lap duong dan toi file js

$cs->registerScriptFile(

Yii::app()->assetManager->publish(

$assetsDir.'/facebook_events.js'

),

CClientScript::POS_END

);

//thiet lap duong dan toi file css

http://www.seodrupal.vn | Learn Drupal Online

Page 49: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$cs->registerCssFile(

Yii::app()->assetManager->publish(

$assetsDir.'/facebook_events.css'

)

);

// thiet lap duong dan toi file images

// asset can be accessed with

$this->loadingImageUrl = Yii::app()->assetManager->publish(

$assetsDir.'/ajax-loader.gif'

);

}

public function run()

{

$this->render("body", array(

'url' => $this->getUrl(),

'loadingImageUrl' => $this->loadingImageUrl,,

'keyword' => $this->keyword,

));

}

}

Tiếp theo vào protected/extensions/facebook_events/ tạo views/body.php

<div class="facebook-events" data-url="<?php echo $url?>">

<h2><?php echo $keyword?> events</h2>

http://www.seodrupal.vn | Learn Drupal Online

Page 50: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<div class="data">

<?php echo CHtml::image($loadingImageUrl)?>

</div>

</div>

Tiếp theo vào file facebook_events.js :

jQuery(function($){

$(".facebook-events").each(function(){

var url = $(this).data("url");

var container = $(".data", this);

$.getJSON(url,function(json){

var html = "<ul>";

$.each(json.data,function(){

html += "<li>"+

"<p><strong>" + this.name + "</strong>

</p><p>"+this.location

"</p></li>";

});

html += "</ul>";

container.html(html);

});

});

});

Vào file facebook_events.css:

.facebook-events {

http://www.seodrupal.vn | Learn Drupal Online

Page 51: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

padding: 10px;

width: 400px;

float: left;

}

.facebook-events ul {

padding: 0;

}

.facebook-events li {

list-style: none;

border: 1px solid #ccc;

padding: 10px;

margin: 2px;

}

Vào protected/views/site/index.php

<?php $this->widget("ext.facebook_events.EFacebookEvents", array(

'keyword' => 'php',

))?>

<?php $this->widget("ext.facebook_events.EFacebookEvents", array(

'keyword' => 'jquery',

))?>

Giờ vào trang chủ để xem kết quả:

http://www.seodrupal.vn | Learn Drupal Online

Page 52: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Cách thức hoạt động:

Khi chúng ta sử dụng $this->widget trong site/index view, 2 phương thức trong EFacebookEvents đều chạy init cái mà public assert và kết nối chúng tới trang, sau đó chạy render html.

Những gì có trong thư mục :Assert

Nếu bạn kiểm tra sẽ thấy những dòng sau:

Thư mục như 1a6630a0 được sử dụng để ngăn chặn va chạm của các tập tin với những cái tên tương tự từ các thư mục khác nhau. Tên của thư mục

http://www.seodrupal.vn | Learn Drupal Online

Page 53: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

là một hàm băm mã hóa path assert directory.Trước đó assert từ mỗi thư mục được copy tới cùng một nơi,điều này nghĩa là thư mục image,css,js public của bạn có thể tham chiếu tới images,css,js từ các đường dẫn lien quan.

3.Including resource tới trang

Yii có tên class đặc biệt là CClientScript để giúp cho việc include script css.

Cách thức như :

Yii::app()->clientScript->registerScriptFile("http://example.com/js/main.js");

Đối với core jquery:

Yii::app()->clientScript->registerCoreScript('jquery');

Đối với CSS;

Yii::app()->clientScript->registerCssFile('http://example.com/css/main.css');

Yii::app()->registerCss('myCSS', 'body {margin: 0; padding: 0}','all');

Đăng ký linker resources:

Yii::app()->clientScript->registerLinkTag(

'alternate',

'application/rss+xml',

$this->createUrl('rss/articles')

);

Đăng ký metaTag:

Yii::app()->clientScript->registerMetaTag(' text/html;charset=utf-8',

null, 'Content-Type');

http://www.seodrupal.vn | Learn Drupal Online

Page 54: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

4. Làm việc với JSON

JSON rất đơn giản,dễ sử dụng, là sử dụng định dạng AJAX application data.YII cũng có làm việc với nó.

Đầu tiên ta vào phpmyadmin và tạo mới table : Tin tức:

CREATE TABLE `news` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`created_on` int(11) unsigned NOT NULL,

`title` varchar(255) NOT NULL,

PRIMARY KEY (`id`)

)

Tiếp theo bạn vào GII rồi gererated Model, bạn gõ news và nhấn generated. Sau khi thành công kiểm tra tại protected/models xem đã có file new chưa ?

Vào protected/controllers tạo NewsController.php

<?php

class NewsController extends Controller

{

//tao bo loc.

public function filters()

{

return array(

'ajaxOnly + data',

);

}

public function actionIndex()

http://www.seodrupal.vn | Learn Drupal Online

Page 55: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

$this->render('index');

}

public function actionData()

{

$criteria = new CDbCriteria();

$criteria->order = 'created_on DESC';

$criteria->limit = 10;

$news = News::model()->findAll($criteria);

echo CJSON::encode($news);

}

public function actionAddRandomNews()

{

$news = new News();

$news->title = "Item #".rand(1, 10000);

$news->created_on = time();

$news->save();

echo "OK";

}

}

Tiếp theo bạn tạo views: protected/views/news/index.php

<div class="news-list">

Loading…

</div>

http://www.seodrupal.vn | Learn Drupal Online

Page 56: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php Yii::app()->clientScript->registerCoreScript("jquery")?>

<script type="text/javascript">

jQuery(function($) {

var newsList = $('.news-list');

function updateNews(){

newsList.html("Loading…");

$.ajax({

url: "<?php echo $this->createUrl('data')?>",

dataType: 'json',

cache: false,

success: function(data) {

var out = "<ol>";

$(data).each(function(){

out+="<li>"+this.title+"</li>";

});

out += "</ol>";

newsList.html(out);

}

});

}

updateNews();

setInterval(function(){

updateNews()

}, 2000);

});

http://www.seodrupal.vn | Learn Drupal Online

Page 57: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

</script>

Sau thực hiện xong vào trình duyệt gõ: http://localhost/skybook/index.php/news/index

5: Xử lí biến số của input

Đôi khi ứng dụng yêu cầu nhập form chứa biến số của input,một chức năng quản lý ứng dụng có thể cung cấp hình ảnh,nơi bạn có thể them một hoặc nhiều chức năng trong danh sách task,bạn có thể xem ví dụ dưới đây:

http://www.seodrupal.vn | Learn Drupal Online

Page 58: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Bởi mặc định, trang sẽ hiển thị một vài chức năng và hai button: Add task sẽ them thuộc tính và save là lưu lại thong tin của form.

Ta sẽ tạo protected/models file Task.php:

<?php

class Task extends CFormModel

{

public $title;

public $text;

public function rules() //thiet lap quy tac

{

return array(

array('title', 'required'), // tieu de khong rong

array('text', 'safe'), //text duoc bao ve

);

}

}

Tiếp theo vào protected/controllers/TaskController.php

<?php

class TaskController extends Controller

{

public function filters()

{

return array(

'ajaxOnly + field'

);

http://www.seodrupal.vn | Learn Drupal Online

Page 59: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

public function actionIndex()

{

$models = array();

if(!empty($_POST['Task'])) //kiem tra co request post hay k

{

foreach($_POST['Task'] as $taskData)

{

$model = new Task();

$model->setAttributes($taskData);

if($model->validate())

$models[] = $model;

}

}

if(!empty($models)){

// Neu ban muon luu lai du lieu co the luu tai day

}

else

$models[] = new Task();

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

'models' => $models,

));

}

public function actionField($index)

{

http://www.seodrupal.vn | Learn Drupal Online

Page 60: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$model = new Task();

$this->renderPartial('_task', array(

'model' => $model,

'index' => $index,

));

}

}

Ta tạo view: protected/views/task/index.php

<div class="form">

<?php echo CHtml::beginForm()?>

<ul class="tasks">

<?php for($i=0; $i<count($models); $i++):?>

<?php $this->renderPartial('_task', array(

'model' => $models[$i],

'index' => $i,

))?>

<?php endfor ?>

</ul>

<div class="row buttons">

<?php echo CHtml::button('Add task',

array('class' => 'tasks-add'))?>

<?php Yii::app()->clientScript->registerCoreScript

("jquery")?>

<script>

http://www.seodrupal.vn | Learn Drupal Online

Page 61: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$(".tasks-add").click(function(){

$.ajax({

success: function(html){

$(".tasks").append(html);

},

type: 'get',

url: '<?php echo $this->createUrl('field')?>',

data: {

index: $(".tasks li").size()

},

cache: false,

dataType: 'html'

});

});

</script>

<?php echo CHtml::submitButton('Save')?>

</div>

<?php echo CHtml::endForm()?>

</div>

Cuối cùng tạo views cho partial: protected/views/task/_task.php

<li>

<div class="row">

<?php echo CHtml::activeLabel($model, "[$index]title")?>

<?php echo CHtml::activeTextField($model, "[$index]title")?>

</div>

http://www.seodrupal.vn | Learn Drupal Online

Page 62: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<div class="row">

<?php echo CHtml::activeLabel($model, "[$index]text")?>

<?php echo CHtml::activeTextArea($model, "[$index]text")?>

</div>

</li>

Vào trình duyệt gõ http://localhost/skybook/task/index để xem kết quả.

CHƯƠNG 4 LÀM VIỆC VỚI FORM

Chương này bạn sẽ khám phá:

Uploading files

Thêm Captcha

Custom Captcha

Tạo một custom widget với Cwidget

1. Uploading files

Trong folder protected bạn tạo một thư mục mới có tên: uploads

Chúng ta sẽ bắt đầu với model, vì vậy sẽ tạo protected/models/Upload.php

http://www.seodrupal.vn | Learn Drupal Online

Page 63: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php

class Upload extends CFormModel

{

public $file;

public function rules()

{

return array(//yeu cau thuoc tinh file có thể them các thuộc tính khác cách nhau dấu //phẩy

array('file', 'file', 'types'=>'zip'),

);

}

}

Trong protected/controllers tạo UploadController.php

<?php

class UploadController extends Controller

{

function actionIndex()

{

$dir = Yii::getPathOfAlias('application.uploads'); //hien thi duong dan upload

$uploaded = false;

$model=new Upload(); //goi model

if(isset($_POST['Upload']))

{

http://www.seodrupal.vn | Learn Drupal Online

Page 64: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$model->attributes=$_POST['Upload'];

$file=CUploadedFile::getInstance($model,'file');

if($model->validate()){ //validate form thanh cong thi luu file do vao thu muc

$uploaded = $file->saveAs($dir.'/'.$file->getName());

}

}

$this->render('index', array( //hien thi thong tin ten file, duong dan

'model' => $model,

'uploaded' => $uploaded,

'dir' => $dir,

));

}

}

Tiếp theo ta tạo views: protected/views/upload/index.php

<?php if($uploaded):?>

<p>File was uploaded. Check <?php echo $dir?>.</p>

<?php endif ?>

<?php echo CHtml::beginForm('','post',array

('enctype'=>'multipart/form-data'))?>

<?php echo CHtml::error($model, 'file')?>

<?php echo CHtml::activeFileField($model, 'file')?>

<?php echo CHtml::submitButton('Upload')?>

<?php echo CHtml::endForm()?>

Vào trình duyệt gõ: http://localhost/skybook/index.php/upload/index

http://www.seodrupal.vn | Learn Drupal Online

Page 65: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

2. Thêm Captcha

Tạo protected/models/EmailForm.php

<?phpclass EmailForm extends CFormModel

{

public $email;

function rules(){

return array(

array('email', 'email'),

);

}

}

Tạo protected/controller/EmailController.php

<?php

class EmailController extends Controller

{http://www.seodrupal.vn | Learn Drupal Online

Page 66: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public function actionIndex()

{

$success = false;

$model = new EmailForm();

if(!empty($_POST['EmailForm']))

{

$model->setAttributes($_POST['EmailForm']);

if($model->validate())

{

$success = true;

// handle form here

}

}

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

'model' => $model,

'success' => $success,

));

}

}

Tạo views: protected/email/index.php

<?php if($success):?>

<p>Success!</p>

<?php endif?>

<?php echo CHtml::beginForm()?>

<p>

http://www.seodrupal.vn | Learn Drupal Online

Page 67: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php echo CHtml::activeLabel($model, 'email')?>

<?php echo CHtml::activeTextField($model, 'email')?>

<?php echo CHtml::error($model, 'email')?>

</p>

<p>

<?php echo CHtml::submitButton()?>

</p>

<?php echo CHtml::endForm()?>

Vào http://localhost/skybook/index.php/email/index test

3.Custom Captcha

Ta có thể custom captcha một cách dễ dàng nhờ CCaptchaAction

Trong protected/components tạo MathCaptchaAction.php

<?php

class MathCaptchaAction extends CCaptchaAction

{

protected function generateVerifyCode()http://www.seodrupal.vn | Learn Drupal Online

Page 68: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

return mt_rand((int)$this->minLength,

(int)$this->maxLength);

}

public function renderImage($code)

{

parent::renderImage($this->getText($code));

}

protected function getText($code)

{

$code = (int)$code;

$rand = mt_rand(1, $code-1);

$op = mt_rand(0, 1);

if($op)

return $code-$rand.»+».$rand;

else

return $code+$rand.»-».$rand;

}

}

Trong controller trước them action sau:

public function actions()

{

return array(

'captcha'=>array(

'class'=>'MathCaptchaAction',

http://www.seodrupal.vn | Learn Drupal Online

Page 69: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'minLength' => 1,

'maxLength' => 10,

),

);

}

Ta có kết quả:

4. Tạo một custom input widget với CInputWidget

Trong protected/components tạo RangeInputField.php

<?php

class RangeInputField extends CInputWidget

{

public $attributeFrom;

public $attributeTo;

http://www.seodrupal.vn | Learn Drupal Online

Page 70: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public $nameFrom;

public $nameTo;

public $valueFrom;

public $valueTo;

function run()

{

if($this->hasModel())

{

echo CHtml::activeTextField

($this->model, $this->attributeFrom);

echo ' &rarr; ';

echo CHtml::activeTextField

($this->model, $this->attributeTo);

}

else {

echo CHtml::textField($this->nameFrom, $this->valueFrom);

echo ' &rarr; ';

echo CHtml::textField($this->nameTo, $this->valueTo);

}

}

}

Tiếp theo vào protected/models RangeForm.php

<?php

class RangeForm extends CFormModel

{

http://www.seodrupal.vn | Learn Drupal Online

Page 71: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public $from;

public $to;

function rules()

{

return array(

array('from, to', 'numerical', 'integerOnly' => true),

array('from', 'compare', 'compareAttribute' => 'to',

'operator' => '<=', 'skipOnError' => true),

);

}

}

Tiếp theo vào protected/controllers tạo RangeController.php

<?php

class RangeController extends Controller

{

function actionIndex()

{

$success = false;

$model = new RangeForm();

if(!empty($_POST['RangeForm']))

{

$model->setAttributes($_POST['RangeForm']);

if($model->validate())

$success = true;

}

http://www.seodrupal.vn | Learn Drupal Online

Page 72: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

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

'model' => $model,

'success' => $success,

));

}

}

Tiếp theo vào protected/views/ tạo range/index.php

<?php if($success):?>

<p>Success!</p>

<?php endif?>

<?php echo CHtml::errorSummary($model)?>

<?php echo CHtml::beginForm()?>

<?php $this->widget('RangeInputField', array(

'model' => $model,

'attributeFrom' => 'from',

'attributeTo' => 'to',

))?>

<?php echo CHtml::submitButton('Submit')?>

<?php echo CHtml::endForm()?>

Vào trình duyệt gõ: http://localhost/skybook/index.php/range/index

http://www.seodrupal.vn | Learn Drupal Online

Page 73: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

CHƯƠNG 5 Database ,ActiveRecord,và Model Tricks

Trong chương này bạn sẽ khám phá:

http://www.seodrupal.vn | Learn Drupal Online

Page 74: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Nhận dữ liệu từ database

Sử dụng scopes để hiển thị model với các ngôn ngữ khác nhau

Truy cập models field với AR

Applying Markdown và HTML

Hightlight code với Yii

Tự động timestamp

Thiết lập author tự động

Thực thi các bảng kế thừa đơn

Sử dụng CDbCriteria

1. Nhận dữ liệu từ database

Hầu hết ứng dụng ngày nay đều sử dụng database,dù là một website nhỏ cho tới mạng xã hội , ít nhất một phần được bảo vệ bởi database,Yii giới thiệu 3 cách làm việc trên database:

Active Record

Query Builder

SQL và DAO

Để thực hiện bạn vào : http://dev.mysql.com/doc/sakila/en/sakila.html để tải gói database về sau đó vào phpmyadmin import vào csdlTiếp theo vào Gii tạo model actor và field tables

Ta vào protected /controller tạo DbController.php

<?phpclass DbController extends Controller{protected function afterAction($action){$time = sprintf('%0.5f', Yii::getLogger()

http://www.seodrupal.vn | Learn Drupal Online

Page 75: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

->getExecutionTime());$memory = round(memory_get_peak_usage()/(1024*1024),2)."MB";echo "Time: $time, memory: $memory";parent::afterAction($action);}public function actionAr(){$actors = Actor::model()->findAll(array('with' => 'films','order' => 't.first_name, t.last_name, films.title'));echo '<ol>';foreach($actors as $actor){echo '<li>';echo $actor->first_name.' '.$actor->last_name;echo '<ol>';foreach($actor->films as $film){echo '<li>';echo $film->title;echo '</li>';}echo '</ol>';echo '</li>';}echo '</ol>';}public function actionQueryBuilder(){$rows = Yii::app()->db->createCommand()->from('actor')->join('film_actor', 'actor.actor_id=film_actor.actor_id')->leftJoin('film', 'film.film_id=film_actor.film_id')->order('actor.first_name, actor.last_name, film.title')->queryAll();$this->renderRows($rows);}public function actionSql(){$sql = "SELECT *

FROM actor aJOIN film_actor fa ON fa.actor_id = a.actor_idJOIN film f ON fa.film_id = f.film_idORDER BY a.first_name, a.last_name, f.title";

http://www.seodrupal.vn | Learn Drupal Online

Page 76: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$rows = Yii::app()->db->createCommand($sql)->queryAll();$this->renderRows($rows);}public function renderRows($rows){$lastActorName = null;echo '<ol>';foreach($rows as $row){$actorName = $row['first_name'].' '.$row['last_name'];if($actorName!=$lastActorName){if($lastActorName!==null){echo '</ol>';echo '</li>';}$lastActorName = $actorName;echo '<li>';echo $actorName;echo '<ol>';}echo '<li>';echo $row['title'];echo '</li>';}echo '</ol>';}}

Sauk hi thực hiện xong bạn chạy trên trình duyệt và vào databse để kiểm tra dữ liệu mới tạo.

2. Sử dụng Scopes để hiển thị models cho những ngôn ngữ khác nhau

Đa ngôn ngữ trong website của bạn là việc điều khiển không hề dễ dàng,bạn cần phải thay đổi giao diện,thay đổi tin nhắn,định dạng ngày tháng,và rất nhiều thứ khác. Yii giúp bạn làm việc hiệu quả hơn với CLDR (Unicode Common Locate Data Repository) dữ liệu và cung cấp công cụ thay đổi ngôn ngữ. Khi tới ứng dụng với nhiều ngôn ngữ, bạn có thể sẽ tìm ra cách của riêng bạn.

http://www.seodrupal.vn | Learn Drupal Online

Page 77: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Để bắt đầu tạo mới databse: vào phpmyadmin và chọn mục SQL :

DROP TABLE IF EXISTS `post`;CREATE TABLE IF NOT EXISTS `post` (`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,`lang` VARCHAR(5) NOT NULL DEFAULT 'en',`title` VARCHAR(255) NOT NULL,`text` TEXT NOT NULL,PRIMARY KEY (`id`));INSERT INTO `post`(`id`,`lang`,`title`,`text`)VALUES (1,'en_us','Yii news','Text in English'),(2,'de','Yii Nachrichten','Text in Deutsch');

Sau khi hoàn tất vào GII chọn model generated gõ Post vào modelname và generated

Sauk hi generated bạn vào models/Post.php và viết lại method giống như sau:

class Post extends CActiveRecord

{

public function defaultScope()

{

return array(

'condition' => "lang=:lang",

'params' => array(

':lang' => Yii::app()->language,

),

);

}

public function lang($lang){

$this->getDbCriteria()->mergeWith(array(

'condition' => "lang=:lang",

http://www.seodrupal.vn | Learn Drupal Online

Page 78: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'params' => array(

':lang' => $lang,

),

));

return $this;

}

}

Tiếp theo vào protected/controllers/DbtestController.php

<?php

class DbtestController extends CController

{

public function actionIndex()

{

// Hiển thị ngôn ngữ mặc định

$posts = Post::model()->findAll();

echo '<h1>Default language</h1>';

foreach($posts as $post)

{

echo '<h2>'.$post->title.'</h2>';

echo $post->text;

}

// Hiển thị ngôn ngữ của Đức

$posts = Post::model()->lang('de')->findAll();

echo '<h1>German</h1>';

foreach($posts as $post)

http://www.seodrupal.vn | Learn Drupal Online

Page 79: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

echo '<h2>'.$post->title.'</h2>';

echo $post->text;

}

}

}

Sauk hi hoàn thành vào trình duyệt gõ : http://localhost/skybook/dbtest/index

3. Truy cập model field với Active-Record event-like method

Vào phpmyadmin chọn mục SQL và thực hiện query sau:

DROP TABLE IF EXISTS `post`;

CREATE TABLE IF NOT EXISTS `post` (

`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,

`title` VARCHAR(255) NOT NULL,

`text` TEXT NOT NULL,

PRIMARY KEY (`id`)

);

http://www.seodrupal.vn | Learn Drupal Online

Page 80: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Tiếp theo vào Gii generated model Post

Sau đó bạn vào models/Post.php và thêm hàm sau:

protected function beforeSave()

{

$this->text = preg_replace('~((?:https?|ftps?)://.*?)( |$)~iu',

'<a href="\1">\1</a>\2', $this->text);

return parent::beforeSave();

}

Tiếp theo vào protected/controllers tạo TestController.php

<?php

class TestController extends CController

{

function actionIndex()

{

$post=new Post();

$post->title='links test';

$post->text='test http://www.đập chết mẹ tàu khựa.vn/ test';

$post->save();

print_r($post->text);

}

}

Vào tình duyệt gõ http://localhost/skybook/test/index để xem kết quả.

Cách làm việc như sau:

http://www.seodrupal.vn | Learn Drupal Online

Page 81: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

beforeSave (trước khi lưu) được định nghĩa trong CActiveRecord class và chỉ thực hiện hàm trước khi lưu models.Bởi sử dụng biểu thức quy tắc, chúng thay thế mọi thứ giống một url với một link được sử dụng và gọi lại để hàm thực thi cha,sự kiện thực tế là raised propery , trong hàm saving bạn có thể trả về giá trị false.

Một số method bạn nên biết:

AfterConstruct : Hàm được gọi sau khi một model được khởi tạo bởi mã nguồn

beforeDelete/afterDelete : Hàm được gọi trước/sau khi bản ghi bị xóa

beforeSave/afterSave: Hàm được khởi tạo trước khi/sau khi lưu bản ghi thành công.

beforeValidate/afterValidate: Hàm được gọi khi khởi tạo trước/sau khi validation form kết thúc.

4. Highlight code với Yii

Nếu bạn post code,công ty của bạn lien quan đến nghề báo và wiki blog,sẽ luôn luôn tốt hơn khi hệ thống có highlight (hiệu ứng nháy), và một người đọc code cũng cảm thấy thoải mái.

Để thực hiện ta vào phpmyadmin chọn mục SQL và thực hiện query sau:

CREATE TABLE `snippet` (

`id` int(11) unsigned NOT NULL auto_increment,

`title` varchar(255) NOT NULL,

`code` text NOT NULL,

http://www.seodrupal.vn | Learn Drupal Online

Page 82: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

`html` text NOT NULL,

`language` varchar(20) NOT NULL,

PRIMARY KEY (`id`)

);

Tiếp theo vào Giii generated model Snippet

Sauk hi generate thành công bạn thay đổi hàm rules trong Snippet.php ở protected/models/Snippet.php

public function rules()

{

return array(

array('title, code, language', 'required'),

array('title', 'length', 'max'=>255),

array('language', 'length', 'max' => 20),

);

}

Thêm method sau khi validate:

protected function afterValidate()

{

$highlighter = new CTextHighlighter();

$highlighter->language = $this->language;

$this->html = $highlighter->highlight($this->code);

return parent::afterValidate();

}

public function getSupportedLanguages()

http://www.seodrupal.vn | Learn Drupal Online

Page 83: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

return array(

'php' => 'PHP',

'css' => 'CSS',

'html' => 'HTML',

'javascript' => 'JavaScript',

);

}

Tiếp theo vào protected/controller tạo SnippetController.php

<?php

class SnippetController extends CController

{

public function actionIndex()

{

$criteria = new CDbCriteria();

$criteria->order = 'id DESC';

$models = Snippet::model()->findAll();

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

'models' => $models,

));

}

public function actionView($id)

{

$model = Snippet::model()->findByPk($id);

if(!$model)

http://www.seodrupal.vn | Learn Drupal Online

Page 84: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

throw new CException(404);

$this->render('view', array(

'model' => $model,

));

}

public function actionAdd()

{

$model = new Snippet();

$data = Yii::app()->request->getPost('Snippet');

if($data)

{

$model->setAttributes($data);

if($model->save())

$this->redirect(array('view', 'id' => $model->id));

}

$this->render('add', array(

'model' => $model,

));

}

public function actionEdit($id){

$model = Snippet::model()->findByPk($id);

if(!$model)

throw new CHttpException(404);

$data = Yii::app()->request->getPost('Snippet');

if($data)

http://www.seodrupal.vn | Learn Drupal Online

Page 85: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

$model->setAttributes($data);

if($model->save())

$this->redirect(array('view', 'id' => $model->id));

}

$this->render('edit', array(

'model' => $model,

));

}

}

Tiếp theo ta tạo view trong protected/views/snippet/index.php

<h2>Snippets</h2>

<?php echo CHtml::link('Add snippet', array('add'))?>

<ol>

<?php foreach($models as $model):?>

<li>

<?php echo CHtml::link(

CHtml::encode($model->title),

array('view', 'id' => $model->id)

)?>

</li>

<?php endforeach?>

</ol>

Tạo tiếp view thứ 2 : protected/views/snippet/view.php

http://www.seodrupal.vn | Learn Drupal Online

Page 86: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<h2><?php echo CHtml::link('Snippets', array('index'))?> → <?php

echo CHtml::encode($model->title)?>

</h2>

<?php echo CHtml::link('Edit', array

('edit', 'id' => $model->id))?>

<div>

<?php echo $model->html?>

</div>

Tạo view add : protected/views/snippet/add.php

<h2><?php echo CHtml::link('Snippets', array('index'))?> → Add

snippet

</h2>

<?php $this->renderPartial('_form', array('model' => $model))?>

Tạo view edit: protected/views/snippet/edit.php

<h2><?php echo CHtml::link('Snippets', array('index'))?> → Edit

snippet

</h2>

<?php $this->renderPartial('_form', array('model' => $model))?>

Tạo view _form : protected/views/snippet/_form.php

<?php echo CHtml::beginForm()?>

<ul>

<li>

<?php echo CHtml::activeLabel($model, 'title')?>

<?php echo CHtml::activeTextField($model, 'title')?>

</li>

http://www.seodrupal.vn | Learn Drupal Online

Page 87: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<li>

<?php echo CHtml::activeLabel($model, 'code')?>

<?php echo CHtml::activeTextArea($model, 'code')?>

</li>

<li>

<?php echo CHtml::activeLabel($model, 'language')?>

<?php echo CHtml::activeDropDownList($model, 'language',

$model->getSupportedLanguages())?>

</li>

<li>

<?php echo CHtml::submitButton('Save')?>

</li>

</ul>

<?php echo CHtml::endForm()?>

Sauk hi hoàn thành vào trình duyệt gõ : http://localhost/skybook/snippet/index

Từ từ tận hưởng hiệu ứng:

http://www.seodrupal.vn | Learn Drupal Online

Page 88: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

5. Thực thi kế thừa bảng

Dữ liệu quan hệ thường không hỗ trợ kế thừa . Nếu bạn muốn thực hiện kế thừa database, bạn cũng có thể được hỗ trợ từ Yii

Cấu trúc kế thừa đơn giản như:

Xe

|-> Xe thể thao

|->Xe du lịch

|->Xe gia đình.

Để bắt đầu ta vào phpmyadmin chọn sql và chạy query sau:

CREATE TABLE `car` (

`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,

`name` varchar(255) NOT NULL,

`type` varchar(100) NOT NULL,

PRIMARY KEY (`id`)

);

INSERT INTO `car` (`name`, `type`)

VALUES ('Ford Focus', 'family'),

('Opel Astra', 'family'),

('Kia Ceed', 'family'),

http://www.seodrupal.vn | Learn Drupal Online

Page 89: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

('Porsche Boxster', 'sport'),

('Ferrari 550', 'sport');

Ta generated model Car trong Gii

Trong Protected/models/Car.php ta sửa lại như sau:

<?php

class Car extends CActiveRecord

{

public static function model($className=__CLASS__)

{

return parent::model($className);

}

public function tableName()

{

return 'car';

}

protected function instantiate($attributes)

{

switch($attributes['type'])

{

case 'sport':

$class='SportCar';

break;

case 'family':

$class='FamilyCar';

break;

http://www.seodrupal.vn | Learn Drupal Online

Page 90: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

default:

$class=get_class($this);

}

$model=new $class(null);

return $model;

}

}

Sau đó ta kế thừa cho protected/models/SportCar.php

<?php

class SportCar extends Car

{

public static function model($className=__CLASS__)

{

return parent::model($className);

}

public function defaultScope()

{

return array(

'condition'=>"type='sport'",

);

}

}

Tiếp theo ta cũng kế thừa cho protected/models/FamilyCar.php

<?php

class FamilyCar extends Car

http://www.seodrupal.vn | Learn Drupal Online

Page 91: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

public static function model($className=__CLASS__)

{

return parent::model($className);

}

public function defaultScope()

{

return array(

'condition'=>"type='family'",

);

}

}

Trong protected/controller tạo TestController.php

<?php

class TestController extends CController

{

public function actionIndex()

{

echo "<h1>All cars</h1>";

$cars = Car::model()->findAll();

foreach($cars as $car)

{

// Mỗi chiếc xe có thể là của class car, sportcar, hoặc familycar

echo get_class($car).' '.$car->name."<br />";

}

http://www.seodrupal.vn | Learn Drupal Online

Page 92: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

echo "<h1>Sport cars only</h1>";

$sportCars = SportCar::model()->findAll();

foreach($sportCars as $car)

{

echo get_class($car).' '.$car->name."<br />";

}

}

}

Xong xuôi vào trình duyệt gõ : http://localhost/skybook/test/index

6. Sử dụng CdbCriteria

Khi sử dụng Active Record method như findAll, hoặc find, chúng ta có thể nhận tiêu chuẩn giống như tham số,nó có thể trả về mảng hay một khởi tạo của CdbCriteria class.Class này hiển thị query tiêu chuẩn, giống như điều kiện,ordering by,limit/offset, vv…

Thường thường nó hay được sử dụng như dưới đây:

$criteria = new CDbCriteria();

$criteria->limit = 10;

$criteria->order= 'id DESC';

$criteria->with = array('comments');

http://www.seodrupal.vn | Learn Drupal Online

Page 93: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$criteria->compare('approved', 1);

$criteria->addInCondition('id', array(4, 8, 15, 16, 23, 42));

$posts = Post::model()->findAll($criteria);

Cách làm việc:

Bản thân class Criteria không xây dựng query, nhưng chỉ hiển thị dữ liệu hoặc cho phép điều chỉnh chúng, Hàm làm việc thực tế nằm trong Active Record method nơi các tiêu chuẩn của class này sử dụng.

Dịch code có thể đọc như sau:

Hiển thị 10 dòng post với comment từ approved post với id trong khoảng 4,8,15,16,24 hoặc 42 order by id.

Select * from post p (định danh post) JOIN (nối) comment c(định danh comment) ON (điều kiện nối) p.id=c.post_id where p.approval=1 and p.id in (4,8,16,15,24,42) order by p.id DESC LIMIT 10.

http://www.seodrupal.vn | Learn Drupal Online

Page 94: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

CHƯƠNG 6 KẾ THỪA Yii

Trong chương này, bạn sẽ khám phá:

Sử dụng data provides

Sử dụng grids (lưới)

Sử dụng lists (danh sách)

Tạo custom grid column( Cột lưới)

Yii có thư viện hữu ích gọi là Zii, nó đồng hành cùng với framework và một số class khác giúp cho việc phát triển trở lên dễ dàng hơn bao giờ hết,hầu hết thành phần chủ yếu là grid và list cái cho phép bạn xây dựng dữ liệu trong Admin và user website rất nhanh và đẹp. Trong chương này bạn sẽ học cách điều chỉnh component và những thứ bạn cần,bạn sẽ học về data provides,chúng là một phần trong core framework.

1 Sử dụng data provides (nhà cung cấp dữ liệu)

Data provides được sử dụng để triệu tập dữ liệu model giống như sắp xếp, phân trang, và querying.Chúng được sử dụng với grids và lists. Bởi vì cả 2 widget và provider là một tiêu chuẩn (chuẩn mực),bạn có thể hiển thị giống như dữ liệu sử dụng khác widget và bạn có thể hiện dữ liệu cho một widget từ various provider (tài sản được cung cấp).

Để thực hiện coder bạn vào http://dev.mysql.com/doc/sakila/en/sakila.html download database sau đó import vào csdl thong qua phpmyadmin.

Sử dụng Gii để tạo model film.

Vào protected/views/ tạo grid/index.php

<?php $this->widget('zii.widgets.grid.CGridView',

array('dataProvider' => $dataProvider,

))?>

Sau đó,tạo protected/controllers/GridController.php

<?php

http://www.seodrupal.vn | Learn Drupal Online

Page 95: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

class GridController extends Controller

{

public function actionAR()

{

$dataProvider = new CActiveDataProvider('Film', array(

'pagination'=>array(

'pageSize'=>10,

),

'sort'=>array(

'defaultOrder'=> array('title'=>false),

)

));

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

'dataProvider' => $dataProvider,

));

}

public function actionArray()

{

$yiiDevelopers = array(

array(

'name'=>'Qiang Xue',

'id'=>'2',

'forumName'=>'qiang',

'memberSince'=>'Jan 2008',

'location'=>'Washington DC, USA',

http://www.seodrupal.vn | Learn Drupal Online

Page 96: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'duty'=>'founder and project lead',

'active'=>true,

),

array(

'name'=>'Wei Zhuo',

'id'=>'3',

'forumName'=>'wei',

'memberSince'=>'Jan 2008',

'location'=>'Sydney, Australia',

'duty'=>'project site maintenance and development',

'active'=>true,

),

array(

'name'=>'Sebastián Thierer',

'id'=>'54',

'forumName'=>'sebas',

'memberSince'=>'Sep 2009',

'location'=>'Argentina',

'duty'=>'component development',

'active'=>true,

),

array(

'name'=>'Alexander Makarov',

'id'=>'415',

'forumName'=>'samdark',

http://www.seodrupal.vn | Learn Drupal Online

Page 97: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'memberSince'=>'Mar 2010',

'location'=>'Russia',

'duty'=>'core framework development',

'active'=>true,

),

array(

'name'=>'Maurizio Domba',

'id'=>'2650',

'forumName'=>'mdomba',

'memberSince'=>'Aug 2010',

'location'=>'Croatia',

'duty'=>'core framework development',

'active'=>true,

),

array(

'name'=>'Y!!',

'id'=>'1644',

'forumName'=>'Y!!',

'memberSince'=>'Aug 2010',

'location'=>'Germany',

'duty'=>'core framework development',

'active'=>true,

),

array(

'name'=>'Jeffrey Winesett',

http://www.seodrupal.vn | Learn Drupal Online

Page 98: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'id'=>'15',

'forumName'=>'jefftulsa',

'memberSince'=>'Sep 2010',

'location'=>'Austin, TX, USA',

'duty'=>'documentation and marketing',

'active'=>true,

),

array(

'name'=>'Jonah Turnquist',

'id'=>'127',

'forumName'=>'jonah',

'memberSince'=>'Sep 2009 - Aug 2010',

'location'=>'California, US',

'duty'=>'component development',

'active'=>false,

),

array(

'name'=>'István Beregszászi',

'id'=>'1286',

'forumName'=>'pestaa',

'memberSince'=>'Sep 2009 - Mar 2010',

'location'=>'Hungary',

'duty'=>'core framework development',

'active'=>false,

),

http://www.seodrupal.vn | Learn Drupal Online

Page 99: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

);

$dataProvider = new CArrayDataProvider(

$yiiDevelopers, array(

'sort'=>array(

'attributes'=>array('name', 'id', 'active'),

'defaultOrder'=>array('active' => true, 'name' => false),

),

'pagination'=>array(

'pageSize'=>10,

),

));

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

'dataProvider' => $dataProvider,

));

}

public function actionSQL()

{

$count=Yii::app()->db->createCommand('SELECT COUNT(*)

FROM film')->queryScalar();

$sql='SELECT * FROM film';

$dataProvider=new CSqlDataProvider($sql, array(

'keyField'=>'film_id',

'totalItemCount'=>$count,

'sort'=>array(

'attributes'=>array('title'),

http://www.seodrupal.vn | Learn Drupal Online

Page 100: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'defaultOrder'=>array('title' => false),

),

'pagination'=>array(

'pageSize'=>10,

),

));

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

'dataProvider' => $dataProvider,

));

}

}

Vào localhost /skybook/grid/aR , grid/array và grid/sql để xem kết quả:

http://www.seodrupal.vn | Learn Drupal Online

Page 101: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

2. Sử dụng Zii Grid

Zii grid rất hữu ích và nhanh chóng trong việc tạo khung lưới cho các trang quản trị admin hoặc bất kỳ trang nào yêu cầu về số liệu.

Để bắt đầu bạn vào website : http://dev.mysql.com/doc/sakila/en/

sakila.html. down load database sau do giải nén vào phpmyadmin, chọn table của bạn và import db.

Sử dụng Gii tạo model generated cho customer, address,city.

Tiếp theo vào Gii chọn controller generated : Customer

Chạy customer controller và tới quản trị Manage Customer link trong gii bạn sẽ có kết quả như sau:

3. Sử dụng lists

Zii list là công cụ khá tốt cho việc trình bày dữ liệu ở bất kỳ data provider để kết thúc user khi xử lí phân trang và sắp xếp tự động.CListView là rất dễ dàng trong việc custom vì nó cho phép xây dựng bất kỳ thuộc tính nào trong list page.

Vào website : http://dev.mysql.com/doc/sakila/en/

http://www.seodrupal.vn | Learn Drupal Online

Page 102: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

sakila.html download cơ sở dữ liệu rồi vào phpmyadmin import vào database

Vào gii model generated tạo : customer,store,address,city

Tiếp theo mở gii,chọn CRug generator và nhấn Customer tới model class field, nhấn preview và generated

Gii sẽ generated controller trong protected/controllers

Chạy index action của customer controller ta có kết quả sau :

http://localhost/skybook/customer/index

Thêm tiêu chuẩn sắp xếp:

bạn vào protected/views/customer/index.php và thay thế bằng nội dung sau :

<?php $this->widget('zii.widgets.CListView', array(

'dataProvider'=>$dataProvider,

'itemView'=>'_view',

'sortableAttributes'=>array(

'last_name',

'email',

),

)); ?>

Customer templates:

http://www.seodrupal.vn | Learn Drupal Online

Page 103: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Thay thế views với nội dung sau:

<?php $this->widget('zii.widgets.CListView', array(

'dataProvider'=>$dataProvider,

'itemView'=>'_view',

'sortableAttributes'=>array(

'last_name',

'email',

),

'template' => '{sorter} {pager} {items} {sorter} {pager}',

)); ?>

Customer markup data display

<?php $this->widget('zii.widgets.CListView', array(

'dataProvider'=>$dataProvider,

'itemView'=>'_view',

'itemsTagName' => 'ol',

'itemsCssClass' => 'customers',

'sortableAttributes'=>array(

'last_name',

'email',

),

'template' => '{sorter} {pager} {items} {sorter} {pager}',

)); ?>

Tiếp theo vào protected/views/customer tạo _views.php

<li>

<h2>

http://www.seodrupal.vn | Learn Drupal Online

Page 104: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php

$title = CHtml::encode($data->first_name.' '.$data->last_name);

echo CHtml::link($title, array('view', 'id'=>

$data->customer_id));

?>

</h2>

<ul>

<li>

<strong><?php echo CHtml::encode($data->

getAttributeLabel('store_id')); ?>:</strong>

<?php echo CHtml::encode($data->store->

address->address.', '.$data->store->address->city->city.',

'.$data->store->address->district); ?>

</li>

<li>

<strong><?php echo CHtml::encode($data->

getAttributeLabel('email')); ?>:</strong>

<?php echo CHtml::encode($data->email); ?>

</li>

<li>

<strong><?php echo CHtml::encode($data->

getAttributeLabel('address_id')); ?>:</strong>

<?php echo CHtml::encode($data->address->address.',

'.$data->address->city->city.',

'.$data->address->district); ?>

http://www.seodrupal.vn | Learn Drupal Online

Page 105: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

</li>

<li>

<strong><?php echo CHtml::encode($data->

getAttributeLabel('active')); ?>:</strong>

<?php echo $data->active ? 'Yes' : 'No'; ?>

</li>

</ul>

</li>

Vào protected/assets tạo customer.css

ol.customers {

list-style: none;

margin: 1em 0;

}

ol.customers>li {

margin: 1em;

padding:1em;

background: #fcfcfc;

border: 1px solid #9aafe5;

}

Quay lại file _views trong protected/views/customer và thêm đoạn sau vào dưới cùng

<?php Yii::app()->clientScript->registerCssFile(

Yii::app()->assetManager->publish(Yii::getPathOfAlias('application.

assets').'/customers.css'))?>

Thử lại trên trình duyệt bằng việc F5:

http://www.seodrupal.vn | Learn Drupal Online

Page 106: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

4. Tạo customer Grid column

Hầu hết thời gian bạn không cần tạo khung lưới cho các thuộc tính của bạn khi mà Yii đã cung cấp đầy đủ công cụ thực hiện vì thế nên bạn chỉ cần tạo custom cho riêng mình.

Ta bắt đầu tạo custom grid column cho phép toggling Y/N giá trị và thay đổi giá trị trong models nhờ AJAX

Bạn vào : http://dev.mysql.com/doc/sakila/en/

sakila.html tải database về sau đó vào phpmyadmin import và db của bạn.

Vào GII model generated tạo : customer

Mở Gii chọn CRUD generated chọn : Customer và generated

Cách thực hiện : Trong table chúng ta có một field active (kích hoạt) , chúng ta muốn toggle với flag column . Column sẽ hiển thị 2 trường Y và N quyết định giá trị trả về được cliking hay ko.

Vào protected/components/ tạo FlagColumn.php

<?php

class FlagColumn extends CGridColumn

{

public $name;

public $sortable=true;

http://www.seodrupal.vn | Learn Drupal Online

Page 107: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public $callbackUrl = array('flag');

private $_flagClass = "flag_link";

public function init() {

parent::init();

$cs=Yii::app()->getClientScript();

$gridId = $this->grid->getId();

$script = <<<SCRIPT

jQuery(".{$this->_flagClass}").live("click", function(e){

e.preventDefault();

var link = this;

$.ajax({

dataType: "json",

cache: false,

url: link.href,

success: function(data){

$('#$gridId').yiiGridView.update('$gridId');

}

});

});

SCRIPT;

$cs->registerScript(__CLASS__.$gridId.'#flag_link', $script);

}

protected function renderDataCellContent($row, $data) {

$value=CHtml::value($data,$this->name);

$this->callbackUrl['pk'] = $data->primaryKey;

http://www.seodrupal.vn | Learn Drupal Online

Page 108: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$this->callbackUrl['name'] = urlencode($this->name);

$this->callbackUrl['value'] = (int)empty($value);

$link = CHtml::normalizeUrl($this->callbackUrl);

echo CHtml::link(!empty($value) ? 'Y' : 'N', $link, array(

'class' => $this->_flagClass,

));

}

protected function renderHeaderCellContent()

{

if($this->grid->enableSorting && $this->sortable &&

$this->name!==null)

echo $this->grid->dataProvider->getSort()->link(

$this->name,$this->header);

else if($this->name!==null && $this->header===null)

{

if($this->grid->dataProvider instanceof CActiveDataProvider)

echo CHtml::encode($this->grid->dataProvider->

model->getAttributeLabel($this->name));

else

echo CHtml::encode($this->name);

}

else

parent::renderHeaderCellContent();

}

}

http://www.seodrupal.vn | Learn Drupal Online

Page 109: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Tiếp theo vào protected/controllers/CustomerController.php và thay đổi action Flag

public function actionFlag($pk, $name, $value){

$model = $this->loadModel($pk);

$model->{$name} = $value;

$model->save(false);

if(!Yii::app()->request->isAjaxRequest){

$this->redirect('admin');

}

}

Cuối cùng vào protected/views/customer/admin.php

Thay đổi dòng widget:

<?php $this->widget('zii.widgets.grid.CGridView', array(

'id'=>'customer-grid',

'dataProvider'=>$model->search(),

'filter'=>$model,

'columns'=>array(

'customer_id',

'store_id',

'first_name',

'last_name',

'email',

'address_id',

array(

http://www.seodrupal.vn | Learn Drupal Online

Page 110: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'class' => 'FlagColumn',

'name' => 'active',

),

/*

'create_date',

'last_update',

*/

array(

'class'=>'CButtonColumn',

),

),

)); ?>

Sau k hi thành công vào Http://localhost/skybook/customer/admin

Bạn đã có thể thấy một loạt công cụ kích hoạt, CRUD hiện lên, customer thật dễ dàng đúng ko , đệt mợ tàu khựa.

http://www.seodrupal.vn | Learn Drupal Online

Page 111: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

CHƯƠNG 7 KẾ THỪA Yii

Trong chương này bạn sẽ khám phá:

Tạo component

Tạo controller action

Tạo reusable controller

Tạo một widget

Tạo CLI commands

Tạo filter

Tạo modules

Tạo một customer view renderer

Làm mở rộng distribution-ready

1. Tạo component

Nếu bạn có một vài đoạn code có thể tái sử dụng được nhưng bạn không biết cách thức,widget,behavior hãy sử dụng component. Component kế thừa từ CComponent hoặc CApplicationComponent.Sau đó một component có thể kích hoạt tới ứng dụng và cấu hình sử dụng trong protected/config/main.php.

Để ví dụ chúng ta định nghĩa: EImageManage ứng dụng thành phần sẽ dùng để resize ảnh sử dụng thư viện GD, kích hoạt nó tới ứng dụng và sử dụng nó.

Vào protected/components tạo EImageManage.php

<?php

class EImageManager extends CApplicationComponent

{

protected $image;http://www.seodrupal.vn | Learn Drupal Online

Page 112: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

protected $width;

protected $height;

protected $newWidth;

protected $newHeight;

public function resize($width = false, $height = false){

if($width!==false) $this->newWidth = $width;

if($height!==false) $this->newHeight = $height;

return $this;

}

public function load($filePath)

{

list($this->width, $this->height, $type) =

getimagesize($filePath);

switch ($type)

{

case IMAGETYPE_GIF:

$this->image = imagecreatefromgif($filePath);

break;

case IMAGETYPE_JPEG:

$this->image = imagecreatefromjpeg($filePath);

break;

case IMAGETYPE_PNG:

$this->image = imagecreatefrompng($filePath);

break;

default:

http://www.seodrupal.vn | Learn Drupal Online

Page 113: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

throw new CException('Unsupported image type ' . $type);

}

return $this;

}

public function save($filePath)

{

$ext = pathinfo($filePath, PATHINFO_EXTENSION);

$newImage = imagecreatetruecolor($this->newWidth,

$this->newHeight);

imagecopyresampled($newImage, $this->image, 0, 0, 0, 0,

$this->newWidth, $this->newHeight, $this->width,

$this->height);

switch($ext)

{

case 'jpg':

case 'jpeg':

imagejpeg($newImage, $filePath);

break;

case 'png':

imagepng($newImage, $filePath);

break;

case 'gif':

imagegif($newImage, $filePath);

break;

default:

http://www.seodrupal.vn | Learn Drupal Online

Page 114: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

throw new CException("Unsupported image type ", $ext);

}

imagedestroy($newImage);

if(!is_file($filePath))

throw new CException("Failed to write image.");

}

function __destruct()

{

imagedestroy($this->image);

}

}

Tiếp theo vào main.php trong protected/config để kích hoạt:

Tìm và thêm vào đoạn sau :

// application components

'components'=>array(

'image' => array(

'class' => 'EImageManager',

),

Tiếp theo chúng ta sẽ sử dụng đoạn component mới như sau:

Yii::app()->image

->load(Yii::getPathOfAlias('webroot').'/src.png')

->resize(100,100)

http://www.seodrupal.vn | Learn Drupal Online

Page 115: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

->save(Yii::getPathOfAlias('webroot').'/dst.png');

Tải application component đã tồn tại

Hầu hết thời gian chúng ta cần tạo ứng dụng thành phần của riêng ta, tuy nhiên việc tải code đã tồn tại giúp ta giảm thời gian lập trình và tiết kiệm công sức.

Ví dụ để hiện user role từ databse sử dụng Yii::app()->user->role có thể kế thừa từ CwebUser component giống như sau:

<?php

class WebUser extends CWebUser {

private $_model = null;

function getRole() {

if($user = $this->getModel()){

return $user->role;

}

else return 'guest';

}

private function getModel(){

if($this->_model === null){

if($this->id === null) return null;

$this->_model = User::model()->findByPk($this->id);

}

return $this->_model;

}

}

http://www.seodrupal.vn | Learn Drupal Online

Page 116: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Và trong main.php ta phải cấu hình lại như sau:

// application components

'components'=>array(

'user'=>array(

'class' => 'WebUser',

// other properties

),

2. Tạo controller action

Trước tiên bạn vào phpmyadmin chọn sql và thực hiện query sau:

CREATE TABLE `post` (

`id` int(11) NOT NULL auto_increment,

`text` text,

`title` varchar(255) default NULL,

PRIMARY KEY (`id`)

);

CREATE TABLE `comment` (

`id` int(11) NOT NULL auto_increment,

`text` text,

PRIMARY KEY (`id`)

);

Generated model với : post và comment trong Gii.

Vào protected/extensions/actions tạo EDeleteAction.phphttp://www.seodrupal.vn | Learn Drupal Online

Page 117: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php

class EDeleteAction extends CAction

{

public $modelName;

public $redirectTo = array('index');

/**

* Runs the action.

* This method is invoked by the controller owning this action.

*/

public function run($pk)

{

CActiveRecord::model($this->modelName)->deleteByPk($pk);

if(Yii::app()->getRequest()->getIsAjaxRequest())

{

Yii::app()->end(200, true);

}

else

{

$this->getController()->redirect($this->redirectTo);

}

}

}

Tiếp theo vào kích hoạt controller : protected/controllers/ tạo DeleteController.php:

<?php

http://www.seodrupal.vn | Learn Drupal Online

Page 118: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

class DeleteController extends CController

{

public function actions()

{

return array(

'deletePost' => array(

'class' => 'ext.actions.EDeleteAction',

'modelName' => 'Post',

'redirectTo' => array('indexPosts'),

),

'deleteComment' => array(

'class' => 'ext.actions.EDeleteAction',

'modelName' => 'Comment',

'redirectTo' => array('indexComments'),

),

);

}

public function actionIndexPosts()

{

echo "I'm index action for Posts.";

}

public function actionIndexComments()

{

echo "I'm index action for Comments.";

}

http://www.seodrupal.vn | Learn Drupal Online

Page 119: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

Bây giờ bạn có thể vào trình duyệt gõ: http://localhost/skybook/delete/deletePost/pk, http://localhost/skybook/delete/deleteComment/pk

3. Tạo reusable Controller

Trong Yii bạn có thể tái sử dụng controller , nếu bạn tạo nhiều ứng dụng với controller có thuộc tính giống nhau, di chuyển tất cả các lệnh code tới controller tái sử dụng sẽ tiết kiệm nhiều thời gian cho bạn.

Trong bài này,chúng ta sẽ tạo đơn giản api controller sẽ được thi hành với JSON,CRUD API cho một model, nó sẽ đưa input data từ POST hoặc GET và sẽ sử lý bằng JSON data tiếp theo là HTTP code

Vào Gii,tạo 1 model generated là Post

Tiếp theo vào protected/extensions/ tạo json_api tạo JsonApiController.php:

<?php

class JsonApiController extends CController

{

const RESPONSE_OK = 'OK';

const RESPONSE_NO_DATA = 'No data';

const RESPONSE_NOT_FOUND = 'Not found';

const RESPONSE_VALIDATION_ERRORS = 'Validation errors';

public $modelName;

public function init()

{

parent::init();

http://www.seodrupal.vn | Learn Drupal Online

Page 120: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

if(empty($this->modelName))

throw new CException("You should set modelName before

using JsonApiController.");

}

public function actionCreate()

{

if(empty($_POST))

$this->respond(400, self::RESPONSE_NO_DATA);

$model = new $this->modelName;

$model->setAttributes($_POST);

if($model->save())

$this->respond(200, self::RESPONSE_OK);

else

$this->respond(400, self::RESPONSE_VALIDATION_ERRORS,

$model->getErrors());

}

public function actionGet($pk)

{

$model = CActiveRecord::model

($this->modelName)->findByPk($pk);

if(!$model)

$this->respond(404, self::RESPONSE_NOT_FOUND);

$this->respond(200, self::RESPONSE_OK,

$model->getAttributes());

}

http://www.seodrupal.vn | Learn Drupal Online

Page 121: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public function actionUpdate($pk)

{

if(empty($_POST))

$this->respond(400, self::RESPONSE_NO_DATA);

$model = CActiveRecord::model

($this->modelName)->findByPk($pk);

if(!$model)

$this->respond(404, self::RESPONSE_NOT_FOUND);

$model->setAttributes($_POST);

if($model->save())

$this->respond(200, self::RESPONSE_OK);

else

$this->respond(400, self::RESPONSE_VALIDATION_ERRORS,

$model->getErrors());

}

public function actionDelete($pk)

{

if(CActiveRecord::model($this->modelName)->deleteByPk($pk))

{

$this->respond(200, self::RESPONSE_OK);

}

else {

$this->respond(404, self::RESPONSE_NOT_FOUND);

}

}

http://www.seodrupal.vn | Learn Drupal Online

Page 122: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

protected function respond($httpCode, $status, $data = array())

{

$response['status'] = $status;

$response['data'] = $data;

echo CJSON::encode($response);

Yii::app()->end($httpCode, true);

}

}

Tiếp theo bạn cần kết nối t ới ứng dụng với protected/conFig/main.php

Nó có thể hoàn thành việc thêm con troller,cấu hình tới controllerMap property của CwebApplication và tat hay thế cấu hình sau trong main.php

'controllerMap' => array(

'api' => array(

'class' => 'ext.json_api.JsonApiController',

'modelName' => 'Post',

),

),

Chúng ta cần kết nối tới controller và đặc biệt nó sẽ làm việc với post model.

Bạn sẽ cần form tới post data nhưng nếu bạn có một số dữ liệu tồn tại bạn có thể sử dụng phương thức nhận bằng cách http://localhost/skybook/api/get/pk/1

Ứng dụng trả về cho bạn như sau:

http://www.seodrupal.vn | Learn Drupal Online

Page 123: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{"status":"OK","data":{"id":"1","text":"post1",

"title":"post1","is_deleted":"0"}}

4. Tạo một widget

Một widget là một phần tái sử dụng của khung nhìn views nó không chỉ render một số dữ liệu mà còn đọc một số logic. Nó có thể là một sự kiện nhận dữ liệu từ models và sử dụng nó trong bản thân views.

Hãy tạo một widget và vẽ một chart biểu đồ nghệ thuật sử dụng google API.

Trong protected/extensions/ tạo folder chart, tạo EChartWidget.php:

<?php

class EChartWidget extends CWidget

{

public $title;

public $data=array();

public $labels=array();

public function run()

{

echo "<img

src=\"http://chart.apis.google.com/chart?chtt=".urlencode

($this->title)."&cht=pc&chs=300x150&chd=".

$this->encodeData($this->data)."&chl=".implode

('|', $this->labels)."\">";

}

http://www.seodrupal.vn | Learn Drupal Online

Page 124: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

protected function encodeData($data)

{

$maxValue=max($data);

$chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwx

yz0123456789';

$chartData="s:";

for($i=0;$i<count($data);$i++)

{

$currentValue=$data[$i];

if($currentValue>-1)

$chartData.=substr($chars,61*($currentValue/$maxValue),1);

else

$chartData.='_';

}

return $chartData."&chxt=y&chxl=0:|0|".$maxValue;

}

}

Tiếp theo vào protected/controllers/ tạo ChartController.php

<?php

class ChartController extends CController

{

public function actionIndex()

{

$value = rand(10, 90);

$this->widget('ext.chart.EChartWidget', array(

http://www.seodrupal.vn | Learn Drupal Online

Page 125: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'title' => 'Do you like it?',

'data' => array(

$value, 100-$value

),

'labels' => array(

'No',

'Yes',

),

));

}

}

Vào trình duyệt gõ : http://localhost/skybook/chart/index lưu ý nhà phải kết nối với internet mới truy nhập vào được google thì mới thấy cái biểu đồ này.

5. Tạo filters (bộ lọc)

Một filters là một class có thể chạy trước/sau một action đang thực hiện. Nó có thể sử dụng và thay đổi nội dung thực hiện hoặc thay đổi output, trong ví dụ này bạn sẽ thực thi một output đơn giản được filter với compress HTML output và xóa tất cả mọi định dạng.

Vào protected/extensions/ tạo compress_html folder, tạo ECompressHtmlFilter.php

http://www.seodrupal.vn | Learn Drupal Online

Page 126: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php

class ECompressHtmlFilter extends CFilter

{

protected function preFilter($filterChain)

{

ob_start();

return parent::preFilter($filterChain);

}

protected function postFilter($filterChain)

{

$out = ob_get_clean();

echo preg_replace("~>(\s+|\t+|\n+)<~", "><", $out);

parent::postFilter($filterChain);

}

}

Tiếp theo chúng ta cần kết nối tới ứng dụng, chúng ta vào protected/controllers/ SiteController và thêm filter:

public function filters()

{

return array(

array(

'ext.compress_html.ECompressHtmlFilter'

),

);

}

http://www.seodrupal.vn | Learn Drupal Online

Page 127: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Chạy ứng dụng và kiểm tra source code ta sẽ thấy như sau:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//

EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.

dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"

lang="en"><head><meta http-equiv="Content-Type" content="text/

html; charset=utf-8" /><meta name="language" content="en" /><!--

blueprint CSS framework -->

6. Tạo một modules

Nếu bạn muốn tạo một ứng dụng đầy đủ và muốn sử dụng nó với việc custom theo í bạn, hầu hết điều bạn muốn đó là việc bạn cần phải tạo một modules.

Trong bài này,chúng ta sẽ nhìn việc tạo modules wiki,chúng ta sẽ không focus user và quản lý phân quyền và để mọi người điều khiển mọi thứ.

Trước tiên vào php myadmin chọn SQL : tạo query sau : CREATE TABLE `wiki` (

`id` varchar(255) NOT NULL,

`text` text NOT NULL,

PRIMARY KEY (`id`)

)

Generated : wiki model với Gii

Generated : wiki module với Gii

Di chuyển protected/models/wiki.php tới protected/modules/wiki/models/wiki.php

Thêm wiki tới moduels section của protected/config/main.php

'modules'=>array(

http://www.seodrupal.vn | Learn Drupal Online

Page 128: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

// uncomment the following to enable the Gii tool

'gii'=>array(

'class'=>'system.gii.GiiModule',

'password'=>false,

),

'wiki'

),

Cách thực hiện: Đầu tiên hãy thêm wiki link tới CMarkdownParser. Tạo protected/modules/wiki/components/wikiMarkdownParser.php:

<?php

class WikiMarkdownParser extends CMarkdownParser

{

public function transform($text)

{

$text = preg_replace_callback('~\[\[(.*?)(?:\|(.*?))?\]\]~',

array($this, 'processWikiLinks'), $text);

return parent::transform($text);

}

protected function processWikiLinks($matches)

{

$page = $matches[1];

$title = isset($matches[2]) ? $matches[2] : $matches[1];

return CHtml::link(CHtml::encode($title), array(

'view', 'id' => $page,

http://www.seodrupal.vn | Learn Drupal Online

Page 129: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

));

}

}

Tiếp theo sử dụng getHtml method từ protected/modules/wiki/models/wiki.php

public function getHtml()

{

$parser = new WikiMarkdownParser();

return $parser->transform($this->text);

}

Chúng ta tạo customer protected/modules/wiki/controller/DefaultController. Chúng ta chỉ cần 2 action là views và edit.

Tạo protected/modules/wiki/controller/DefaultController.php

class DefaultController extends Controller

{

public function actionIndex()

{

$this->actionView('index');

}

public function actionView($id)

{

$model = Wiki::model()->findByPk($id);

if(!$model)

{

http://www.seodrupal.vn | Learn Drupal Online

Page 130: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$this->actionEdit($id);

Yii::app()->end();

}

$this->render('view', array(

'model' => $model,

));

}

public function actionEdit($id)

{

$model = Wiki::model()->findByPk($id);

if(!$model)

{

$model = new Wiki();

$model->id = $id;

}

if(!empty($_POST['Wiki']))

{

if(!empty($_POST['Wiki']['text']))

{

$model->text = $_POST['Wiki']['text'];

if($model->save())

$this->redirect(array('view', 'id' => $id));

}

else

{

http://www.seodrupal.vn | Learn Drupal Online

Page 131: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Wiki::model()->deleteByPk($id);

}

}

$this->render('edit', array(

'model' => $model

));

}

}

Tiếp theo tạo views : protected/modules/wiki/views/default/view.php

<h2>

<?php echo CHtml::encode($model->id)?>

[<?php echo CHtml::link('edit', array('edit', 'id' =>

$model->id))?>]

</h2>

<?php echo $model->html ?>

Tạo views edit: protected/modules/wiki/views/default/edit.php

<h2>Editing <?php echo CHtml::encode($model->id)?></h2>

<?php echo CHtml::beginForm()?>

<?php echo CHtml::activeTextArea($model, 'text',

array('cols' => 100, 'rows' => 20))?>

<br /><br />

<?php echo CHtml::submitButton('Done')?>

<?php echo CHtml::endForm()?>

http://www.seodrupal.vn | Learn Drupal Online

Page 132: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Xong xuôi vào http://localhost/skybook/wiki/index và localhost/skybook/wiki/edit

Tiếp theo vào main.php trong protected/config thay đổi :

'modules'=>array(

// uncomment the following to enable the Gii tool

'gii'=>array(

'class'=>'system.gii.GiiModule',

'password'=>false,

),

'wiki'=>array(

'class' => 'ext.wiki.WikiModule'

),

),

Mỗi modules được tạo chứa một main modules class giống wikimodule nơi chúng ta có thể định nghĩa cấu hình thuộc tính,định nghĩa import, thay đổi đường dẫn, kích hoạt controller, và nhiều hơn..

Mặc định mỗi moduels generated với Gii chạy index action của default controller:

public function actionIndex()

{

http://www.seodrupal.vn | Learn Drupal Online

Page 133: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

$this->actionView('index');

}

Trong wiki module indexaction tat hay đổi như sau:

$model = Wiki::model()->findByPk($id);

if(!$model)

{

$this->actionEdit($id);

Yii::app()->end();

}

$this->render('view', array(

'model' => $model,

));

Nếu modules này giữ một ID chúng ta sẽ hiển thị nó và sử dụng trong views.

Nếu không có trang nào giữ ID, chúng ta xử lý bởi action khác:

$model = Wiki::model()->findByPk($id);

if(!$model)

{

$model = new Wiki();

$model->id = $id;

}

if(!empty($_POST['Wiki']))

{

if(!empty($_POST['Wiki']['text']))

http://www.seodrupal.vn | Learn Drupal Online

Page 134: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

{

$model->text = $_POST['Wiki']['text'];

if($model->save())

$this->redirect(array('view', 'id' => $id));

}

else

{

Wiki::model()->deleteByPk($id);

}

}

$this->render('edit', array(

'model' => $model

));

NẾU KHÔNG CÓ modules nào sử dụng ID mới tạo,nếu có một models chúng ta edit nó,edit form data từ POST và kiểm tra nó rỗng hay không chúng ta delete models,nếu có ký tự chúng ta lưu lại.

6. Tạo một custom view renderer

Có nhiều PHP templates được yii nhận là native PHP và Prado templates. Nếu bạn muốn sử dụng nó trong Yii bạn có thể định nghĩa chúng.

Bây giờ chúng ta sẽ nhúng Smarty 3.0 vào Yii.

Bạn vào trang chủ : http://www.smarty.net/. Tải phiên bản mới nhất về.

Giải nén (extract here ) rồi vào folder đó copy folder libs của smarty tới protected/vendors/smarty .

Cách thực hiện như sau:

Vào protected/extensions/smarty tạo ESmartyViewRenderer.php:

http://www.seodrupal.vn | Learn Drupal Online

Page 135: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php

class ESmartyViewRenderer extends CApplicationComponent

implements IViewRenderer

{

public $fileExtension='.tpl';

public $filePermission=0755;

private $smarty;

function init()

{

Yii::import('application.vendors.smarty.*');

spl_autoload_unregister(array('YiiBase','autoload'));

require_once('Smarty.class.php');

spl_autoload_register(array('YiiBase','autoload'));

$this->smarty = new Smarty();

$this->smarty->template_dir = '';

$compileDir = Yii::app()->getRuntimePath

().'/smarty/compiled/';

if(!file_exists($compileDir)){

mkdir($compileDir, $this->filePermission, true);

}

$this->smarty->compile_dir = $compileDir;

$this->smarty->assign('Yii', Yii::app());

}

/**

* Render một file viws.

http://www.seodrupal.vn | Learn Drupal Online

Page 136: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

* Phương thức được yêu cầu từ {@link IViewRenderer}.

* @param CBaseController the controller or widget who is

rendering the view file.

* @param string the view file path

* @param mixed the data to be passed to the view

* @param boolean whether the rendering result should be

returned

* @return mixed the rendering result, or null if the rendering

result is not needed.

*/

public function renderFile($context,$sourceFile,$data,$return) {

// current controller properties will be accessible as

{this.property}

$data['this'] = $context;

if(!is_file($sourceFile) || ($file=realpath($sourceFile))=

==false)

throw new CException(Yii::t('ext','View file

"$sourceFile" does not exist.', array('{file}'=>$sourceFile)));

$this->smarty->assign($data);

if($return)

return $this->smarty->fetch($sourceFile);

else

$this->smarty->display($sourceFile);

}

http://www.seodrupal.vn | Learn Drupal Online

Page 137: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

Tiếp theo bạn cần kết nối views renderer với ứng dụng. Trong protected/config/main.php chúng ta cần tải viewRenderer component:

// application components

'components'=>array(

'viewRenderer'=>array(

'class'=>'ext.smarty.ESmartyViewRenderer',

),

),

Lưu ý, trong component có dữ liệu thì bạn để nguyên chỉ việc thêm vào :

'viewRenderer'=>array(

'class'=>'ext.smarty.ESmartyViewRenderer',

),

Bây giờ kiểm tra nó, Tạo protected/controllers/ Tạo SmartyController.php

<?php

class SmartyController extends Controller

{

function actionNative()

{

$this->render('native', array(

'username' => 'Alexander',

));

http://www.seodrupal.vn | Learn Drupal Online

Page 138: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

function actionSmarty()

{

$this->render('smarty', array(

'username' => 'Alexander',

));

}

}

Tiếp theo t ạo views: protected/views/smarty/native.php:

Hello, <?php echo $username?>!

protected/views/smarty/smarty.tpl:

Hello, {$username}!

Bây giờ vào trình duyệt gõ : http://localhost/skybook/smarty/native

Bạn sẽ thấy dòng : Hello,Alexander!

7. Làm extensions distribution-ready

Trong chương này bạn đã được học rất nhiều các tạo thuộc tính từ Yii extensions. Bây giờ chúng ta nói về cách chia sẻ thành quả của bạn với mọi người và tại sao nó lại quan trong.

Hãy check trong form sau những điều bạn suy nghĩ là đúng nhất về extensions

Nội dung trong sang, dễ đọc và sử dụng trong API

Tài liệu tốt

Mọi người đều có thể tìm thấy nó

Extensions áp dụng được hầu hết trong ứng dụng user

http://www.seodrupal.vn | Learn Drupal Online

Page 139: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Sẽ là thành phần chính

Tốt cho việc test code, tạo nền tảng cho ý tưởng với bài test

Bạn cần được cung cấp hỗ trợ cho nó

Tất nhiên tất cả yếu tố trên đều được yêu cầu thực sự cần thiết để tạo ra một sản phẩm tốt.

CHƯƠNG 8 BẢO MẬT

Bạn sẽ khám phá điều gì trong chương cuối này ?

Sử dụng controller filter

Sử dụng CHtml và CHtmlPurifier tới sự kiện XSS

Khám phá SQL injection

Khám phá CSRF

Sử dụng RBAC

1. Sử dụng controller filter

Trong nhiều trường hợp,chúng ta cần lọc ra dữ liệu hoặc thực hiện một số action cơ bản trong data,ví dụ với custom filter, chúng ta có thể lọc ra lượt truy cập bởi IP,sức mạnh của user với việc sử dụng HTTPS,hoặc redirect user từ một phần quan trọng trong cấu hình trang để sử dụng trong ứng dụng. Yii có xây dựng hai bộ lọc ,đầu tiên là CInlineFilter nó cho phép sử dụng controller method như một bộ lọc, và cái thứ hai là (là một thứ chúng

http://www.seodrupal.vn | Learn Drupal Online

Page 140: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

ta sẽ focus nó) CAccessControlFilter nó cho phép điều khiển truy cập tới dữ liệu của controller action.

Trong bài học này ta sẽ thực hiện những việc sau:

Giới hạn truy cập tới controller action với chỉ các user định danh

Giới hạn truy cập tới controller action từ IPs đặc biệt

Giới hạn truy cập tới người dùng đặc biệt

Giới hạn truy cập cho user của một trình duyệt đặc biệt, trong trường hợp chúng ta cũng có thể hiển thị custom messager

Trước tiên vào protected/controllers tạo AccessController.php

<?php

class AccessController extends CController

{

public function actionAuthOnly()

{

echo "Looks like you are authorized to run me.";

}

public function actionIp()

{

echo "Your IP is in our list. Lucky you!";

}

public function actionUser()

{

echo "You're the right man. Welcome!";

}

}

http://www.seodrupal.vn | Learn Drupal Online

Page 141: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Tiếp theo ta thêm bộ lọc sau:

public function filters()

{

return array(

'accessControl',

);

}

Tiếp theo ta thêm access Rules (quy tắc truy cập)

{

return array(

array(

'deny',

'expression' => 'strpos($_SERVER[\'HTTP_USER_AGENT\'],

\'MSIE\') !== FALSE',

'message' => "You're using the wrong browser, sorry.",

),

array(

'allow',

'actions' => array('authOnly'),

'users' => array('@'),

),

array(

'allow',

'actions' => array('ip'),

http://www.seodrupal.vn | Learn Drupal Online

Page 142: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'ips' => array('127.0.0.1'),

),

array(

'allow',

'actions' => array('user'),

'users' => array('admin'),

),

array('deny'),

);

}

http://localhost/skybook/access/authonly , thay autheronly bằng ip, user để test

Bây giờ chúng ta sẽ thử controller trên trình duyệt sử dụng cả 2 tài khoản admin và demo sẽ đều có kết quả sau

2. Sử dụng CHtml và CHtmlPurifier tới sự kiện XSS

XSS là viết tắt của cross-site scripting và là một loại lỗ hổng mà cho phép tríchmột kịch bản phía máy khách (thông thường, JavaScript) trong trang được xem bởi người dùng khác. Xem xét sức mạnh của kịch bản phía máy khách này có thể dẫn đến hậu quả rất nghiêm trọng như bỏ qua kiểm tra an ninh, nhận được một thông tin người dùng, hoặc rò rỉ dữ liệu.

Để test ta vào protected/controllers tạo XssController.php

http://www.seodrupal.vn | Learn Drupal Online

Page 143: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

<?php

class XssController extends CController

{

public function actionSimple()

{

echo 'Hello, '.$_GET['username'].'!';

}

}

Bây giờ vào trình duyệt gõ : http://localhost/skybook/xss/simple?username=Longt8x, tuy nhiên tài sản chính không xuất hiện lên output , ta gõ tiếp ; http://localhost/skybook/xss/simple?username=<script>alert(‘XSS’);</script>

Đương nhiên trong ví dụ này khách chỉ sử dụng một hàm alert thong số, nhưng trong form data của bạn chứa nhiều dữ liệu mật thì điều thất thoát là khó tránh, Yii đưa ra giải pháp sau:

class XssController extends CController

{

public function actionSimple()

{

echo 'Hello, '.CHtml::encode($_GET['username']).'!';

http://www.seodrupal.vn | Learn Drupal Online

Page 144: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

}

}

Đối với một link bạn chỉ cần sử dụng như sau:

echo CHtml::link(CHtml::encode($_GET['username']), array());

Tiếp theo sử dụng CHtmlPurifier giúp loại bỏ những thong tin thừa do phía máy khách tự nhập vào

public function actionHtml()

{

$this->beginWidget('CHtmlPurifier');

echo $_GET['html'];

$this->endWidget();

}

public function actionHtml()

{

$purifier=new CHtmlPurifier();

echo $purifier->purify($_GET['html']);

}

Ta vào trình duyệt gõ http://localhost/skybook/xss/html?html=Hello,<strong>username</strong>!<script>alert(‘XSS’);</script> sẽ có kết quả sau:

http://www.seodrupal.vn | Learn Drupal Online

Page 145: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

3. Sự kiện SQL injection

SQL injection là một loại injection code được sử dụng để làm tổn thương ở cấp cơ sở dữ liệu và cho phép thực hiện bất kỳ SQL cho phép người sử dụng độc hại để thực hiện hành động chẳng hạn như xóa dữ liệu hoặc nâng cao đặc quyền của họ.

Trước tiên vào phpmyadmin chọn sql và thêm query sau:

CREATE TABLE `user` (

`id` int(11) unsigned NOT NULL AUTO_INCREMENT,

`username` varchar(100) NOT NULL,

`password` varchar(32) NOT NULL,

PRIMARY KEY (`id`)

);

INSERT INTO `user`(`id`,`username`,`password`) VALUES ( '1','Alex'

,'202cb962ac59075b964b07152d234b70');

INSERT INTO `user`(`id`,`username`,`password`) VALUES ( '2','Qiang

','202cb962ac59075b964b07152d234b70');

Tiếp theo generated model : User sử dụng Gii

Vào protected/controllers/ tạo SqlController.php

<?php

class SqlController extends CController

{

http://www.seodrupal.vn | Learn Drupal Online

Page 146: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

public function actionSimple()

{

$userName = $_GET['username'];

$password = md5($_GET['password']);

$sql = "SELECT * FROM user WHERE username = '$userName'

AND password = '$password' LIMIT 1;";

$user = Yii::app()->db->createCommand($sql)->queryRow();

if($user)

{

echo "Success";

}

else

{

echo "Failure";

}

}

}

Vào trình duyệt gõ : http://localhost/skybook/sql/simple?username=test&password=test bạn sẽ thấy trình duyệt in : Failure.

Bây giờ thay http://localhost/skybook/sql/simple?username=%27+or+%271%27%3D%271%2

7%3B+--&password=whatever.

Sẽ thấy ‘ hoặc ‘1’ =’1’; --

Nó tương đương với query :

SELECT * FROM user WHERE username = '' or

http://www.seodrupal.vn | Learn Drupal Online

Page 147: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'1'='1'; --' AND password = '008c5926ca861023c1d2a36653fd88e2'

LIMIT 1;

Để fix vấn đề này bạn thêm vào controller action mới:

public function actionPrepared()

{

$userName = $_GET['username'];

$password = md5($_GET['password']);

$sql = "SELECT * FROM user WHERE username = :username

AND password = :password LIMIT 1;";

$command = Yii::app()->db->createCommand($sql);

$command->bindValue('username', $userName);

$command->bindValue('password', $password);

$user = $command->queryRow();

if($user)

{

echo "Success";

}

else

{

echo "Failure";

}

}

Bây giờ vào http://localhost/skybook/sql/preparedSẽ hiện ra chữ failure, như vậy thong tin đã được bảo toàn.

http://www.seodrupal.vn | Learn Drupal Online

Page 148: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

4. Sự kiện CSRF

CSRF hay XSRF viết tắt cross-site là một request giả ,một vài thủ thuật sử dụng độc hại của trình duyệt user để âm thầm thực hiện một yêu cầu HTTP đến với trang web khi người dùng đăng nhập. Một ví dụ về cuộc tấn công này là chèn một thẻ hình ảnh vô hình với src trỏ đếnhttp://example.com/site/logout. Thậm chí nếu các thẻ hình ảnh được chèn vào trong một trang web khác,ngay lập tức bạn sẽ được đăng nhập từ example.com. Hậu quả của CSRF có thể sẽ rất nghiêm trọng: phá hủy dữ liệu trang web, ngăn chặn tất cả các người sử dụng trang web đăng nhập vào, phơi bày tin dữ liệu, và hơn thế nữa…

Một số thực trạng của CSRF:

Như CSRF nên được thực hiện bởi người sử dụng trình duyệt của nạn nhân, kẻ tấn công có thể không thường thay đổi tiêu đề HTTP được gửi.

Yii include một token generation và token checking. Thêm nữa có thể tự động insert một token trong HTML form:

Vào protected/config/main.php thêm đoạn sau:

'components'=>array(

'request'=>array(

'enableCsrfValidation'=>true,

),

),

Sauk hi cấu hình ứng dụng bạn sử dụng C:Html::beginForm và CHtml::endForm khởi tạo của HTML form.

public function actionCreate()

{

echo CHtml::beginForm();

http://www.seodrupal.vn | Learn Drupal Online

Page 149: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

echo CHtml::submitButton();

echo CHtml::endForm();

}

Yii sẽ tự động thêm một token field ẩn sau:

<form action="/csrf/create" method="post">

<div style="display:none"><input type="hidden" value="e4d1021e79ac

269e8d6289043a7a8bc154d7115a" name="YII_CSRF_TOKEN" />

Nếu bạn lưu form html và thử submit,bạn sẽ nhận được một lời thong báo giống như sau:

Bảo mật mức cao:

Nếu ứng dụng của bạn yêu cầu độ bảo mật cao hơn nữa, bạn hãy vào protected/config/main.php

'components' => array(

...

'user'=>array(

// enable cookie-based authentication

'allowAutoLogin'=>false,

),

...

http://www.seodrupal.vn | Learn Drupal Online

Page 150: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

),

Sau đó cho session timeout hoạt động

'components' => array(

...

'session' => array(

'timeout' => 200,

),

...

),

Sử dụng thuộc tính GET và POST

HTTP khẳng định không sử dụng GET cho các hoạt động thay đổi dữ liệu hoặc trạng thái. Gắn bó với nguyên tắc này là một cách tốt. Nó không ngăn cản tất cả các loại CSRF, nhưng ít nhất sẽ làm cho một số mũi trích như <img src = trở lên vô nghĩa....

5 . Sử dụng RBAC

RBAC là phương pháp kiểm soát truy cập mạnh mẽ nhất có sẵn trong Yii. Nó được mô tả trong tài liệu hướng dẫn,nhưng kể từ khi nó là khá phức tạp và mạnh mẽ, nó không phải là dễ dàng như vậy để hiểu làm thế nào nó thực sựhoạt động mà không nhận được hood .Trong bài này, chúng ta sẽ làm rõ vai trò của hệ thống phân cấp từ tiêu chuẩn hướng dẫn, import nó, và giải thích những gì đang xảy ra trong nội bộ.

Vào protected/config/main.php sửa lại thong số giống như sau:

return array(

'components'=>array(

'authManager'=>array(

http://www.seodrupal.vn | Learn Drupal Online

Page 151: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

'class'=>'CDbAuthManager',

'connectionID'=>'db',

),

),

);

Thêm vào protected/components/UserIdentity.php đoạn sau:

$users=array(

// username => password

'demo'=>'demo',

'admin'=>'admin',

'readerA'=>'123',

'authorB'=>'123',

'editorC'=>'123',

'adminD'=>'123',

);

Tạo protected/controllers/RbacController.php

<?php

class RbacController extends CController

{

public function filters()

{

return array(

'accessControl',

http://www.seodrupal.vn | Learn Drupal Online

Page 152: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

);

}

public function accessRules()

{

return array(

array(

'allow',

'actions' => array('deletePost'),

'roles' => array('deletePost'),

),

array(

'allow',

'actions' => array('init', 'test'),

),

array('deny'),

);

}

public function actionInit()

{

$auth=Yii::app()->authManager;

$auth->createOperation('createPost','create a post');

$auth->createOperation('readPost','read a post');

$auth->createOperation('updatePost','update a post');

$auth->createOperation('deletePost','delete a post');

$bizRule='return Yii::app()->user->id==$params

http://www.seodrupal.vn | Learn Drupal Online

Page 153: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

["post"]->authID;';

$task=$auth->createTask('updateOwnPost','update a

post by author himself',$bizRule);

$task->addChild('updatePost');

$role=$auth->createRole('reader');

$role->addChild('readPost');

$role=$auth->createRole('author');

$role->addChild('reader');

$role->addChild('createPost');

$role->addChild('updateOwnPost');

$role=$auth->createRole('editor');

$role->addChild('reader');

$role->addChild('updatePost');

$role=$auth->createRole('admin');

$role->addChild('editor');

$role->addChild('author');

$role->addChild('deletePost');

$auth->assign('reader','readerA');

$auth->assign('author','authorB');

$auth->assign('editor','editorC');

$auth->assign('admin','adminD');

echo "Done.";

}

public function actionDeletePost()

{

http://www.seodrupal.vn | Learn Drupal Online

Page 154: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

echo "Post deleted.";

}

public function actionTest()

{

$post = new stdClass();

$post->authID = 'authorB';

echo "Current permissions:<br />";

echo "<ul>";

echo "<li>Create post: ".Yii::app()->user->checkAccess

('createPost')."</li>";

echo "<li>Read post: ".Yii::app()->user->checkAccess

('readPost')."</li>";

echo "<li>Update post: ".Yii::app()->user->checkAccess

('updatePost', array('post' => $post))."</li>";

echo "<li>Delete post: ".Yii::app()->user->checkAccess

('deletePost')."</li>";

echo "</ul>";

}

}

Bây giờ vào localhost/skybook/rbac/init để xem kết quả

http://www.seodrupal.vn | Learn Drupal Online

Page 155: Yii 1.1 Development Cookbook - Vietnamese

153

[YII 1.1 APP DEVELOPMENT COOKBOOK ] August 28, 2012

Đặt tên các nút RBAC Một hệ thống cấp bậc phức tạp trở nên khó hiểu mà không cần sử dụng một số loại đặt tên một hội nghị. Một quy ước giúp không làm cho chúng ta nhầm lẫn như sau: [Group_] [own_] entity_action Trường hợp riêng được sử dụng khi quy tắc xác định khả năng sửa đổi một phần tử chỉ khi người sử dụng hiện nay là chủ sở hữu của các yếu tố và nhóm chỉ là một không gian tên. Thực thể là một tên của thực thể, chúng tôi đang làm việc và hành động là hành động mà chúng tôi đang thực hiện. Ví dụ, nếu chúng ta cần phải tạo ra một quy tắc để xác định nếu người dùng có thể xóa một bài đăng blog, chúng tôi sẽ đặt tên nó như là blog_post_delete. Nếu quy tắc xác định nếu một người dùng có thể chỉnh sửa các blog của riêng bình luận, tên sẽ được blog_own_comment_edit. Một cách để giữ cho hệ thống phân cấp đơn giản và hiệu quả Theo những đề nghị khi có thể để tối đa hóa hiệu suất và giảm hệ thống phân cấp phức tạp: ff Tránh gắn nhiều vai trò một người dùng duy nhất. ff Không kết nối các nút cùng loại. Vì vậy, ví dụ, tránh kết nối một trong những nhiệm vụ một số khác. Để giữ cho hệ thống phân cấp còn đơn giản, chúng ta có thể tránh việc tạo ra và sử dụng các nút thêm trong một số trường hợp bằng cách thay thế chúng bằng các điều kiện bổ sung. Một ví dụ là các sửa đổi của Post. Chúng ta có thể tạo ra một nút blog_own_post_edit với bizRule như sau: return Yii::app()->user->id==$params["post"]->author_id;Ngoài ra, chúng ta có thể thêm cùng một logic thường xuyên lựa chọn bài như sau: $post = Post::model()->findByAttributes(array(

'id' => $id,

'author_id' => Yii::app()->user->id,

));

If(!$post)

throw new CHttpException(404);

Bằng cách sử dụng cách thứ hai, chúng ta sẽ tránh nhận được một nút hệ thống phân cấp RBAC do lưu kho.

http://www.seodrupal.vn | Learn Drupal Online