cake php framework

113
CAO ĐẲNG KỸ THUẬT CAO THẮNG Tìm hiểu cakephp Thái Thanh Phong Sưa tập by VanTaickc 3/22/2011

Upload: van-tai-vo

Post on 21-Jun-2015

250 views

Category:

Engineering


4 download

DESCRIPTION

chúc bạn thành công

TRANSCRIPT

Page 1: Cake php framework

CAO Đ NG KỸ THU T CAO TH NGẲ Ậ Ắ

Tìm hi u cakephpểThái Thanh Phong

Sưa tập by VanTaickc

3/22/2011

Page 2: Cake php framework

Tìm hi u cakephpể

T ng h p các bài vi t v CakePHP - Updated Daily b i Thái Thanh Phong ổ ợ ế ề ở

Tổng hợp các bài viết về CakePHP

1.Giới thiệuCakePHP là một Framework cho php . Mục đích của nó là cung cấp một framework cho người sử dụng php phát triển những ứng dụng web nhanh, mạnh mẽ ,linh họa .Và điều quan trọng là CakePHP là một OpenSource (miễn phí). Để sử dụng nó, yêu cầu người làm phải biết những kiến thức sau • Cơ bản về PHP và HTML, • Kiến trúc MVC • Lập trình hướng đối tượng

Các bài viết mà tôi viết dưới đây ghi nhận lại quá trình tìm hiểu về CakePHP của tôi. Qua đó tôi còn muốn chia sẽ kiến thức ấy với những ai đã và đang tìm hiểu Framework này . Mỗi bài viết dưới đây có những nét đặc trưng riêng của nó. Nếu bạn là người mới bắt đầu tìm hiểu về CakePHP thì phải đi xem kĩ từng bài viết , bởi các bài viết đều có mối quan hệ chặt chẽ với nhau.

2.Nội dung :

CakePHP cho người mới bắt đầu Cài đặt CakePHP Cấu trúc thư mục CakePHP Kiến trúc CakePHP

Một số qui ước CakePHP cần chú ý Cách đặt tên file, tên lớp Các qui ước về Model và CSDL Qui ước về Controller Qui ước về View Tổng kết : viết demo đơn giản với CakePHPs

Các kiểu truy vấn CSDL đơn giản với CakePHP Truy vấn có điều kiện Truy vấn theo cách bình thường bằng câu lệnh SQL

Phân trang dữ liệu với CakePHPData validation toàn tập với CakePHP

Cách làm việc với Data validation Cài đặt Cakephp và viết ứng dụng datavalidation Sử dụng 1 tập luật cho 1 field Sử dụng nhiều tập luật cho 1 field Sử dụng tập luật bằng regular expression Sử dụng chức năng callback function

Page 3: Cake php framework

Source các ví dụCách viết 1 helper cho CakePHPCách viết 1 component cho CakePHPSử dụng layout trong CakePHPCác sử dụng Session trong CakePHPViết ứng dụng đăng nhập với CakePHP

Ki n trúc MVC c a CakePHPế ủadmin Manual MVC

CakePHP hoạt động theo mô hình MVC. Mô hình này chia ứng dụng ra làm 3 phần chính: Model, View, ControllerCụ thể chức năng:1. Model: mô tả dữ liệu của ứng dụng. Trên model ta có thể thiết lập các ràng buộc dữ liệu, quan hệ giữa các bảng.2. View: đảm nhận việc hiển thị thông tin3. Controller: xử lý và điều hướng các yêu cầu của client

Mô hình MVC căn bảnMô hình này được diễn giải như  sau:- A click vào 1 liên kết có dạng http://abc.com/products/view/10, trình duyệt sẽ gởi yêu cầu tới server- Bộ phận điều vận Dispatcher (một thành phần của CakePHP) kiểm tra phần tử products/view/10 và gởi yêu cầu tới controller tương ứng (ở đây sẽ là controller products)- Controller có thể sẽ làm một vài thao tác luận lí cần thiết (ví dụ như kiểm tra xem A có đăng nhập hay chưa, có đăng nhập thì mới cho xem chi tiết sản phẩm – cái này tùy yêu cầu của hệ thống)- Controller đồng thời sử dụng Model tương ứng (một controller có thể không cần đến model hoặc có thể sử dụng 1 –> nhiều model khác nhau) để truy xuất dữ liệu. Dữ liệu ở đây có thể là các record trong table của 1 database, 1 phần tử LDAP (http://en.wikipedia.org/wiki/Ldap), RSS feeds hoặc files trên hệ thống.- Sau khi lấy được dữ liệu, Controller đẩy dữ liệu này ra View và tầng này có nhiệm vụ chuẩn bị đưa dữ liệu đầu ra. View có thể chuẩn bị dữ liệu ở dạng HTML, PDF, tài liệu XML hoặc một đối tượng JSON.- Công việc cuối cùng là hiển thị lên cho A thấy thông tin sản phẩm có id = 10 thông qua trình duyệtTại sao lại dùng mô hình MVC?

Page 4: Cake php framework

- Vì nó giúp chúng ta xây dựng ứng dụng nhanh chóng, dễ bảo trì, module hóa. MVC tách các tác vụ của ứng dụng thành các thành phần riêng lẻ, giúp ta dễ dàng thêm mới (hoặc thay đổi) các tính năng mà không làm ảnh hưởng đến các thành phần khác.CakePHP Framework: Cho người mới bắt đầuCakePHP là một Framework cho php . Mục đích của nó là cung cấp một framework cho người sử dụng php phát triển những ứng dụng web nhanh, mạnh mẽ ,linh họa .Và điều quan trọng là CakePHP là một OpenSource (miễn phí). Để sử dụng nó, yêu cầu người làm phải biết những kiến thức như: Cơ bản về PHP và HTML, Kiến trúc MVC,Lập trình hướng đối tượng. Một số tính năng của CakePHP :

• Nguồn mở, miễn phí, có cộng đồng sử dụng và hỗ trợ rộng lớn• Tương thích PHP4 và PHP5• Mô hình MVC• Đa ngôn ngữ• Sinh code tự động• Caching• Phân quyền (ACL)• Kiểm tra ràng buộc dữ liệu• Xây dựng nhiều thư viện hỗ trợ cho View như: Ajax, HTML Form, Javascript…• Xây dựng nhiều thư viện hỗ trợ cho Controller: Email, Security, Session, Cookies, Request Handling• Dễ dàng viết thêm thư viện hỗ trợ, liên kết với ứng dụng khác (thông qua vendors)• Đa giao diện• Hỗ trợ nhiều hệ quản trị CSDL Cài đặt Cake PHP

Trong bài viết hướng dẫn người dùng các cài đặt CakePHP,Ở đây tôi dùng CakePHP ver1.36 webserver XAMPP tích hợp Mysql và Apache.

Yêu cầu hệ thống : Hệ điều hành Windown hoặc Linux Hệ quản trị CSDL MySQL

Chuẩn bị cài đặt :Tải phiên bản CakePHP mới nhất (1.3.6 stable) từ địa chỉ:http://github.com/cakephp/cakephp/archives/1.3- Giải nén, cho vào thư mục của web server- Trong ví dụ này thư mục webser góc của tôi là :C://xampp/htdocs- Vậy ta có cấu trúc như sau :C://xampp/htdocs/cakephp

Page 5: Cake php framework

Cài đặt CakePHP thành công :- Chmod thư mụcapp/tmpthành0777(nếu trên host, còn localhost thì khỏi cần)- Mở file app/config/core.php- Thay đổi giá trị của dòng Configure::write(‘Security.salt', ‘DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi2010‘ );- Thay đổi giá trị của dòng Configure::write(‘Security.cipherSeed', ‘768593096574535424967496836452011‘);- Tạo csdl với tên:cake_test- Mở file app/config/database.php, điền như sau:view source print ? 1 var $default = array(

2 'driver' => 'mysql',

3 'persistent' => false,4 'host' => 'localhost',

5 'login' => 'root',

6 'password' => 'my_password',7 'database' => cakephp_test',

8 'prefix' => '',

Page 6: Cake php framework

9 );

Bạn cần thay đổi các mục in đậm cho phù hợp với cấu hình trên máy bạn. Cấu trúc thư mục CakePHP

Sau khi tải và giải nén CakePHP, bạn có thể thấy các files và thư mục sau :-app: là nơi chứa mã nguồn ứng dụng của bạn (phần này quang trọng)-cake: là nơi chứa mã nguồn của CakePHP. Bạn không nên chỉnh sửa các files trong thư mục này nếu bạn không hiểu rõ về chúng-vendors: chứa ứng dụng của bên thứ 3, phục vụ cho ứng dụng của bạn-plugins: chứa các thành phần mở rộng dùng cho ứng dụng

Ghi chú :Config Chứa file cấu hình hệ thốngControllers Chứa các controller và componentLocale Chứa file ngôn ngữ , phục vụ cho ứng dụng đa ngôn ngữMolels Chứa file Model và behavor, datasourcePlugins Chứa các gói mở rộngTmpThư mục tạm của ứng dụngVendors Chứa ứng dụng của bên thứ 3Views Chứa các file giao diệnWebroot Chứa tài liệu (hình ảnh,file..), file CSS , file javascript… Kiến trúc CakePHP

CakePHP hoạt động theo mô hình MVCMô hình này chia ứng dụng ra làm 3 phần chính:• Model

Page 7: Cake php framework

• View• ControllerTrong bài viết này giúp người đọc hiểu được cách hoạt động chung của CakePHP trên mô hình MCV, ở những phần sau sẽ đi vào chi tiết hơn về cách sử dụng của CakePHP.

Ví dụ về mô hình MVC căn bản :Ta có liên kếthttp://abc.com/product/view/10- User A click vào 1 liên kết có dạnghttp://abc.com/products/view/10thì :

Trình duyệt sẽ gởi yêu cầu tới server Bộ phận điều vậnDispatcher(một thành phần của CakePHP) kiểm tra phần

tửproducts/view/10và gởi yêu cầu tới controller tương - Tham số thứ 1 : ta có Controllerproduct- Tham số thứ 2 : ta có view là tên của 1 action của Controllerproduct sẽ được gọi để thực thi 1 hành động nào đó- Tham số thứ 3 : ta có 1 giá trị 10, thông thường tham số thứ 3 có thểm có hoặc không, tùy vào mục đích sử dụng, ở đây tôi có tham số = 10 để xem sản phẩm có id = 10

Mô tả bằng lời qua ví dụ trên : Vào địa chỉhttp://abc.com/để xem sản phẩm có id=10Tại sao lại dùng mô hình MVC?

Vì nó giúp chúng ta xây dựng ứng dụng nhanh chóng Dễ bảo trì, module hóa MVC tách các tác vụ của ứng dụng thành các thành phần riêng lẻ, giúp ta dễ dàng thêm

mới (hoặc thay đổi) các tính năng mà không làm ảnh hưởng đến các thành phần khác. CakePHP Framework: Một số quy ước cơ bảnỞ bài trước, chúng ta đã có dịp nói về cách cài đặt và tìm hiểu kiến trúc bên trong của CakePHP. Trong bài, chúng tôi tiếp tục hưỡng dẫn các bạn sử dụng và làm quen với các quy ước cơ bản trong CakePHP. Qua đó nắm bắt tổng quan đồng thời vận dụng CakePHP một cách linh hoạt nhất có thể.

Cách đặt tên file, tên lớp - Tên file sử dụng chữ thường, dùng dấu “_” để phân cách các từ

Page 8: Cake php framework

- Tên lớp dùng CamelCased (viết hoa chữ cái đầu tiên của từ)Ví dụ : ta có tên lớp là MyClass-> file class tương ứng :my_class.phpDưới đây là các ví dụ về cách đặt tên file cho mỗi dạng lớp khác nhau mà bạn thường sử dụng trong ứng dụng CakePHP :

Các qui ước về Model và CSDL- Tên các lớp model được đặt ở dạng số ít và việc viết hoa thường tuân theo CamelCasedVí dụ: Person, BigPerson và ReallyBigPerson.- CakePHP không hỗ trợ khóa chính gồm nhiều cột. Nếu bạn muốn thao tác trực tiếp kết nối (join) các bảng, hãy truy vấn trực tiếp hoặc thêm một khóa chính thay cho khóa nhiều cột.Ví dụ:view source print ?

1 CREATE TABLE posts_tags (

2 id INT(10) NOT NULL AUTO_INCREMENT,3 post_id INT(10) NOT NULL,

4 tag_id INT(10) NOT NULL,

5 PRIMARY KEY(id)); - Lẽ ra trong table post_tags, bình thường thì 2 cột post_id và tag_id ta có thể cho nó làm khóa chính nhưng CakePHP không chấp nhận điều này.- Tên bảng tương ứng với các model của CakePHP ở dạng số nhiều và sử dụng gạch dưới (_) tên bảng tương ứng với các model ở trên là people, big_people, và really_big_people.- Tuy nhiên, bạn vẫn có thể đặt tên bảng khác đi và cho CakePHP biết điều này thông qua biến $useTable trong model (các bài viết tiếp theo sẽ có ví dụ).- Bạn có thể dùng thư viện Inflector có sẵn trong CakePHP để kiểm tra dạng số ít/số nhiều của các từ.- Các khóa ngoại trong các quan hệ hasMany, belongsTo, hasOne có tên mặc định là số ít của tên bảng kèm theo _id ở cuối cùng.Ví dụ với quan hệ NewsCategory có nhiều News, bảng news sẽ có khóa ngoại đến bảng news_categories là news_category_id.- Các bảng liên kết được sử dụng trong quan hệ hasAnhBelongsToMany(viết tắt là HABTM – quan hệ nhiều nhiều) được đặt tên bằng cách kết nối các tên model theo thứ tự abc, vì vậy tên đúng sẽ là apples_zebras chứ không phải là zebras_apples.- Do đó, ta phải thêm một khóa khác có tên là id- Khóa chính mặc định trong CakePHP là cột id, kiểu int, tự tăng. Tuy nhiên, bạn cũng có thể định nghĩa lại khóa chính cho bảng thông qua biến $primaryKey trong model.

Page 9: Cake php framework

- Thay cho việc sử dụng kiểu int, auto-increment làm khóa chính, bạn có thể sự dụngchar(36)hoặc binary(36), khi đó CakePHP sẽ tự động tạo ra UUIDs để làm khóa khi ta thêm mới một record. UUID là một chuỗi gồm 32 byte, tương ứng với 36 ký tự.Ví dụ :550e8400-e29b-41d4-a716-446655440000 Qui ước về Controller :- Tên lớp của controller đặt theo dạng số nhiều,- Tuân theo CamelCased và cuối tên phải có chữ “Controller”.

Ví dụ: ta có Controller tênProductsthì có class Controller như sau :view sourceprint ?

1 <?php

2             Class ProductsController extends AppController{3             //Mã lệnh ở đây

4         }

5 ?>

- Khi một phương thức trong Controller được đặt tên bắt đầu với với dấu “_”ở phía trước, bạn sẽ không thể truy xuất nó từ bên ngoài mà chỉ có thể truy xuất trong controller đó (cái này gọi là private).Ví dụ:view sourceprint ?

01 <?php

02         Class ProductsControllers extends AppController{

03             function index(){

04                //Mã lệnh ở đây

05             }

06

07             function _get_product(){

08                 //Mã lệnh ở đây

09             }

10

11             function viewProduct(){

12                     $this->_get_product();

Page 10: Cake php framework

13             }

14         }

15 ?>

Kết quả hiển thị như sau: index() : public function_get_product() : private function Mô tả hoạt động :-http://localhost/products: function index() :run-http://localhost/products/_get_product: function _get_product() :not run-http://localhost/products/viewProduct: function _get_product() :run Ví dụ :Ta có controller NewsController với 2 function:- View_all()- View_detail()Thì ta phải có 2 file tương ứng :- View_all.ctp- View_detail.ctpĐặt trong thư mục app/view/news - Mặc định, nếu trong controller NewsController có methodview(), khi gọi actionviewtrên trình duyệt (http://localhost/news/view) thì Controller sẽ tìm file view.ctp trong app/views/news/view.ctp- Tuy nhiên, bạn có thể gọi một file view khác không phải là view.ctp bằng lệnhview sourceprint ?

1 <?php

2 $this->render('ten_view');

3 ><

Ví dụ về mặc định :view sourceprint ?

1 <?php

2 Class NewsController extends AppController{

3

4    function view(){5     …

Page 11: Cake php framework

6    }

7 }

8 ?>

-Truy cập :http://localhost/news/view->load file :view.ctptrong thư mục app/views/news/Ví dụ về load 1 file view khác :view sourceprint ?

1 <?php

2 Class NewsController extends AppController{

3

4     function view(){

5         ….

6       $this->render(“view_demo”);

7     }

8 }

9 ?>

- Truy cập :http://localhost/news/view-> load file :view_demo.ctp trong thư mụcapp/views/news/ Tổng kết : viết demo đơn giản với CakePHP

- Viết dứng dụng đơn giản với đường link :http://localhost/cakephp/relax/playgame/10- Từ link trên, ta cần có :- Model : trong ví dụ này không xử lý dữ liệu nên không cần viết- View : file view.ctp để hiển thị kết quả : Ban dang chon tro choi thu 12- Controller :Relax với action Playgame nhận tham số 12Cách thực hiện :- Vào thư mục app/controllers/ tạo relaxs_controller.php với nội dung :view sourceprint ?

01 <?php

02 class RelaxsController extends AppController {

03     

Page 12: Cake php framework

04     function index(){05     }

06     

07     function playgame($id=null){

08         $info = array(

09                         "title_page" => "CakePHP demo by qhonline.info",

10                         "id" => $id,

11                     );

12         $this->set("data",$info);

13     }

14 }

Ghi chú : Hàm $this->set(“data”,$info) gán mảng giá trị $info vào biến $data để hiển thị bên View tương ứng - Vào thư mục app/views/ tạo thư mục relaxs ứng với Controllers relaxs trên- Trong thư mục relaxs mới tạo , ta tạo file playgame.ctp với nội dung :view sourceprint ? 01 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">

02 <html>

03     <head>

04         <title>

05             <?php

06             echo $this->Html->charset();07             echo $data['title_page']; /* Tiêu đề của trang web */

08             ?>

09         </title>

10     </head>

11     <body>

12     <?php

13         echo "Ban dang choi tro choi thu ".$data['id'];

Page 13: Cake php framework

14     ?>

15     </body>

16 </html>

-Kiểm tra kết quả :http://localhost/relaxs/playgame/12

Title không hiển thị kết quả như mong muốn do CakePHP có 2 chế độ :- Dùng template có sẳn của nó- Template của mìnhTrong ví dụ này , mình dùng template mặc định nên phần title là do CakePHP quyết định

CakePHP Framework: Thao tác trên cơ sở dữ liệuỞ bài trước, chúng ta đã có dịp đề cập về thao tác cài đặt và tìm hiểu các quy tắc cơ bản trong CakePHP Framework. Trong bài này, chúng tôi tiếp tục hưỡng dẫn các bạn thao tác với mô hình cơ sở dữ liệu. Từ đó, chúng ta có thể tiến tới viết ứng dụng thực tế trên nền CakePHP Framework. Để dễ dàng cho việc tương tác với cơ sở dữ liệu (CSDL). Trước tiên chúng ta cần cấu hình theo đường dẫn app/config/database.php thông tin kết nối vào hệ thống. (Xem lại bài CakePHP Framework cho người mới bắt đầu).

Sau khi đã kết nối vào hệ thống, tiếp đến ta tiến hành thực hiện các câu truy vấn sau để tiến hành tạo bảng dữ liệu mẫu, để phục vụ cho những đoạn code test bên dưới.view sourceprint ?

01 CREATE TABLE books (

02   id int(11) NOT NULL AUTO_INCREMENT,

03   isbn  varchar(13) NOT NULL,

04   title  varchar(64) NOT NULL,

Page 14: Cake php framework

05   description  text NOT NULL,

06   PRIMARY KEY (id)

07 )

08  

09 INSERT INTO `books` VALUES ('1', 'abc', 'Kĩ thuật lập trình', 'abc');

10 INSERT INTO `books` VALUES ('2', 'c,c++', 'Lập trình C', 'lap trinh c');

11INSERT INTO `books` VALUES ('3', 'C++', 'Cấu trúc dữ liệu và giả thuật', 'abc');

12 INSERT INTO `books` VALUES ('4', 'php', 'PHP căn bản', 'php, lap trinh php');

13INSERT INTO `books` VALUES ('5', 'php nc', 'PHP Nâng cao', 'php,php nang cao');

14INSERT INTO `books` VALUES ('6', 'php fw', 'PHP Framework', 'php, php framework');

Tiếp tục, trong thư mục app/models ta tiếp tục tạo file tên .php với nội dung sau:view sourceprint ?

1 <?php

2 class Book extends AppModel{3     var $name = "Book"; // tên cua Model Book

4 }

Có thể hiểu ý nghĩa của những đoạn code trên như sau:- Tên file và class Model được đặt ở dạng số ít.- Tên Model đặt giống với tên table tương ứng nhưng ở dạng số ít.- VD tôi có table users . Tên file Model dùng cho table users là :§ user.phpTên class là : User§ - Như trong ví dụ này tôi có table books thì Tên file Model dùng cho table books là :§ book.phpTên class là : Book§ Kế tới trong thư mục app/controllers/ ta tạo file books_controller.php với nội dung sau:view sourceprint ?

1 <?php class BooksController extends appController{

2     var $name = "Books"; // tên của Controller Book

3

4 function exam01(){5         $data = $this->Book->find("all");

Page 15: Cake php framework

6         $this->set("data",$data);

7     }

8

9 }

- Hàm : $this->Book->find("all") Gọi Model Book , Model Book sẽ tự động lấy tất cả dữ liệu trong table books và trả về kết quả dạng mãng như sau:

- Hàm : $this->set("data",$data) gán giá trị vào biến $data để hiển thị tương ứngTrong thư mục app/view/tạo file thư mục books tương ứng với Controller BookstrênTrong thư mục books, tạo fileexam01.cpt:view sourceprint ? 01 <html>

02 <body>

03 <?php

04 if($data==NULL){

05     echo "<h2>Dada Empty</h2>";

06 }

07 else{

08     echo "<table>

Page 16: Cake php framework

09           <tr>

10             <td>id</td>

11             <td>Title</td>

12           </tr>";

13     foreach($data as $item){

14         echo "<tr>";

15         echo "<td>".$item['Book']['id']."</td>";

16        echo "<td><a href='books/view/".$item['Book']['id']."' >".$item['Book']['title']."</a></td>";

17         echo "</tr>";

18     }

19 }

20 ?>

21 </body>

22 </html>

Sau khi đã hoàn tất các công đoạn trên. Chạy thử kết quả theo đường dẫn sau ta sẽ có:http://localhost/cakephp/books/exam01\\\\Truy vấn có điều kiện :Thêm vào Controller Book với function exam02 :view sourceprint ?

01 <?php

02 class BooksController extends AppController{03     var $name = "Books"; // tên của Controller Book

04

05 function exam01(){

06         $data = $this->Book->find("all");07         $this->set("data",$data);

08     }

09

10 function exam02(){

Page 17: Cake php framework

11         $sql = array(

\12                         "conditions"=> array(

1ư3                                                "title LIKE"=> "PHP%",

14                                             ),

15 “limit” => “0,2”

16                     );

17

        $data = $this->Book->find("all",$sql);

18         $this->set("data",$data);

19     }

20

21 }

-Tham số“conditions”ơ đây ý nói điều kiện lọc . Ở đây tôi lọc “những title chuỗi bắt đầu là PHP và phía sau là gì cũng được”- Bạn có thể thêm điều kiệu lọc như “lấy tất cả ngoại trừ id có giá trị là 4”- Vậy Controller Books bây giờ là :view sourceprint ?

01 <?php

02 class BooksController extends AppController{03     var $name = "Books"; // tên của Controller Book

04

05 function exam01(){

06         $data = $this->Book->find("all");07         $this->set("data",$data);

08     }

09

10 function exam02(){

11         $sql = array(

12                         "conditions"=> array(

13                                                 "title LIKE"=> "PHP%",

Page 18: Cake php framework

14 “id !=” => 4,

15                                             ),

16 “limit” => “0,2”

17                     );        $data = $this->Book->find("all",$sql);

18         $this->set("data",$data);

19     }

20

21 }

Trong app/views/booksTạo file exam02.ctp:view sourceprint ? 01 <html>

02 <body>

03 <?php

04 if($data==NULL){

05     echo "<h2>Dada Empty</h2>";

06 }

07 else{

08     echo "<table>

09           <tr>

10             <td>id</td>

11             <td>Title</td>

12           </tr>";

13     foreach($data as $item){

14         echo "<tr>";

15         echo "<td>".$item['Book']['id']."</td>";

16         echo "<td>".$item['Book']['title']."</td>";17         echo "</tr>";

18     }

19 }

Page 19: Cake php framework

20 ?>

21 </body>

22 </html>

Chạy kiểm tra thử :http://localhost/cakephp/books/exam02

Truy vấn theo cách bình thường:- Bình thường ở đây là ta viết 1 câu truy vấn hoàn chỉnh và thực thi nó, không dùng các hàmHổ trợ sẵn của CakePHP , bởi đôi lúc ta cần thực thi những câu truy vấn dài và phức tạp mà lại không nhớ cách viết của CakePHP thì dùng phương pháp này

Thêm vào Controller Book function exam03 :view sourceprint ?

1 <?php

2 function exam03(){

3         $sql = "Select * From books";

4         $data = $this->Book->query($sql);5         $this->set("data",$data);

6     }

Trong app/views/books/tạo file exam03.ctp:view sourceprint ? 01 <html>

02 <body>

03 <?php

04 if($data==NULL){

05     echo "<h2>Dada Empty</h2>";

06 }

Page 20: Cake php framework

07 else{

08     echo "<table>

09           <tr>

10             <td>id</td>

11             <td>Title</td>

12           </tr>";

13     foreach($data as $item){

14         echo "<tr>";

15         echo "<td>".$item['books']['id']."</td>";

16         echo "<td>".$item['books']['title']."</td>";17         echo "</tr>";

18     }

19 }

20 ?>

21 </body>

22 </html>

Chạy kiểm tra thử :http://localhost/cakephp/books/exam03

Vậy qua bài này ta cần lưu ý các điểm sau :

Page 21: Cake php framework

- Tên table đặt dạng số nhiều , Model tương ứng cùng tên và ở dạng số ít . Vd : table users -> Moldel User- Các hàm truy vấn CSDL :+ $this->Book->find("all");+ $this->Book->find("all",dieu_kien);+ $this->Book->query(cau_truy_van_sql);+ $this->Book->getNumRows();

CakePHP FrameworkCakePHP Framework: Tìm hiểu kỹ thuật phân trang

Qua loạt bài trước về CakePHP Framework, hẳn lúc này các bạn đã có góc nhìn tương đối về nguyên tắc làm việc của CakePHP. Nhất là chúng ta đã tìm hiểu về cách thức hoạt động đối với cơ sở dữ liệu trong CakePHP. Ở bài này, chúng ta tiếp tục tìm hiểu về kỹ thuật phân trang của CakePHP để hoàn thiện ứng dụng một cách đầy đủ hơn. Để dễ dàng cho việc tương tác với cơ sở dữ liệu (CSDL). Trước tiên chúng ta cần

cấu hình theo đường dẫn app/config/database.php thông tin kết nối vào hệ thống. (Xem lại bài CakePHP Framework cho người mới bắt đầu). Sau khi đã kết nối vào hệ thống, tiếp đến ta tiến hành thực hiện các câu truy vấn sau để tiến hành tạo bảng dữ liệu mẫu, để phục vụ cho những đoạn code test bên dưới.view sourceprint ?

01 CREATE TABLE `books` (

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

03   `isbn` varchar(13) NOT NULL,

04   `title` varchar(64) NOT NULL,05   `description` text NOT NULL,

06   PRIMARY KEY (`id`)

07 )

08

09INSERT INTO `books` VALUES ('1', 'abcxyz', 'Kĩ thuật lập trình', 'Kĩ thuật lập trình');

10INSERT INTO `books` VALUES ('2', 'c,c++', 'Lập trình C', 'Lap trinh C can ban');

11INSERT INTO `books` VALUES ('3', 'C++', 'Cấu trúc dữ liệu và giả thuật', 'Cau truc du lieu va giai thuat');

12 INSERT INTO `books` VALUES ('4', 'php', 'PHP căn bản', 'php, lap trinh php');13 INSERT INTO `books` VALUES ('5', 'php nc', 'PHP Nâng cao', 'php,php nang

Page 22: Cake php framework

cao');

14INSERT INTO `books` VALUES ('6', 'php fw', 'PHP Framework', 'php, php framework');

15INSERT INTO `books` VALUES ('22', 'abc', 'Lập trình ứng dụng web tập I', 'Lập trình ứng dụng web tập I');

16INSERT INTO `books` VALUES ('24', 'abc', 'Lập trình ứng dụng web tập II', 'abc');

17 INSERT INTO `books` VALUES ('26', 'abc', 'Lập trình web với CakePHP', 'abc');

18INSERT INTO `books` VALUES ('27', 'acb', 'Lập trình web với CodeIgniter', 'abc');

19INSERT INTO `books` VALUES ('28', 'abc', 'Tutorial covered by Thái Thanh Phong ^0^', 'abc');

Tiếp tục, ta tạo Controller Books (app/controllers/books/books_controller.php)view sourceprint ?

01 <?php

02 class BooksController extends AppController{03     var $name = "Books";// ten cua Controller Book

04     var $helpers = array('Paginator','Html');

05     var $components = array('Session');

06     var $paginate = array();

07     

08     //------- Paging Normal

09     function paging(){

10         $this->paginate = array(

11                                 'limit' => 4,

12                                 'order' => array('title' => 'desc'),

13                              );

14         $data = $this->paginate("Book");15         $this->set("data",$data);

16     }

- Để sử dụng chức năng phân trang của cakePHP thì trong Controller cần có thành phần helper Paginator :view sourceprint ? 1 var $helpers = array('Paginator','Html');

Page 23: Cake php framework

và namespace paginate :view sourceprint ? 1 var $paginate = array();- Ở đây tôi lấy tất dữ liệu bắt đầu với 4 record đầu tiên vào theo thứ tự giảm dần theo “title”.view sourceprint ?

1 $this->paginate = array(

2                                 'limit' => 4,3                                 'order' => array('title' => 'desc'),

4                              );

- Nếu chỉ lấy những 1 số field cần thiết :view sourceprint ?

1 $this->paginate = array(

2 ‘field’ =>array(“title”,”info”),

3                                 'limit' => 4,

4                                 'order' => array('title' => 'desc'),5                              );

- Để lấy dữ liệu theo cấu hình của biến namespace paginate ta dùng hàm $this->paginate(‘ten_model'), trong ví dụ này model của tôi có tên là Book.view sourceprint ? 1 $data = $this->paginate("Book");- Việc cấu hình biến namspace paginate dùng hàm $this->paginate(‘ten_model')Giống như việc cấu hình điều kiện truy xuất dữ liệu và lấy dữ liệu bằng hàm$this->find(‘…');.(Xem lại hàm truy vấn CSDL)- Chúng ta chỉ cần cấu hình như vậy là có thể phân trang cho CSDL , mặc định cakePHP dùng biến page để xác định trang hiện tại.Tiếp tục, ta tạo model Book (app/models/book.php)view sourceprint ?

1 <?php

2 class Book extends AppModel{3     var $name = "Book"; // Ten cua Model Book

4 }

Sau đó, ta tạo tiếp view(phần hiển thị) cho việc phân trang (app/views/books/paging.ctp)

Page 24: Cake php framework

view sourceprint ? 01 <html>

02 <body>

03 <?php

04    echo $this->Paginator->prev('« Previous ', null, null, array('class' => 'disabled')); //Shows the next and previous links

05     echo " | ".$this->Paginator->numbers()." | "; //Shows the page numbers

06    echo $this->Paginator->next(' Next »', null, null, array('class' => 'disabled')); //Shows the next and previous links

07    echo " Page ".$this->Paginator->counter(); // prints X of Y, where X is current page and Y is number of pages

08 ?>

09

10 <?php

11 if($data==NULL){

12     echo "<h2>Dada Empty</h2>";

13 }

14 else{

15     echo "<table>

16           <tr>

17             <td>id</td>

18             <td>Title</td>

19           </tr>";

20     foreach($data as $item){

21         echo "<tr>";

22         echo "<td>".$item['Book']['id']."</td>";

23        echo "<td><a href='".$this->webroot."books/view/".$item['Book']['id']."' >".$item['Book']['title']."</a></td>";

24         echo "</tr>";

25     }

26 }

Page 25: Cake php framework

27 ?>

28 </body>

29 </html>

Cuối cùng, ta chạy với đường dẫn sau để xem kết quả:http://localhost/cakephp/books/paging

Phân trang d li u v i CakePHP ữ ệ ớ

Phân trang dữ liệu với CakePHP

- Người biên soạn : Thái Thanh Phong- YID : thaiphong260189- Email : [email protected] Cũng như bao framework khác như Zend, CodeIgniter … CakePHP cũng hỗ trợ các phương thức phân trang cho dữ liệu.1.Chuẩn bị CSDL :Mã:CREATE TABLE `books` ( `id` int(11) NOT NULL AUTO_INCREMENT, `isbn` varchar(13) NOT NULL, `title` varchar(64) NOT NULL, `description` text NOT NULL, PRIMARY KEY (`id`))

INSERT INTO `books` VALUES ('1', 'abcxyz', 'Kĩ thuật lập trình', 'Kĩ thuật lập trình');INSERT INTO `books` VALUES ('2', 'c,c++', 'Lập trình C', 'Lap trinh C can ban');INSERT INTO `books` VALUES ('3', 'C++', 'Cấu trúc dữ liệu và giả thuật', 'Cau truc du lieu va giai thuat');INSERT INTO `books` VALUES ('4', 'php', 'PHP căn bản', 'php, lap trinh php');INSERT INTO `books` VALUES ('5', 'php nc', 'PHP Nâng cao', 'php,php nang cao');INSERT INTO `books` VALUES ('6', 'php fw', 'PHP Framework', 'php, php framework');

Page 26: Cake php framework

INSERT INTO `books` VALUES ('22', 'abc', 'Lập trình ứng dụng web tập I', 'Lập trình ứng dụng web tập I');INSERT INTO `books` VALUES ('24', 'abc', 'Lập trình ứng dụng web tập II', 'abc');INSERT INTO `books` VALUES ('26', 'abc', 'Lập trình web với CakePHP', 'abc');INSERT INTO `books` VALUES ('27', 'acb', 'Lập trình web với CodeIgniter', 'abc');INSERT INTO `books` VALUES ('28', 'abc', 'Tutorial covered by Thái Thanh Phong ^0^', 'abc');Tạo Controller Books (app/controllers/books/books_controller.php):PHP Code:<?phpclass BooksController extends  AppController{    var $name = "Books";// ten cua Controller Book    var $helpers = array('Paginator','Html');    var $components = array('Session');    var $paginate = array();        //------- Paging Normal     function paging(){        $this->paginate = array(                                'limit' => 4,                                'order' => array('title' => 'desc'),                             );        $data = $this->paginate("Book");        $this->set("data",$data);    }

Ghi chú : - Để sử dụng chức năng phân trang của cakePHP thì trong Controller cần có thành phần helper Paginator : PHP Code:var $helpers = array('Paginator','Html'); 

và namespace paginate : PHP Code:var $paginate = array(); 

- Ở đây tôi lấy tất dữ liệu bắt đầu với 4 record đầu tiên vào theo thứ tự giảm dần theo “title” PHP Code:$this->paginate = array(                                'limit' => 4,                                'order' => array('title' => 'desc'),                             ); 

- Nếu chỉ lấy những 1 số field cần thiết :PHP Code:$this->paginate = array(‘field’ =>array(“title”,”info”),                                'limit' => 4,                                'order' => array('title' => 'desc'),                             ); 

Page 27: Cake php framework

- Để lấy dữ liệu theo cấu hình của biến namespace paginate ta dùng hàm $this->paginate(‘ten_model’) , trong ví dụ này model của tôi có tên là BookPHP Code:$data = $this->paginate("Book"); 

- Việc cấu hình biến namspace paginate dùng hàm $this->paginate(‘ten_model’)Giống như việc cấu hình điều kiện truy xuất dữ liệu và lấy dữ liệu bằng hàm $this->find(‘…’); . Xem lại hàm truy vấn CSDL - Chúng ta chỉ cần cấu hình như vậy là có thể phân trang cho CSDL , mặc định cakePHP dùng biến page để xác định trang hiện tại

Việc cấu hình có vẻ đơn giản hơn nhiều so với CodeIgniter phải không !

Tạo Model Book (app/models/book.php) :PHP Code:<?phpclass Book extends AppModel{    var $name = "Book"; // Ten cua Model Book}

Tạo view cho function Paging của Controller Books (app/views/books/paging.ctp):PHP Code:<html><body><?php    echo $this->Paginator->prev('« Previous ', null, null, array('class' => 'disabled')); //Shows the next and previous links    echo " | ".$this->Paginator->numbers()." | "; //Shows the page numbers    echo $this->Paginator->next(' Next »', null, null, array('class' => 'disabled')); //Shows the next and previous links    echo " Page ".$this->Paginator->counter(); // prints X of Y, where X is current page and Y is number of pages?> 

<?phpif($data==NULL){    echo "<h2>Dada Empty</h2>";}else{    echo "<table>          <tr>            <td>id</td>            <td>Title</td>          </tr>";    foreach($data as $item){        echo "<tr>";        echo "<td>".$item['Book']['id']."</td>";        echo "<td><a href='".$this->webroot."books/view/".$item['Book']

Page 28: Cake php framework

['id']."' >".$item['Book']['title']."</a></td>";        echo "</tr>";    } }?></body></html>

Chạy thử : http://localhost/cakephp/books/paging

Data validation toàn t p v i CakePHP ậ ớ

Data validation toàn tập với CakePHP- Người biên soạn : Thái Thanh Phong- YID : thaiphong260189- Email : [email protected]

Data Validation là một trong những thành phần không thể thiếu trong hầu hết các ứng dụng web. Nó giúp cho các dữ liệu được đảm bảo được kiểm tra chặt chẽ trước khi chèn vào CSDL.

Cũng như CodeIgniter, Zend ,CakePHP cũng có chức năng Data Validation .Bài viết sẽ hướng dẫn cho người dùng cách sử dụng tập luật và ứng dụng chúng trong các trường hợp cụ thể khác nhau với các

Page 29: Cake php framework

hàm hổ trợ sẵn của CakePHP.

1.Cách làm việc của Datavalidation : Để sử dụng Datavalidation thì trong ứng dụng của chúng ta cần có hai thành phần chính : Thành phần form helper : sử dụng cho việc tạo formPHP Code:var $helpers = array ('Html','Form'); 

Thành phần namespace validate : sử dụng các tập luật để validation dữ liệuPHP Code:var $validate = array(tập_luật); 

Cụ thể trong ứng dụng này tôi có mô hình như sau :Controller : Valids , với các function : demo01 : sử dụng 1 tập luật cho 1 field demo02 : sử dụng nhiều tập luật cho 1 field demo03 : sử dụng tập luật bằng regular expression demo04 : sử dụng chức năng callback function giống như các Framework khác như CodeIgniter,Zend…. demo05 : ví dụ tổng hợp từ các demo được liệt kê trênModel : Valid , với các hàm cho từng function trong Controller tương ứng valid_01 : sử dụng cho hàm demo01 trong Controller Valids ……….. valid_05 : sử dụng cho hàm demo05 trong Controller ValidsView : demo01.ctp : file hiển thị form của hàm trong controller tương ứng (demo01) ……… Demo05.ctp : file hiển thị form của hàm trong controller tương ứng (demo05)

2.Cài đặt Cakephp và viết ứng dụng datavalidation :2.1.Cài đặt CakePHP : xem cách cài đặt cakePHP

Các thư mục cần chuẩn bị :- app/controllers/valids_controller.php- app/model/valid.php- app/views/valids/Chuẩn bị cho Controller Valids : (app/controllers/valids_controller.php)PHP Code:<?phpclass ValidsController extends AppController{    var $name = "Valids";    var $helpers = array ('Html','Form');    var $components = array('Session'); // Use Flash messenger of Session comp

Page 30: Cake php framework

onent?>

Chuẩn bị cho Controller Valids : (app/models/valid.php)PHP Code:<?phpclass valid extends  AppModel{      var $useTable = false; // không sử dụng table valid đồng nghĩa là không sử dụng database    var $validate = array(); // namespace mặc định khi sử dụng datavalidation?>

Trong ví dụ này các ứng dụng không chèn dữ liệu vào database mà chỉ thông báo có hợp lệ hay không và báo lỗi tương ứng . Nên trong Model tôi dùng namespace là PHP Code:var $useTable = false; 

để ám chỉ là không sử dụng bảng CSDL

Sử dụng 1 tập luật cho 1 field

- Yêu cầu tạo 1 form nhập liệu với 2 field với các tập luật được mô tả :- title : không được phép rỗng- info : không được phép rỗngTrong Controller Valid ta thêm hàm demo01 :PHP Code:<?phpclass ValidsController extends AppController{    var $name = "Valids";    var $helpers = array ('Html','Form');    var $components = array('Session'); // Use Flash messenger of Session component // ---- Valid one rule    function demo01(){                $this->Valid->set($this->data);                if($this->Valid->valid_01()==TRUE){                    $this->Session->setFlash("Data is avaliable !");                }else{                    $this->Session->setFlash("Data is not avaliable !");                }     }?>

Ghi chú : Chức năng validation sẽ được kích hoạt khi ta dùng hàm PHP Code:$this->Valid->set($this->data); 

Sau đó Model Valid gọi hàm valid_01() để sử dụng tập luật cho các field tương ứng (title,info)

Page 31: Cake php framework

Trong thư mục app/views/valids/ tạo file demo01.ctp :PHP Code:<h1>Add Post</h1><?phpecho $this->Form->create('Valid', array('action' => 'demo01'));echo $this->Form->input('title');echo $this->Form->input('info');echo $this->Form->end('Register');?>

Trong model Valid thêm hàm valid_01() :PHP Code:<?phpclass valid extends  AppModel{      var $useTable = false;    var $validate = array();            //------- Valid 01 :  one rule    function valid_01(){        $this->validate = array(                                    "title" => array(                                                            "rule" => "notEmpty",                                                            "message" => "Please enter title !",                                                        ),                                    "info" => array(                                                            "rule" => "notEmpty", // tập luật là không rỗng                                                            "message" => "Please enter info !", // thông báo khi có lỗi                                                        )                                );        if($this->validates($this->validate)) // nếu dữ liệu đã được validate (hợp lệ)        return TRUE;        else         return FALSE;    }?>

Ghi chú : Để validate dữ liệu ta dùng namespace validate ($this->validate) để gán tập luật cho các field Với rule là từ khóa để chỉ đó là tập luật và notEmpty là từ khóa để nói là không được rỗngTrong 1 số tài liệu người ta có thể dùng từ khóa VALID_NOT_EMPTY để thay cho từ khóa notEmpty message là từ khóa để chỉ thông báo lỗi PHP Code:$this->validates($this->validate) //hàm kiểm tra các tập luật 

Các từ được koi là từ khóa thì phải viết đúng tên và giữ nguyên nội dung của từ.

Page 32: Cake php framework

Chạy thử ứng dụng đầu tiên : http://localhost/cakephp/valids/demo01

Mã: Một số tập luật thông dụng : 'rule' => 'alphaNumeric' : chỉ có số hoặc chữ 'rule' => array('between', 5, 15) : giá trị nằm trong khoản từ 5-15 'rule' => array('comparison', '>=', 18) : giá trị phải lớn hơn 18 'rule' => array('email', true) : định dạng email 'rule' => array('extension', array('gif', 'jpeg', 'png', 'jpg')) : dành cho upload file , kiểm tra extension 'rule' => array('minLength', 8) : độ dài nhỏ nhất là 8 'rule' => array('maxLength', 8) : độ dài tối đa là 8 'rule' => 'numeric' : dữ liệu nhập là số 'rule' => 'notEmpty' : dữ liệu không được bỏ trống 'rule' => 'url' : định dạng địa chỉ url

- Yêu cầu tạo 1 form nhập liệu với 3 field với các tập luật được mô tả :- username : không được phép rỗng Tối đa là 10 kí tự Ít nhất là 4 kí tự

- email : không được phép rỗng định dạng là email

Page 33: Cake php framework

- website không được phép rỗng định dạng là địa chỉ url

Trong Controller Valid ta thêm hàm demo02 : PHP Code:<?php class ValidsController extends AppController{     var $name = "Valids";     var $helpers = array ('Html','Form');     var $components = array('Session'); // Use Flash messenger of Session component   // ---- Valid multi rules     function demo02(){                 $this->Valid->set($this->data);                 if($this->Valid->valid_02()==TRUE){                     $this->Session->setFlash("Data is avaliable !");                 }else{                     $this->Session->setFlash("Data is not avaliable !");                 }      } ?>

Trong thư mục app/views/valids/ tạo file demo02.ctp : PHP Code:<h1>Add Post</h1> <?php echo $this->Form->create('Valid', array('action' => 'demo02')); echo $this->Form->input('username'); echo $this->Form->input('email'); echo $this->Form->input('website'); echo $this->Form->end('Register'); ?>

Trong model Valid thêm hàm valid_02() :PHP Code:<?php class valid extends  AppModel{       var $useTable = false;     var $validate = array();     //-------- Valid : Multi rule     function valid_02(){         $this->validate = array(                                 "username"=>array(                                                     "rule1" => array(                                                                     "rule" => "notEmpty",                                                                     "message" => "Username can not empty",                                                                     ),                                                     "rule2" => array(                                                                     "rule" => array('minLength', 4),                                                                     "message" 

Page 34: Cake php framework

=> "Usernames must be at least 4 characters long",                                                                     ),                                                     "rule3" => array(                                                                     "rule" => array('maxLength', 10),                                                                     "message" => "Usernames must be no larger than 10 characters long",                                                                     ),                                                 ),                                 "email" => array(                                                     "rule1" => array(                                                                         "rule" => "notEmpty",                                                                         "message" => "Please enter email !",                                                                     ),                                                     "rule2" => array(                                                                         "rule" => "email",                                                                         "message" => "Email not avaliable !",                                                                     ),                                                 ),                                 "website" => array(                                                     "rule1" => array(                                                                         "rule" => "notEmpty",                                                                         "message" => "Please enter website !",                                                                     ),                                                     "rule2" => array(                                                                         "rule" => "url",                                                                         "message" => "website is not avaliable",                                                                     ),                                                 ),                             );                                     if($this->validates($this->validate))          return TRUE;         else          return FALSE;       } ?>

Page 35: Cake php framework

Chạy thử ứng dụng : http://localhost/cakephp/valids/demo02

Data validation toàn t p v i CakePHP ậ ớ

Source các ví dụ trên

Dưới đây là source code gồm 3 phần chính :- app/controllers/valids_controller.php- app/models/valid.php- app/views/valids/....

Download : Data_Validation.rar

Page 36: Cake php framework

Cách vi t 1 Hepler cho CakePHP ế

Cách viết 1 Hepler cho CakePHP

- Người biên soạn : Thái Thanh Phong- YID : thaiphong260189- Email : [email protected] Ghi chú : Bài viết được tổng hợp từ nhiều nguồn khác nhau Giả sử, bạn có hàm tạo chuỗi ngẫu nhiên, bạn muốn dùng hàm này ở bất cứ nơi đâu trong view, bạn có thể viết hàm này trong một controller nào đó sau đó dùng requestAction để gọi hàm ra. Tuy nhiên đây không phải là cách tốt, đó là chưa kể tới việc dùng nhiều requestAction sẽ làm cho ứng dụng bị chậm đi. Chúng ta sẽ giải quyết vấn đề này cách xây dựng một helper!

Có thể hiểu nôm na rằng helper trong CakePHP là một tập hợp các thư viện hữu ích để dùng trong view. CakePHP đã xây dựng sẵn rất nhiều helper: form, html, ajax, number, session, rss, xml, time….

Muốn dùng helper nào thì trong Controller ta phải khai báo thông qua biến $helpersVí dụ:PHP Code:var $helpers = array('Html','Form','Javascript','Ajax'); 

Các bạn có thể tìm hiểu về các helper có sẵn của cake bằng cách vào: cake/libs/view/helpersVà bây giờ, chúng ta bắt đầu đi viết một helper cho riêng mình! Giả sử helper tôi muốn viết có tên là : Common => tên file tương ứng là common.php Đặt trong app/views/helpers/

Page 37: Cake php framework

Chú ý rằng AppHelper là lớp cơ sở cho mọi Helper .Do do đó, khi tạo ra một Helper mới, bạn có thể extends từ AppHelper hoặc từ một Helper nào đó có sẵn của CakePHPMã:Tên lớp helper = tên helper + “Helper”Bắt đầu với lớp Helper với tên Common , đặt trong thư mục (app/views/helpers/common.php)Với hàm tạo 1 chuỗi ngẫu nhiên.PHP Code:<?phpclass CommonHelper extends HtmlHelper {

 function create_random_string($num) {    //Tao du lieu cho hinh ngau nhien    $chars = array( 'a', 'A', 'b', 'B', 'c', 'C', 'd', 'D', 'e', 'E', 'f', 'F', 'g', 'G', 'h', 'H', 'i', 'I', 'j', 'J',  'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N', 'o', 'p', 'P', 'q', 'Q', 'r', 'R', 's', 'S', 't', 'T',  'u', 'U', 'v', 'V', 'w', 'W', 'x', 'X', 'y', 'Y', 'z', 'Z', '1', '2', '3', '4', '5', '6', '7', '8', '9');    $max_chars = count($chars) - 1;    for($i = 0; $i < $num; $i++) {      $code = ( $i == 0 ) ? $chars[rand(0, $max_chars)] : $code . $chars[rand(0, $max_chars)];    }    return $code;  }}?>

Cách sử dụng lớp Herpler Common vừa mới tạo :- Tôi tạo 1 Controller tên Testcommons (app/controllers/ testcommons _controller.php) sử dụng lớp Helper Common vừa tạoPHP Code:<?phpclass TestcommonsController extends AppController {    var $helpers = array('Common');        function test_helper(){

Page 38: Cake php framework

        $this->render("test_helper"); // load  file view test_helper.ctp     }}?>

- Sử dụng ngoài view : tạo file test_helper.ctp (app/views/testcommons/ test_helper.ctp)PHP Code:<?php    echo $this->Common->create_random_string(10);?>

Chạy thử : http://localhost/cakephp/testcommons/test_helper

Chú ý : Biến $helpers được khai báo trong Controller nào thì chỉ dùng được trong View của controller đó. Nếu tôi khai báo trong controller NewsController thì sang trang Product, dùng echo $common->create_random_string(6); sẽ bị báo lỗi ngay ! Như vậy không áp dụng được tính chất “dùng mọi lúc, mọi nơi” .Nhưng không sao, ta có thể giải quyết vấn đề này bằng cách:- Tạo file app_controller.php đặt trong thư mục app, nội dung file này như sau:

Page 39: Cake php framework

PHP Code:<?phpclass AppController extends Controller {   var $helpers = array('Html', 'Form','Javascript','Ajax','Common');}?>

Mọi thứ đặt trong AppController sẽ có tác dụng trên toàn bộ các Controller khác, do đó ta chỉ cần khai báoPHP Code:var $helpers = array('Html', 'Form','Javascript','Ajax','Common'); 

Cách vi t 1 Component cho CakePHP ế

Cách viết 1 Component cho CakePHP

- Người biên soạn : Thái Thanh Phong- YID : thaiphong260189- Email : [email protected]

- CakePHP đã hỗ trợ chúng ta một số component hữu ích: acl, mail, time, security… đặt trong cake/libs/controller/components. - Để sử dụng các component này, trong controller chúng ta khai báoPHP Code:var $components=array('Acl',’Mail’); 

- Giả sử tôi muốn loại bỏ dấu tiếng Việt các bài viết mà tôi nhận được từ user, không chỉ các bài bình luận về sản phẩm mà cả các bài bình luận về dự án, về hình ảnh nào đó trong website của tôi…- Cách đặt tên cho 1 Class Component :Mã:Tên lớp helper = tên comonent + “Component”

Page 40: Cake php framework

Component mà tôi muốn tạo ra có tên là Common, class tương ứng là CommonComponent và file tương ứng là common.php (app/controllers/components/common.php)

Nội dung file common.php như sau:PHP Code:<?phpclass CommonComponent extends Object{

function unicode_convert($str){              if(!$str) return false;              $unicode = array(                'a'=>array('á','à','ả','ã','ạ','ă','ắ','ặ','ằ','ẳ','ẵ','â','ấ','ầ','ẩ','ẫ','ậ'),                    'A'=>array('Á','À','Ả','Ã','Ạ','Ă','Ắ','Ặ','Ằ','Ẳ','Ẵ','Â','Ấ','Ầ','Ẩ','Ẫ','Ậ'),                    'd'=>array('đ'),                    'D'=>array('Đ'),                    'e'=>array('é','è','ẻ','ẽ','ẹ','ê','ế','ề','ể','ễ','ệ'),                    'E'=>array('É','È','Ẻ','Ẽ','Ẹ','Ê','Ế','Ề','Ể','Ễ','Ệ'),                    'i'=>array('í','ì','ỉ','ĩ','ị'),                    'I'=>array('Í','Ì','Ỉ','Ĩ','Ị'),                    'o'=>array('ó','ò','ỏ','õ','ọ','ô','ố','ồ','ổ','ỗ','ộ','ơ','ớ','ờ','ở','ỡ','ợ'),                    '0'=>array('Ó','Ò','Ỏ','Õ','Ọ','Ô','Ố','Ồ','Ổ','Ỗ','Ộ','Ơ','Ớ','Ờ','Ở','Ỡ','Ợ'),                    'u'=>array('ú','ù','ủ','ũ','ụ','ư','ứ','ừ','ử','ữ','ự'),                    'U'=>array('Ú','Ù','Ủ','Ũ','Ụ','Ư','Ứ','Ừ','Ử','Ữ','Ự'),                    'y'=>array('ý','ỳ','ỷ','ỹ','ỵ'),                    'Y'=>array('Ý','Ỳ','Ỷ','Ỹ','Ỵ'),                    '-'=>array(' ','&quot;','.','/','\'','’','(',')',',','!','"','“','”','%','&','@','#','$','*'),              );

Page 41: Cake php framework

              foreach($unicode as $nonUnicode=>$uni){                  foreach($uni as $value)                $str = str_replace($value,$nonUnicode,$str);              }        return $str;     }}?>

Tuy nhiên ,code bạn vẫn chạy được nhưng sẽ nhận được thông báo lỗi như sau :PHP Code:Warning (2): call_user_func_array() [function.call-user-func-array]:… 

- Ắc hẳn ít nhiều một số bạn sử dụng các component được chia sẽ trên mạng và cũng sẽ gặp lỗi như vậy. Mà trong khi đó tác giả lại không nhắc đến cách khắc phục , có lẽ một phần họ cho là kiến thức căn bản của chúng ta đã nắm vững .Nhưng không sao, cách phục như sau :Thêm vào Class Component của bạn dòng code dưới đây :PHP Code://called before Controller::beforeFilter()    function initialize(&$controller, $settings = array()) {        // saving the controller reference for later use        $this->controller =& $controller;    }

    //called after Controller::beforeFilter()    function startup(&$controller) {               }

    //called after Controller::beforeRender()    function beforeRender(&$controller) {    }

    //called after Controller::render()    function shutdown(&$controller) {    }

    //called before Controller::redirect()    function beforeRedirect(&$controller, $url, $status=null, $exit=true) {    }

    function redirectSomewhere($value) {        // utilizing a controller method    } 

Vậy Component Common hoàn chỉnh của tôi như sau : (app/controllers/components/common.php)PHP Code:<?phpclass CommonComponent extends Object{

    //called before Controller::beforeFilter()    function initialize(&$controller, $settings = array()) {

Page 42: Cake php framework

        // saving the controller reference for later use        $this->controller =& $controller;    }

    //called after Controller::beforeFilter()    function startup(&$controller) {    }

    //called after Controller::beforeRender()    function beforeRender(&$controller) {    }

    //called after Controller::render()    function shutdown(&$controller) {    }

    //called before Controller::redirect()    function beforeRedirect(&$controller, $url, $status=null, $exit=true) {    }

    function redirectSomewhere($value) {        // utilizing a controller method    }// Ham chuyen doi tieng viet sang khong dau    function unicode_convert($str){              if(!$str) return false;              $unicode = array(                'a'=>array('á','à','ả','ã','ạ','ă','ắ','ặ','ằ','ẳ','ẵ','â','ấ','ầ','ẩ','ẫ','ậ'),                    'A'=>array('Á','À','Ả','Ã','Ạ','Ă','Ắ','Ặ','Ằ','Ẳ','Ẵ','Â','Ấ','Ầ','Ẩ','Ẫ','Ậ'),                    'd'=>array('đ'),                    'D'=>array('Đ'),                    'e'=>array('é','è','ẻ','ẽ','ẹ','ê','ế','ề','ể','ễ','ệ'),                    'E'=>array('É','È','Ẻ','Ẽ','Ẹ','Ê','Ế','Ề','Ể','Ễ','Ệ'),                    'i'=>array('í','ì','ỉ','ĩ','ị'),                    'I'=>array('Í','Ì','Ỉ','Ĩ','Ị'),                    'o'=>array('ó','ò','ỏ','õ','ọ','ô','ố','ồ','ổ','ỗ','ộ','ơ','ớ','ờ','ở','ỡ','ợ'),                    '0'=>array('Ó','Ò','Ỏ','Õ','Ọ','Ô','Ố','Ồ','Ổ','Ỗ','Ộ','Ơ','Ớ','Ờ','Ở','Ỡ','Ợ'),                    'u'=>array('ú','ù','ủ','ũ','ụ','ư','ứ','ừ','ử','ữ','ự'),                    'U'=>array('Ú','Ù','Ủ','Ũ','Ụ','Ư','Ứ','Ừ','Ử','Ữ','Ự'),                    'y'=>array('ý','ỳ','ỷ','ỹ','ỵ'),                    'Y'=>array('Ý','Ỳ','Ỷ','Ỹ','Ỵ'),              );

              foreach($unicode as $nonUnicode=>$uni){                  foreach($uni as $value)

Page 43: Cake php framework

                $str = str_replace($value,$nonUnicode,$str);              }        return $str;     }}?>

Cách sử dụng lớp Component Common vừa mới tạo :- Tôi tạo 1 Controller tên Testcommons (app/controllers/ testcommons _controller.php) sử dụng lớp Comonent Common vừa tạoPHP Code:<?phpclass TestcommonsController extends AppController {    var $components = array("Common");        function test_component(){        $string = "Diễn đàn QHonline . Nơi khơi nguồn các mã nguồn mở "; // chuỗi ban đầu        $data = $this->Common->unicode_convert($string); // dữ liệu sau khi chuyển đổi không dấu        $this->set("data",$data); // gán dữ liệu để hiển thị bên view     }?>

- Tạo file test_component.ctp (app/views/testcommons/ test_component.ctp)PHP Code:<?phpecho $data;?>

Chạy thử : http://localhost/cakephp/testcommons/test_component

Chú ý : Biến $components được khai báo trong Controller nào thì chỉ dùng được trong Controller đóNếu tôi khai báo trong Controller NewsController thì sang trang Controller Product, dùng $this->Common->unicode_convert() sẽ bị báo lỗi ngay! Như vậy không áp dụng được tính chất “dùng mọi lúc, mọi nơi” .

Page 44: Cake php framework

Nhưng không sao, ta có thể giải quyết vấn đề này bằng cách:- Tạo file app_controller.php đặt trong thư mục app, nội dung file này như sau:

PHP Code:class AppController extends Controller {   var $components=array('Acl',’Mail’);} 

Mọi thứ đặt trong AppController sẽ có tác dụng trên toàn bộ các Controller khác, do đó ta chỉ cần khai báoPHP Code:var $components=array('Acl',’Mail’); 

S d ng Layout trong CakePHP ử ụ

Sử dụng Layout trong CakePHP

- Người biên soạn : Thái Thanh Phong- YID : thaiphong260189- Email : [email protected] Khi ta viết một ứng dụng cho CakePHP . mặc định CakePHP đã hổ trợ cho chúng ta dao diện sẵn . Nhưng đôi khi tùy theo sở thích, nhu cầu , xu hướng … nên bắt buộc người thiết kế cũng như người lập trình cần có những giao diện (layout) cho riêng mình.Bài viết sẽ hướng dẫn cách chúng ta tạo 1 layout cho riêng mình và cách áp dụng 1 Helper CakePHP vào ứng dụng của mình.

Khi phân tích 1 trang web , nhìn chung ta thấy gồm các phần chính như sau :

Page 45: Cake php framework

Để vận dụng được sự hổ trợ mạnh mẽ chắc năng load layout của FrameWork CakePHP , ta phân tích các thành phần cố định và thành phần động :

Page 46: Cake php framework

Như vậy ta để tránh việc xử lý các thành phần cố định ở controller ta chỉ cần viết 1 class Hepler để hiển thị nó . Còn thành phần động sẽ được xử lý thông qua Controllers.Cái file cần chuẩn bị trong Tutorial Layout CakePHP như sau : app/controllers/templates/ :-templates_controller.php (Controller chính để load layout) app/views/templates/ :- index.ctp - view.ctp app/views/helpers/ :- common.php (Tạo các thành phần cố định : menu , header,footer) app/views/layouts/ :- template.ctp (File chứa nội dung layout) app/webroot/css/ :- style.css (file CSS của layout)

Tạo file common.php (app/views/helpers/)PHP Code:<?php class CommonHelper extends HtmlHelper {

// Hàm tạo menu function create_menu(){     $menu  = "<ul>";     $menu .= "<li>".$this->link("CodeIgniter",array("controller"=>"templates","action"=>"view",1))."</li>";     $menu .= "<li>".$this->link("CakePHP",array("controller"=>"templates","action"=>"view",2))."</li>";     $menu .= "<li>".$this->link("Zend",array("controller"=>"templates","action"=>"view",3))."</li>";        $menu .= "</ul>";     return $menu;   }    //Hàm tạo các thành phần cho header và footer   function general(){     $data = array(                     "header" => "QHOnline.info",                     "footer" => "Copyright 2011 © | QHTeam",                 );     return $data;     } ?>

Tạo file templates_controller.php (app/controllers/templates/) :PHP Code:

Page 47: Cake php framework

<?php class TemplatesController extends AppController {     var $layout = "template"; // load file chứa nội dung layout : views/layouts/template.ctp     var $helpers = array("Html","Common"); // Thành phần Helper Common được gọi để tạo menu,header,footer trong view          function  index(){         $this->set('title_for_layout', 'Templates By QHOTeam');         $this->set("content","QHO Team");     }          function view($id){         switch($id){             case 1 :{                  $this->set('title_for_layout', 'CodeIgniter FrameWork');                 $this->set("content","CodeIgniter FrameWork");              }             break;             case 2 :{                 $this->set('title_for_layout', 'CakePHP FrameWork');                 $this->set("content","CakePHP FrameWork");             }             break;             case 3 :{                 $this->set('title_for_layout', 'Zend Framework');                 $this->set("content","Zend Framework");             }             break;             default :                 $this->set("content","Framwork");             break;         }     }           } ?>

Tạo file layout template.ctp (app/views/layouts/template.ctp) : File này chứa nội dung layout bao gồm các thành phần cố định và thành phần động như ban đầu mô tả. Nội dung file này gồm mã HTML và PHP…PHP Code:<!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"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title><?php echo $title_for_layout;?></title> <?php echo $this->Html->css("style"); // link oi file style.css (app/webroot/

Page 48: Cake php framework

css/style.css)?>  <?php $general = $this->Common->general(); // Lấy các giá trị của thành phần tĩnh : header,footer ?> </head> <body> <div id="top">     <center><h2><?php echo $general['header']; ?></h2></center> </div> <div id="main">     <div id="menu">         <?php echo $this->Common->create_menu(); // goi ham tao menu tu common helper?>     </div>     <div id="content">         <h1><?php echo $content; // Thành phần động ?></h1>     </div> </div> <div id="footer">     <center><?php echo $general['footer'];?></center> </div>

</body> </html>

Tạo file style.css (app/webroot/css/style.css)Mã:body {

margin: auto;width: 1000px;font-family: Verdana, Geneva, sans-serif;

}#top {

float: left;width: 1000px;height: 100px;background-color: #F36;color: #FFF;

}#main {

float: left;width: 1000px;

}#menu {

float: left;width: 200px;background-color: #F96;

}#menu ul {

margin: 0px;}#menu a {

color: #FFF;font-size: 12px;

Page 49: Cake php framework

}

#content {float: left;width: 800px;

}#content h1 {

font-size: 18px;color: #0CF;padding-left: 50px;

}

#footer {float: left;width: 1000px;height: 50px;background-color: #96C;font-size: 12px;font-weight: bold;color: #FFF;

}Hình mô ta khi file template.ctp sử dụng file helper Common.php

Như thường lệ , khi tạo 1 fuction cho 1 Controller , thì ta phải tạo file view tương ứng để hiển thị nội dung trong file view đó.Trong ví dụ này ta có Controller Templates với 2 function là index() và view(), cần phải có 2 file view là : index.ctp và view.ctp để hiển thị nội dung tương ứng.

Tuy nhiên chúng ta đang sử dụng layout template.ctp (app/views/layouts/template.ctp) ,nên chỉ cần tạo

Page 50: Cake php framework

2 file index.ctp và view.ctp ,nội dung của 2 file này các bạn bỏ trống. Ví dụ function index() được gọi , nó sẽ load file index.ctp và tự động nạp file layout vào (app/views/layouts/templates.ctp).Hình mô tả khi file view load file template.ctp

Page 51: Cake php framework

Ch y th ng d ng :ạ ử ứ ụ http://localhost/cakephp/templates

Khi click vào link c a Menu : ủ http://localhost/cakephp/templates/view/1

Page 52: Cake php framework

Cách s d ng Session trong CakePHP ử ụ

Cách sử dụng Session trong CakePHP

- Người biên soạn : Thái Thanh Phong- YID : thaiphong260189- Email : [email protected] Ắc hẳn khái niệm session khá quen thuộc đối với chúng ta .Trong bài viết này , tôi sẽ hướng dẫn các bạn cách sử dụng Sesion trong CakePHP kèm theo những ví dụ về cách sử dụng trong mỗi trường hợp

Page 53: Cake php framework

1.Giới thiệu :Trong CakePHP muốn lập trình ứng dụng thì ta cũng cần có những thành phần quan trọng như : Helper và Component thông qua hai biến $helpers và $componentXem các viết các thành phần cho CakePHP tại đây

Ví dụ khai báo : PHP Code:var  $helpers = array('Html', 'Form','Javascript','Ajax','Common');var  $components = array('Acl',’Mail’); 

Có những thành phần chỉ được khai báo trong $helpers như : Html,Form… , $component như : Acl,Mail.. . Tuy nhiên Session lại là trường hợp ngoại lệ , nó có thể khai báo trong cả hai thành phần $helpers và $components.PHP Code:var  $helpers = array('Html', 'Form','Javascript','Ajax','Common',’Session’);var  $components = array('Acl',’Mail’,’Session’); 

2.Cú pháp sử dụng : Cho dù Session được khai báo ở $helpers hay $component đi chăng nữa thì nó cũng có các hàm chính như sau :

a) write($name,$value)- Lưu session có giá trị $value vào tên $name- $name có thể sử dụng dấu chấm (.) để tạo thành mảng sessionVí dụ :PHP Code://Lưu theo cú pháp thông thường $this->Session->write('Username','administrator'); //Lưu dạng mảng$this->Session->write('Person.name', 'admin');$this->Session->write('Person.email', '[email protected]'); 

b) read($name)- Lấy giá trị của session thông qua tênVí dụ :PHP Code:echo $this->Session->read('Username');//kết quảadmin

pr($this->Session->read('Person'));//kết quảArray(    [name] => admin    [email] => [email protected]

Page 54: Cake php framework

c) check($name)- Kiểm tra xem có tồn tại session có tên là $name hay khôngVí dụ: không tồn tại Session UsernamePHP Code:$this->Session->check('Username');//Kết quảfalse 

d) delete($key)- Xóa Session thông qua tênPHP Code://Xóa Session Username$this->Session->delete('Username');//Chỉ xóa Session email của Person$this->Session->delete('Person.email');//Xóa toàn bộ Session Person$this->Session->delete('Person'); 

e) destroy()- Xóa toàn bộ Cookie và SessionPHP Code:$this->Session->destroy() 

f) error()- Xác định lỗi cuối cùng lên quan tới session

g) setFlash($message, $element = 'default', $params = array(), $key = 'flash')

- Thường sử trong Controllers $message : nội dung hiển thị $element : load file chứa nội dung bao quanh $message .Nội dung được lưu dạng file *.ctp trong thư mục app/view/elements/ $param : dủng dể thay đổi các thuộc tính như : class, id, style .. $key : mặc định là “flash”Ví dụ : Tôi có file sms.ctp (app/views/elements/sms.ctp)PHP Code:<div id="flashMessage" class="message_01"><?php echo $message ;?></div>

Thực hiện lệnh : PHP Code:$this->Session->setFlash('I miss you all the time', 'sms', array('class' => 'message_02')) 

Thì nội dung file sms.ctp sẽ được load và hiển thị là :PHP Code:<div id="flashMessage" class="message_02">I miss you all the time</div> 

Page 55: Cake php framework

Vi t ng d ng đăng nh p v i CakePHP ế ứ ụ ậ ớ

Viết ứng dụng đăng nhập với CakePHP

- Người biên soạn : Thái Thanh Phong- YID : thaiphong260189- Email : [email protected] 1.Giới thiệu:Trong bài viết này , tôi sẽ hướng dẫn các bạn cách áp dụng Session để viết 1 ứng dụng khá quen thuộc đó là chức năng đăng nhập .Qua bài Tutorial này các bạn sẽ có được kiến thức gì :- Cách vận dụng các hàm xử lý Session thông dụng- Cách sử dụng layout với file CSS được thiết kế riêng theo ý muốn- Cách load 1 file view theo ý muốn , không tuân theo qui tắc load file view của CakePHP- Cách sử dụng hàm của Model từ Controller tương ứng

Chuẩn bị CSDL :Mã:CREATE TABLE `users` ( `user_id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(20) NOT NULL, `password` varchar(20) NOT NULL, `email` varchar(50) DEFAULT NULL,

Page 56: Cake php framework

`gender` int(1) DEFAULT NULL, PRIMARY KEY (`user_id`));-- ------------------------------ Records -- ----------------------------INSERT INTO `users` VALUES ('1', 'admin', 'admin', '[email protected]', '1');INSERT INTO `users` VALUES ('2', 'user', 'user', '[email protected]', '2');INSERT INTO `users` VALUES ('3', 'assistant', 'assistant', '[email protected]', '1');INSERT INTO `users` VALUES ('4', 'kenny', 'kenny', '[email protected]', '1');

2.Yêu cầu : Tạo trang hiển hiển thị thông tin user . Khi truy cập vào trang này ,người sử dụng phải đăng nhập username và password hợp lệ. Nếu không , khi truy cập vào trang này , thì người sử sẽ tự động được chuyển ra trang đăng nhập.

3.Các thành phần chính trong ứng dụng :- Controller User (app/controllers/users_controller.php)giữ vai trò là controller chính, gồm các function :o View() : hiển thị thông tin khi đăng nhập thành côngo Login() : Kiểm tra username và password trước khi đăng nhậpo Logout() : Thoát khỏi trang View (hủy Session)- Model User (app/models/user.php)giữ vai trò kết nối bảng users trong CSDL, gồm các function :o CheckLogin() : kiểm tra username và password trong CSDL khi người dùng đăng nhập- View User (app/views/demos/users)o login.ctp : trang Logino index.ctp : trang hiển thị thông tin khi đăng nhập thành công- File CSSo webroot/css/login.css

4.Bắt đầu viết ứng dụng :Controller User (app/controllers/users_controller.php)PHP Code:<?phpclass UsersController extends AppController{    var $layout = false; // Không sử dụng Layout mặc định của CakePHP , dùng file CSS riêng    var $name = "Users";    var $helpers = array("Html");    var $component = array("Session");         var $_sessionUsername  = "Username"; // tên Session được qui định trước            //---------- View

Page 57: Cake php framework

    function view(){        if(!$this->Session->read($this->_sessionUsername)) // đọc Session xem có tồn tại không            $this->redirect("login");        else            $this->render("/demos/users/index"); // load 1 file view index.ctp trong thư mục “views/demos/users”/    }        //--------- Login    function login(){      $error="";// thong bao loi        if($this->Session->read($this->_sessionUsername))            $this->redirect("view");

        if(isset($_POST['ok'])){           $username = $_POST['username'];           $password = $_POST['password'];            if($this->User->checkLogin($username,$password)){                $this->Session->write($this->_sessionUsername,$username);                $this->redirect("view");            }else{                $error = "Username or Password wrong";           }        }        $this->set("error",$error);        $this->render("/demos/users/login");    }    //---------- Logout    function logout(){        $this->Session->delete($this->_sessionUsername);        $this->redirect("login");    }}

Model User (app/models/user.php)PHP Code:<?phpclass User extends AppModel{    var $name = "User";        function checkLogin($username,$password){        $sql = "Select username,password from users Where username='$username' AND password ='$password'";        $this->query($sql);        if($this->getNumRows()==0){            return false;        }else{            return true;        }

Page 58: Cake php framework

    }}?>

Các file View :index.ctp (app/demos/users/index.ctp)PHP Code:<html><title>Home Page</title><body><span>Login : <?php echo $this->Session->read("Username");?> | <a href="logout">Logout</a></span><h1>Wellcome to CakePHP Framework</h1></body></html>

login.ctp (app/demos/users/login.ctp)PHP Code:

<!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"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><?php echo $this->Html->css("login"); //load file CSS riêng (app/webroot/css/login.css)?><title>Login</title><body>    <form method="post" action="">Username</label><input type="text" name="username" size="20" /><br />        <label>Password</label><input type="password" name="password" size="20" /><br />        <label fieldset>        <legend>Login</legend>        <label >&nbsp;</label><input type="submit" name="ok" value="Login" />       <!—Hiển  thị thông báo lỗi nếu có-->        <span class="error"><?php echo $error; ?></span>        </fieldset>    </form></body></html>

Page 59: Cake php framework

Chạy thử ứng dụng : http://localhost/cakephp/users/login

Đăng nhập thành công

(Thái Thanh Phong)

Sql trong cakephpVí dụ ta có 2 mode $mode1 và $model 2bây giờ ta ở $model1 và ý nghĩa của :hasMany là quan hệ 1 thằng ở $Model1 sẽ có nhiều thằng có liên quan ở thằng $model 2;belongto là quan hệ nhiều 1 ngược lại ở cái trênhasone là quan hệ 1 1hasAndBelongsToMany là quan hệ như thế này :$model1 có id,name,...;$model2 có id,name....;$model3 gọi là có quan hệ hasAndBelongsToMany khi nó có 2 trườngmodel1_id và model2_id;

3.7.6 Associations: Linking Models Together Edit

History

One of the most powerful features of CakePHP is the ability to link relational mapping provided by the model. In CakePHP, the links between models are handled through associations.

Page 60: Cake php framework

Defining relations between different objects in your application should be a natural process. For example: in a recipe database, a recipe may have many reviews, reviews have a single author, and authors may have many recipes. Defining the way these relations work allows you to access your data in an intuitive and powerful way.

The purpose of this section is to show you how to plan for, define, and utilize associations between models in CakePHP.

While data can come from a variety of sources, the most common form of storage in web applications is a relational database. Most of what this section covers will be in that context.

For information on associations with Plugin models, see Plugin Models.

3.7.6.1 Relationship Types

Edit View just this section

History

The four association types in CakePHP are: hasOne, hasMany, belongsTo, and hasAndBelongsToMany (HABTM).

Relationship Association Type Example

one to one hasOne A user has one profile.

one to many hasMany A user can have multiple recipes.

many to one belongsTo Many recipes belong to a user.

many to many hasAndBelongsToMany Recipes have, and belong to many tags.

Associations are defined by creating a class variable named after the association you are defining. The class variable can sometimes be as simple as a string, but can be as complete as a multidimensional array used to define association specifics.

1. <?php2. class User extends AppModel {

3. var $name = 'User';

4. var $hasOne = 'Profile';

5. var $hasMany = array(

Page 61: Cake php framework

6. 'Recipe' => array(

7. 'className' => 'Recipe',

8. 'conditions' => array('Recipe.approved' => '1'),

9. 'order' => 'Recipe.created DESC'

10. )

11. );

12. }

13. ?>

In the above example, the first instance of the word 'Recipe' is what is termed an 'Alias'. This is an identifier for the relationship and can be anything you choose. Usually, you will choose the same name as the class that it references. However, aliases for each model must be unique app wide. E.g. it is appropriate to have

1. <?php2. class User extends AppModel {

3. var $name = 'User';

4. var $hasMany = array(

5. 'MyRecipe' => 'Recipe',

6. );

7. var $hasAndBelongsToMany => array('Member' => 'User');

8. }

9. class Group extends AppModel {

10. var $name = 'Group';

11. var $hasMany = array(

12. 'MyRecipe' => array(

13. 'className' => 'Recipe',

14. )

15. );

16. var $hasAndBelongsToMany => array('MemberOf' => 'Group');

17. }

Page 62: Cake php framework

18. ?>

but the following will not work well in all circumstances: 1. <?php2. class User extends AppModel {

3. var $name = 'User';

4. var $hasMany = array(

5. 'MyRecipe' => 'Recipe',

6. );

7. var $hasAndBelongsToMany => array('Member' => 'User');

8. }

9. class Group extends AppModel {

10. var $name = 'Group';

11. var $hasMany = array(

12. 'MyRecipe' => array(

13. 'className' => 'Recipe',

14. )

15. );

16. var $hasAndBelongsToMany => array('Member' => 'Group');

17. }

18. ?>

because here we have the alias 'Member' referring to both the User (in Group) and the Group (in User) model in the HABTM associations. Choosing non-unique names for model aliases across models can cause unexpected behavior.

Cake will automatically create links between associated model objects. So for example in your User model you can access the Recipe model as

1. $this->Recipe->someFunction();

Similarly in your controller you can access an associated model simply by following your model associations and without adding it to the $uses array:

Page 63: Cake php framework

1. $this->User->Recipe->someFunction();

Remember that associations are defined 'one way'. If you define User hasMany Recipe that has no effect on the Recipe Model. You need to define Recipe belongsTo User to be able to access the User model from your Recipe model

3.7.6.2 hasOne

Edit View just this section

History

Let’s set up a User model with a hasOne relationship to a Profile model.

First, your database tables need to be keyed correctly. For a hasOne relationship to work, one table has to contain a foreign key that points to a record in the other. In this case the profiles table will contain a field called user_id. The basic pattern is:

hasOne: the other model contains the foreign key.

Relation Schema

Apple hasOne Banana bananas.apple_id

User hasOne Profile profiles.user_id

Doctor hasOne Mentor mentors.doctor_id

The User model file will be saved in /app/models/user.php. To define the ‘User hasOne Profile’ association, add the $hasOne property to the model class. Remember to have a Profile model in /app/models/profile.php, or the association won’t work.

1. <?php2. class User extends AppModel {

3. var $name = 'User';

4. var $hasOne = 'Profile';

5. }

6. ?>

Page 64: Cake php framework

There are two ways to describe this relationship in your model files. The simplest method is to set the $hasOne attribute to a string containing the classname of the associated model, as we’ve done above.

If you need more control, you can define your associations using array syntax. For example, you might want to limit the association to include only certain records.

1. <?php2. class User extends AppModel {

3. var $name = 'User';

4. var $hasOne = array(

5. 'Profile' => array(

6. 'className' => 'Profile',

7. 'conditions' => array('Profile.published' => '1'),

8. 'dependent' => true

9. )

10. );

11. }

12. ?>

Possible keys for hasOne association arrays include:

className: the classname of the model being associated to the current model. If you’re defining a ‘User hasOne Profile’ relationship, the className key should equal ‘Profile.’

foreignKey: the name of the foreign key found in the other model. This is especially handy if you need to define multiple hasOne relationships. The default value for this key is the underscored, singular name of the current model, suffixed with ‘_id’. In the example above it would default to 'user_id'.

conditions: An SQL fragment used to filter related model records. It’s good practice to use model names in SQL fragments: “Profile.approved = 1” is always better than just “approved = 1.”

fields: A list of fields to be retrieved when the associated model data is fetched. Returns all fields by default.

order: An SQL fragment that defines the sorting order for the returned associated rows.

dependent: When the dependent key is set to true, and the model’s delete() method is called with the cascade parameter set to true, associated model records are also deleted. In this case we set it true so that deleting a User will also delete her associated Profile.

Page 65: Cake php framework

Once this association has been defined, find operations on the User model will also fetch a related Profile record if it exists:

//Sample results from a $this->User->find() call.

Array( [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ) [Profile] => Array ( [id] => 12 [user_id] => 121 [skill] => Baking Cakes [created] => 2007-05-01 10:31:01 ))

3.7.6.3 belongsTo

Edit View just this section

History

Now that we have Profile data access from the User model, let’s define a belongsTo association in the Profile model in order to get access to related User data. The belongsTo association is a natural complement to the hasOne and hasMany associations: it allows us to see the data from the other direction.

When keying your database tables for a belongsTo relationship, follow this convention:

belongsTo: the current model contains the foreign key.

Relation Schema

Banana belongsTo Apple bananas.apple_id

Profile belongsTo User profiles.user_id

Mentor belongsTo Doctor mentors.doctor_id

If a model(table) contains a foreign key, it belongsTo the other model(table).

Page 66: Cake php framework

We can define the belongsTo association in our Profile model at /app/models/profile.php using the string syntax as follows:

1. <?php2. class Profile extends AppModel {

3. var $name = 'Profile';

4. var $belongsTo = 'User';

5. }

6. ?>

We can also define a more specific relationship using array syntax:

1. <?php2. class Profile extends AppModel {

3. var $name = 'Profile';

4. var $belongsTo = array(

5. 'User' => array(

6. 'className' => 'User',

7. 'foreignKey' => 'user_id'

8. )

9. );

10. }

11. ?>

Possible keys for belongsTo association arrays include:

className: the classname of the model being associated to the current model. If you’re defining a ‘Profile belongsTo User’ relationship, the className key should equal ‘User.’

foreignKey: the name of the foreign key found in the current model. This is especially handy if you need to define multiple belongsTo relationships. The default value for this key is the underscored, singular name of the other model, suffixed with ‘_id’.

conditions: An SQL fragment used to filter related model records. It’s good practice to use model names in SQL fragments: “User.active = 1” is always better than just “active = 1.”

type: the type of the join to use in the SQL query, default is LEFT which may not fit your needs in all situations, INNER may be helpful when you want everything from your main and associated

Page 67: Cake php framework

models or nothing at all!(effective when used with some conditions of course). (NB: type value is in lower case - i.e. left, inner)

fields: A list of fields to be retrieved when the associated model data is fetched. Returns all fields by default.

order: An SQL fragment that defines the sorting order for the returned associated rows.

counterCache: If set to true the associated Model will automatically increase or decrease the “[singular_model_name]_count” field in the foreign table whenever you do a save() or delete(). If its a string then its the field name to use. The value in the counter field represents the number of related rows.

counterScope: Optional conditions array to use for updating counter cache field.

Once this association has been defined, find operations on the Profile model will also fetch a related User record if it exists:

//Sample results from a $this->Profile->find() call.

Array( [Profile] => Array ( [id] => 12 [user_id] => 121 [skill] => Baking Cakes [created] => 2007-05-01 10:31:01 ) [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ))

3.7.6.4 hasMany

Edit View just this section

History

Next step: defining a “User hasMany Comment” association. A hasMany association will allow us to fetch a user’s comments when we fetch a User record.

When keying your database tables for a hasMany relationship, follow this convention:

Page 68: Cake php framework

hasMany: the other model contains the foreign key.

Relation Schema

User hasMany Comment Comment.user_id

Cake hasMany Virtue Virtue.cake_id

Product hasMany Option Option.product_id

We can define the hasMany association in our User model at /app/models/user.php using the string syntax as follows:

1. <?php2. class User extends AppModel {

3. var $name = 'User';

4. var $hasMany = 'Comment';

5. }

6. ?>

We can also define a more specific relationship using array syntax:

1. <?php2. class User extends AppModel {

3. var $name = 'User';

4. var $hasMany = array(

5. 'Comment' => array(

6. 'className' => 'Comment',

7. 'foreignKey' => 'user_id',

8. 'conditions' => array('Comment.status' => '1'),

9. 'order' => 'Comment.created DESC',

10. 'limit' => '5',

11. 'dependent'=> true

12. )

Page 69: Cake php framework

13. );

14. }

15. ?>

Possible keys for hasMany association arrays include:

className: the classname of the model being associated to the current model. If you’re defining a ‘User hasMany Comment’ relationship, the className key should equal ‘Comment.’

foreignKey: the name of the foreign key found in the other model. This is especially handy if you need to define multiple hasMany relationships. The default value for this key is the underscored, singular name of the actual model, suffixed with ‘_id’.

conditions: An SQL fragment used to filter related model records. It’s good practice to use model names in SQL fragments: “Comment.status = 1” is always better than just “status = 1.”

fields: A list of fields to be retrieved when the associated model data is fetched. Returns all fields by default.

order: An SQL fragment that defines the sorting order for the returned associated rows.

limit: The maximum number of associated rows you want returned.

offset: The number of associated rows to skip over (given the current conditions and order) before fetching and associating.

dependent: When dependent is set to true, recursive model deletion is possible. In this example, Comment records will be deleted when their associated User record has been deleted.

exclusive: When exclusive is set to true, recursive model deletion does the delete with a deleteAll() call, instead of deleting each entity separately. This greatly improves performance, but may not be ideal for all circumstances.

finderQuery: A complete SQL query CakePHP can use to fetch associated model records. This should be used in situations that require very custom results.

If a query you're building requires a reference to the associated model ID, use the special {$__cakeID__$} marker in the query. For example, if your Apple model hasMany Orange, the query should look something like this:

1. SELECT Orange.* from oranges as Orange WHERE Orange.apple_id = {$__cakeID__$};

Once this association has been defined, find operations on the User model will also fetch related Comment records if they exist:

//Sample results from a $this->User->find() call.

Page 70: Cake php framework

Array( [User] => Array ( [id] => 121 [name] => Gwoo the Kungwoo [created] => 2007-05-01 10:31:01 ) [Comment] => Array ( [0] => Array ( [id] => 123 [user_id] => 121 [title] => On Gwoo the Kungwoo [body] => The Kungwooness is not so Gwooish [created] => 2006-05-01 10:31:01 ) [1] => Array ( [id] => 124 [user_id] => 121 [title] => More on Gwoo [body] => But what of the ‘Nut? [created] => 2006-05-01 10:41:01 ) ))

One thing to remember is that you’ll need a complimentary Comment belongsTo User association in order to get the data from both directions. What we’ve outlined in this section empowers you to get Comment data from the User. Adding the Comment belongsTo User association in the Comment model empowers you to get User data from the Comment model - completing the connection and allowing the flow of information from either model’s perspective.

3.7.6.5 hasAndBelongsToMany (HABTM)

Edit View just this section

History

there is a pending change for this section

Alright. At this point, you can already call yourself a CakePHP model associations professional. You're already well versed in the three associations that take up the bulk of object relations.

Page 71: Cake php framework

Let's tackle the final relationship type: hasAndBelongsToMany, or HABTM. This association is used when you have two models that need to be joined up, repeatedly, many times, in many different ways.

The main difference between hasMany and HABTM is that a link between models in HABTM is not exclusive. For example, we're about to join up our Recipe model with a Tag model using HABTM. Attaching the "Italian" tag to my grandma's Gnocchi recipe doesn't "use up" the tag. I can also tag my Honey Glazed BBQ Spaghettio's with "Italian" if I want to.

Links between hasMany associated objects are exclusive. If my User hasMany Comments, a comment is only linked to a specific user. It's no longer up for grabs.

Moving on. We'll need to set up an extra table in the database to handle HABTM associations. This new join table's name needs to include the names of both models involved, in alphabetical order, and separated with an underscore ( _ ). The contents of the table should be two fields, each foreign keys (which should be integers) pointing to both of the primary keys of the involved models. To avoid any issues - don't define a combined primary key for these two fields, if your application requires it you can define a unique index. If you plan to add any extra information to this table, it's a good idea to add an additional primary key field (by convention 'id') to make acting on the table as easy as any other model.

HABTM requires a separate join table that includes both model names.

Relation Schema (HABTM table in bold)

Recipe HABTM Tag recipes_tags.id, recipes_tags.recipe_id, recipes_tags.tag_id

Cake HABTM Fan cakes_fans.id, cakes_fans.cake_id, cakes_fans.fan_id

Foo HABTM Bar bars_foos.id, bars_foos.foo_id, bars_foos.bar_id

Table names are by convention in alphabetical order.

Make sure primary keys in tables cakes and recipes have "id" fields as assumed by convention. If they're different than assumed, it has to be changed in model

Once this new table has been created, we can define the HABTM association in the model files. We're gonna skip straight to the array syntax this time:

1. <?php2. class Recipe extends AppModel {

3. var $name = 'Recipe';

4. var $hasAndBelongsToMany = array(

Page 72: Cake php framework

5. 'Tag' =>

6. array(

7. 'className' => 'Tag',

8. 'joinTable' => 'recipes_tags',

9. 'foreignKey' => 'recipe_id',

10. 'associationForeignKey' => 'tag_id',

11. 'unique' => true,

12. 'conditions' => '',

13. 'fields' => '',

14. 'order' => '',

15. 'limit' => '',

16. 'offset' => '',

17. 'finderQuery' => '',

18. 'deleteQuery' => '',

19. 'insertQuery' => ''

20. )

21. );

22. }

23. ?>

Possible keys for HABTM association arrays include:

className: the classname of the model being associated to the current model. If you're defining a ‘Recipe HABTM Tag' relationship, the className key should equal ‘Tag.'

joinTable: The name of the join table used in this association (if the current table doesn't adhere to the naming convention for HABTM join tables).

with: Defines the name of the model for the join table. By default CakePHP will auto-create a model for you. Using the example above it would be called RecipesTag. By using this key you can override this default name. The join table model can be used just like any "regular" model to access the join table directly.

Page 73: Cake php framework

foreignKey: the name of the foreign key found in the current model. This is especially handy if you need to define multiple HABTM relationships. The default value for this key is the underscored, singular name of the current model, suffixed with ‘_id'.

associationForeignKey: the name of the foreign key found in the other model. This is especially handy if you need to define multiple HABTM relationships. The default value for this key is the underscored, singular name of the other model, suffixed with ‘_id'.

unique: If true (default value) cake will first delete existing relationship records in the foreign keys table before inserting new ones, when updating a record. So existing associations need to be passed again when updating.

conditions: An SQL fragment used to filter related model records. It's good practice to use model names in SQL fragments: "Comment.status = 1" is always better than just "status = 1."

fields: A list of fields to be retrieved when the associated model data is fetched. Returns all fields by default.

order: An SQL fragment that defines the sorting order for the returned associated rows.

limit: The maximum number of associated rows you want returned.

offset: The number of associated rows to skip over (given the current conditions and order) before fetching and associating.

finderQuery, deleteQuery, insertQuery: A complete SQL query CakePHP can use to fetch, delete, or create new associated model records. This should be used in situations that require very custom results.

Once this association has been defined, find operations on the Recipe model will also fetch related Tag records if they exist:

//Sample results from a $this->Recipe->find() call.

Array( [Recipe] => Array ( [id] => 2745 [name] => Chocolate Frosted Sugar Bombs [created] => 2007-05-01 10:31:01 [user_id] => 2346 ) [Tag] => Array ( [0] => Array ( [id] => 123 [name] => Breakfast ) [1] => Array ( [id] => 124

Page 74: Cake php framework

[name] => Dessert ) [2] => Array ( [id] => 125 [name] => Heart Disease ) ))

Remember to define a HABTM association in the Tag model if you'd like to fetch Recipe data when using the Tag model.

It is also possible to execute custom find queries based on HABTM relationships. Consider the following examples:

Assuming the same structure in the above example (Recipe HABTM Tag), let's say we want to fetch all Recipes with the tag 'Dessert', one potential (wrong) way to achieve this would be to apply a condition to the association itself:

1. $this->Recipe->bindModel(array(2. 'hasAndBelongsToMany' => array(

3. 'Tag' => array('conditions'=>array('Tag.name'=>'Dessert'))

4. )));

5. $this->Recipe->find('all');

//Data ReturnedArray( 0 => Array { [Recipe] => Array ( [id] => 2745 [name] => Chocolate Frosted Sugar Bombs [created] => 2007-05-01 10:31:01 [user_id] => 2346 ) [Tag] => Array ( [0] => Array ( [id] => 124 [name] => Dessert ) ) ) 1 => Array { [Recipe] => Array

Page 75: Cake php framework

( [id] => 2745 [name] => Crab Cakes [created] => 2008-05-01 10:31:01 [user_id] => 2349 ) [Tag] => Array ( } }}

Notice that this example returns ALL recipes but only the "Dessert" tags. To properly achieve our goal, there are a number of ways to do it. One option is to search the Tag model (instead of Recipe), which will also give us all of the associated Recipes.

1. $this->Recipe->Tag->find('all', array('conditions'=>array('Tag.name'=>'Dessert')));

We could also use the join table model (which CakePHP provides for us), to search for a given ID.

1. $this->Recipe->bindModel(array('hasOne' => array('RecipesTag')));2. $this->Recipe->find('all', array(

3. 'fields' => array('Recipe.*'),

4. 'conditions'=>array('RecipesTag.tag_id'=>124) // id of Dessert

5. ));

It's also possible to create an exotic association for the purpose of creating as many joins as necessary to allow filtering, for example:

1. $this->Recipe->bindModel(array(2. 'hasOne' => array(

3. 'RecipesTag',

4. 'FilterTag' => array(

5. 'className' => 'Tag',

6. 'foreignKey' => false,

7. 'conditions' => array('FilterTag.id = RecipesTag.tag_id')

8. ))));

9. $this->Recipe->find('all', array(

10. 'fields' => array('Recipe.*'),

Page 76: Cake php framework

11. 'conditions'=>array('FilterTag.name'=>'Dessert')

12. ));

Both of which will return the following data:

//Data ReturnedArray( 0 => Array { [Recipe] => Array ( [id] => 2745 [name] => Chocolate Frosted Sugar Bombs [created] => 2007-05-01 10:31:01 [user_id] => 2346 ) [Tag] => Array ( [0] => Array ( [id] => 123 [name] => Breakfast ) [1] => Array ( [id] => 124 [name] => Dessert ) [2] => Array ( [id] => 125 [name] => Heart Disease ) )}

The same binding trick can be used to easily paginate your HABTM models. Just one word of caution: since paginate requires two queries (one to count the records and one to get the actual data), be sure to supply the false parameter to your bindModel(); which essentially tells CakePHP to keep the binding persistent over multiple queries, rather than just one as in the default behavior. Please refer to the API for more details.

For more information on saving HABTM objects see Saving Related Model Data (HABTM)

For more information on binding model associations on the fly see Creating and destroying associations on the fly

Mix and match techniques to achieve your specific objective.

3.7.6.6 hasMany through (The Join Model)

Page 77: Cake php framework

Edit View just this section

History

It is sometimes desirable to store additional data with a many to many association. Consider the following

Student hasAndBelongsToMany Course Course hasAndBelongsToMany Student

In other words, a Student can take many Courses and a Course can be taken my many Students. This is a simple many to many association demanding a table such as this

id | student_id | course_id

Now what if we want to store the number of days that were attended by the student on the course and their final grade? The table we'd want would be

id | student_id | course_id | days_attended | grade

The trouble is, hasAndBelongsToMany will not support this type of scenario because when hasAndBelongsToMany associations are saved, the association is deleted first. You would lose the extra data in the columns as it is not replaced in the new insert.

The way to implement our requirement is to use a join model, otherwise known (in Rails) as a hasMany through association. That is, the association is a model itself. So, we can create a new model CourseMembership. Take a look at the following models.

1. student.php2.

3. class Student extends AppModel

4. {

5. public $hasMany = array(

6. 'CourseMembership'

7. );

8. public $validate = array(

9. 'first_name' => array(

10. 'rule' => 'notEmpty',

11. 'message' => 'A first name is required'

Page 78: Cake php framework

12. ),

13. 'last_name' => array(

14. 'rule' => 'notEmpty',

15. 'message' => 'A last name is required'

16. )

17. );

18. }

19.

20. course.php

21.

22. class Course extends AppModel

23. {

24. public $hasMany = array(

25. 'CourseMembership'

26. );

27. public $validate = array(

28. 'name' => array(

29. 'rule' => 'notEmpty',

30. 'message' => 'A course name is required'

31. )

32. );

33. }

34.

35. course_membership.php

36. class CourseMembership extends AppModel

37. {

38. public $belongsTo = array(

Page 79: Cake php framework

39. 'Student', 'Course'

40. );

41. public $validate = array(

42. 'days_attended' => array(

43. 'rule' => 'numeric',

44. 'message' => 'Enter the number of days the student attended'

45. ),

46. 'grade' => array(

47. 'rule' => 'notEmpty',

48. 'message' => 'Select the grade the student received'

49. )

50. );

51. }

The CourseMembership join model uniquely identifies a given Student's participation on a Course in addition to extra meta-information.

Working with join model data

Now that the models have been defined, let's see how we can save all of this. Let's say the Head of Cake School has asked us the developer to write an application that allows him to log a student's attendance on a course with days attended and grade. Take a look at the following code.

1. controllers/course_membership_controller.php2.

3. class CourseMembershipsController extends AppController

4. {

5. public $uses = array('CourseMembership');

6.

7. public function index() {

8. $this->set('course_memberships_list', $this->CourseMembership->find('all'));

9. }

Page 80: Cake php framework

10.

11. public function add() {

12.

13. if (! empty($this->data)) {

14.

15. if ($this->CourseMembership->saveAll(

16. $this->data, array('validate' => 'first'))) {

17.

18. $this->redirect(array('action' => 'index'));

19. }

20. }

21. }

22. }

23.

24. views/course_memberships/add.ctp

25. <?php echo $form->create('CourseMembership'); ?>

26. <?php echo $form->input('Student.first_name'); ?>

27. <?php echo $form->input('Student.last_name'); ?>

28. <?php echo $form->input('Course.name'); ?>

29. <?php echo $form->input('CourseMembership.days_attended'); ?>

30. <?php echo $form->input('CourseMembership.grade'); ?>

31. <button type="submit">Save</button>

32. <?php echo $form->end(); ?>

You can see that the form uses the form helper's dot notation to build up the data array for the controller's save which looks a bit like this when submitted.

Array( [Student] => Array ( [first_name] => Joe

Page 81: Cake php framework

[last_name] => Bloggs )

[Course] => Array ( [name] => Cake )

[CourseMembership] => Array ( [days_attended] => 5 [grade] => A )

)

Cake will happily be able to save the lot together and assigning the foreign keys of the Student and Course into CourseMembership with a saveAll call with this data structure. If we run the index action of our CourseMembershipsController the data structure received now from a find('all') is:

Array( [0] => Array ( [CourseMembership] => Array ( [id] => 1 [student_id] => 1 [course_id] => 1 [days_attended] => 5 [grade] => A )

[Student] => Array ( [id] => 1 [first_name] => Joe [last_name] => Bloggs )

[Course] => Array ( [id] => 1 [name] => Cake )

)

)

There are of course many ways to work with a join model. The version above assumes you want to save everything at-once. There will be cases where you want to create the Student and Course independently and at a later point associate the two together with a CourseMembership. So you

Page 82: Cake php framework

might have a form that allows selection of existing students and courses from picklists or ID entry and then the two meta-fields for the CourseMembership, e.g.

1. views/course_memberships/add.ctp2.

3. <?php echo $form->create('CourseMembership'); ?>

4. <?php echo $form->input('Student.id', array('type' => 'text', 'label' => 'Student ID', 'default' => 1)); ?>

5. <?php echo $form->input('Course.id', array('type' => 'text', 'label' => 'Course ID', 'default' => 1)); ?>

6. <?php echo $form->input('CourseMembership.days_attended'); ?>

7. <?php echo $form->input('CourseMembership.grade'); ?>

8. <button type="submit">Save</button>

9. <?php echo $form->end(); ?>

And the resultant POST

Array( [Student] => Array ( [id] => 1 )

[Course] => Array ( [id] => 1 )

[CourseMembership] => Array ( [days_attended] => 10 [grade] => 5 )

)

Again Cake is good to us and pulls the Student id and Course id into the CourseMembership with the saveAll.

Join models are pretty useful things to be able to use and Cake makes it easy to do so with its built-in hasMany and belongsTo associations and saveAll feature.

3.7.6.7 Creating and Destroying Associations on the Fly

Page 83: Cake php framework

Edit View just this section

History

Sometimes it becomes necessary to create and destroy model associations on the fly. This may be for any number of reasons:

You want to reduce the amount of associated data fetched, but all your associations are on the first level of recursion.

You want to change the way an association is defined in order to sort or filter associated data.

This association creation and destruction is done using the CakePHP model bindModel() and unbindModel() methods. (There is also a very helpful behavior called "Containable", please refer to manual section about Built-in behaviors for more information). Let's set up a few models so we can see how bindModel() and unbindModel() work. We'll start with two models:

1. <?php2. class Leader extends AppModel {

3. var $name = 'Leader';

4.

5. var $hasMany = array(

6. 'Follower' => array(

7. 'className' => 'Follower',

8. 'order' => 'Follower.rank'

9. )

10. );

11. }

12. ?>

13.  

14. <?php

15. class Follower extends AppModel {

16. var $name = 'Follower';

17. }

Page 84: Cake php framework

18. ?>

Now, in the LeadersController, we can use the find() method in the Leader model to fetch a Leader and its associated followers. As you can see above, the association array in the Leader model defines a "Leader hasMany Followers" relationship. For demonstration purposes, let's use unbindModel() to remove that association in a controller action.

1. function someAction() {2. // This fetches Leaders, and their associated Followers

3. $this->Leader->find('all');

4.

5. // Let's remove the hasMany...

6. $this->Leader->unbindModel(

7. array('hasMany' => array('Follower'))

8. );

9.

10. // Now using a find function will return

11. // Leaders, with no Followers

12. $this->Leader->find('all');

13.

14. // NOTE: unbindModel only affects the very next

15. // find function. An additional find call will use

16. // the configured association information.

17.

18. // We've already used find('all') after unbindModel(),

19. // so this will fetch Leaders with associated

20. // Followers once again...

21. $this->Leader->find('all');

22. }

Page 85: Cake php framework

Removing or adding associations using bind- and unbindModel() only works for the next find operation only unless the second parameter has been set to false. If the second parameter has been set to false, the bind remains in place for the remainder of the request.

Here’s the basic usage pattern for unbindModel():

1. $this->Model->unbindModel(2. array('associationType' => array('associatedModelClassName'))

3. );

Now that we've successfully removed an association on the fly, let's add one. Our as-of-yet unprincipled Leader needs some associated Principles. The model file for our Principle model is bare, except for the var $name statement. Let's associate some Principles to our Leader on the fly (but remember–only for just the following find operation). This function appears in the LeadersController:

1. function anotherAction() {2. // There is no Leader hasMany Principles in

3. // the leader.php model file, so a find here,

4. // only fetches Leaders.

5. $this->Leader->find('all');

6.

7. // Let's use bindModel() to add a new association

8. // to the Leader model:

9. $this->Leader->bindModel(

10. array('hasMany' => array(

11. 'Principle' => array(

12. 'className' => 'Principle'

13. )

14. )

15. )

16. );

17.

18. // Now that we're associated correctly,

Page 86: Cake php framework

19. // we can use a single find function to fetch

20. // Leaders with their associated principles:

21. $this->Leader->find('all');

22. }

There you have it. The basic usage for bindModel() is the encapsulation of a normal association array inside an array whose key is named after the type of association you are trying to create:

1. $this->Model->bindModel(2. array('associationName' => array(

3. 'associatedModelClassName' => array(

4. // normal association keys go here...

5. )

6. )

7. )

8. );

Even though the newly bound model doesn't need any sort of association definition in its model file, it will still need to be correctly keyed in order for the new association to work properly.

3.7.6.8 Multiple relations to the same model

Edit View just this section

History

There are cases where a Model has more than one relation to another Model. For example you might have a Message model that has two relations to the User model. One relation to the user that sends a message, and a second to the user that receives the message. The messages table will have a field user_id, but also a field recipient_id. Now your Message model can look something like:

1. <?php2. class Message extends AppModel {

3. var $name = 'Message';

4. var $belongsTo = array(

Page 87: Cake php framework

5. 'Sender' => array(

6. 'className' => 'User',

7. 'foreignKey' => 'user_id'

8. ),

9. 'Recipient' => array(

10. 'className' => 'User',

11. 'foreignKey' => 'recipient_id'

12. )

13. );

14. }

15. ?>

Recipient is an alias for the User model. Now let's see what the User model would look like.

1. <?php2. class User extends AppModel {

3. var $name = 'User';

4. var $hasMany = array(

5. 'MessageSent' => array(

6. 'className' => 'Message',

7. 'foreignKey' => 'user_id'

8. ),

9. 'MessageReceived' => array(

10. 'className' => 'Message',

11. 'foreignKey' => 'recipient_id'

12. )

13. );

14. }

15. ?>

Page 88: Cake php framework

It is also possible to create self associations as shown below.

1. <?php2. class Post extends AppModel {

3. var $name = 'Post';

4.

5. var $belongsTo = array(

6. 'Parent' => array(

7. 'className' => 'Post',

8. 'foreignKey' => 'parent_id'

9. )

10. );

11. var $hasMany = array(

12. 'Children' => array(

13. 'className' => 'Post',

14. 'foreignKey' => 'parent_id'

15. )

16. );

17. }

18. ?>

An alternate method of associating a model with itself (without assuming a parent/child relationship) is to have both the $belongsTo and $hasMany relationships of a model each to declare an identical alias, className, and foreignKey [property].

1. <?php2. class MySchema extends CakeSchema {

3. public $users = array (

4. 'id' => array ('type' => 'integer', 'default' => null, 'key' => 'primary'),

5. 'username' => array ('type' => 'string', 'null' => false, 'key' => 'index'),

Page 89: Cake php framework

6. // more schema properties...

7. 'last_user_id' => array ('type' => 'integer', 'default' => null, 'key' => 'index'),

8. 'indexes' => array (

9. 'PRIMARY' => array ('column' => 'id', 'unique' => true),

10. // more keys...

11. 'last_user' => array ('column' => 'last_user_id', 'unique' => false)

12. )

13. );

14. }

15. class User extends AppModel {

16. public $hasMany = array (

17. 'Tag' => array (

18. 'foreignKey' => 'last_user_id'

19. ),

20. // more hasMany relationships...

21. 'LastUser' => array (

22. 'className' => 'User',

23. 'foreignKey' => 'last_user_id'

24. )

25. );

26. public $belongsTo = array (

27. // in most cases this would be the only belongsTo relationship for this model

28. 'LastUser' => array (

29. 'className' => 'User',

30. 'foreignKey' => 'last_user_id',

31. 'dependent' => true

Page 90: Cake php framework

32. )

33. );

34. }

35. ?>

Reasoning [for this particular self-association method]: Say there are many models which contain the property $modelClass.lastUserId. Each model has the foreign key last_user_id, a reference to the last user that updated/modified the record in question. The model User also contains the same property (last_user_id), since it may be neat to know if someone has committed a security breach through the modification of any User record other than their own (you could also use strict ACL behaviors).

Fetching a nested array of associated records:

If your table has parent_id field you can also use find('threaded') to fetch nested array of records using a single query without setting up any associations.

3.7.6.9 Joining tables

Edit View just this section

History

there is a pending change for this section

In SQL you can combine related tables using the JOIN statement. This allows you to perform complex searches across multiples tables (i.e: search posts given several tags).

In CakePHP some associations (belongsTo and hasOne) performs automatic joins to retrieve data, so you can issue queries to retrieve models based on data in the related one.

But this is not the case with hasMany and hasAndBelongsToMany associations. Here is where forcing joins comes to the rescue. You only have to define the necessary joins to combine tables and get the desired results for your query.

Remember you need to set the recursion to -1 for this to work. I.e: $this->Channel->recursive = -1;

To force a join between tables you need to use the "modern" syntax for Model::find(), adding a 'joins' key to the $options array. For example:

1. $options['joins'] = array(

Page 91: Cake php framework

2. array('table' => 'channels',

3. 'alias' => 'Channel',

4. 'type' => 'LEFT',

5. 'conditions' => array(

6. 'Channel.id = Item.channel_id',

7. )

8. )

9. );

10. $Item->find('all', $options);

Note that the 'join' arrays are not keyed.

In the above example, a model called Item is left joined to the channels table. You can alias the table with the Model name, so the retrieved data complies with the CakePHP data structure.

The keys that define the join are the following:

table: The table for the join. alias: An alias to the table. The name of the model associated with the table is the best bet.

type: The type of join: inner, left or right.

conditions: The conditions to perform the join.

With joins, you could add conditions based on Related model fields:

1. $options['joins'] = array(2. array('table' => 'channels',

3. 'alias' => 'Channel',

4. 'type' => 'LEFT',

5. 'conditions' => array(

6. 'Channel.id = Item.channel_id',

7. )

8. )

9. );

10. $options['conditions'] = array(

Page 92: Cake php framework

11. 'Channel.private' => 1

12. );

13. $privateItems = $Item->find('all', $options);

You could perform several joins as needed in hasBelongsToMany:

Suppose a Book hasAndBelongsToMany Tag association. This relation uses a books_tags table as join table, so you need to join the books table to the books_tags table, and this with the tags table:

1. $options['joins'] = array(2. array('table' => 'books_tags',

3. 'alias' => 'BooksTag',

4. 'type' => 'inner',

5. 'conditions' => array(

6. 'Books.id = BooksTag.books_id'

7. )

8. ),

9. array('table' => 'tags',

10. 'alias' => 'Tag',

11. 'type' => 'inner',

12. 'conditions' => array(

13. 'BooksTag.tag_id = Tag.id'

14. )

15. )

16. );

17. $options['conditions'] = array(

18. 'Tag.tag' => 'Novel'

19. );

20. $books = $Book->find('all', $options);

Page 93: Cake php framework

Using joins with Containable behavior could lead to some SQL errors (duplicate tables), so you need to use the joins method as an alternative for Containable if your main goal is to perform searches based on related data. Containable is best suited to restricting the amount of related data brought by a find statement.