$i->php();

Hãy tiết kiệm điện và sử dụng opensource để bảo vệ môi trường

Lập trình viên nào không sử dụng mã nguồn mở giơ tay...

Đừng hỏi Tổ Quốc đã làm gì cho ta, mà hãy hỏi ta đã làm gì cho Tổ Quốc hôm nay (Khát Vọng Tuổi Trẻ - ns. Vũ Hoàn - nguyên tác J.F. Kenedy)

March 2010
M T W T F S S
« Feb    
1234567
891011121314
15161718192021
22232425262728
293031  

Sử dụng plugin Paypal IPN trong CakePHP

Posted By hoanbn on October 17, 2009

Xin chào mọi người!

Plugin paypal IPN này thật sự cần thiết cho những ai muốn sử dụng Paypal IPN trong cakephp. Tôi đã tìm kiếm trên mạng và sử dụng plugin này, thấy thật sự mang lại tiện ích rất lớn. Helper trong plugin sẽ giúp ta dẽ dàng tạo ra các nút Checkout, Add to Cart, Subscribe, và Donate một cách dễ dàng. Chức năng chính của plugin này là tạo ra các nút add to cart, subscribe … trong paypal để gửi thông tin lên paypal, thực hiện giao dịch và lưu trữ dữ liệu giao dịch trả về vào trong log và CSDL. (Cách sử dụng plugin bạn tham khảo tại đây).

Paypal IPN plugin. (Paypal Instant Payment Notification)
Version 1.4
Tác giả: Nick Baker (nick@webtechnick.com)

Website: http://www.webtechnick.com

Browse, Download, hoặc  Checkout Plugin.
Browse: http://projects.webtechnick.com/paypal_ipn
Download: http://projects.webtechnick.com/paypal_ipn.tar.gz
SVN: https://svn2.xp-dev.com/svn/nurvzy-paypal-ipn

Các bước cài đặt như sau:

1) Copy plugin vào trong project /app/plugins/paypal_ipn.

2) Import file /plugins/paypal_ipn/paypal_ipn.sql vào trong cơ sở dữ liệu.

3) Thêm những dòng dưới đây vào router: /app/config/routes.php fil

<?php
  /* Paypal IPN plugin */
  Router::connect('/paypal_ipn/process', array('plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'process'));

  /* Optional Routes, but nice for administration */
  Router::connect('/paypal_ipn/edit/:id', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'edit'), array('id' => '[a-zA-Z0-9\-]+', 'pass' => array('id')));
  Router::connect('/paypal_ipn/view/:id', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'view'), array('id' => '[a-zA-Z0-9\-]+', 'pass' => array('id')));
  Router::connect('/paypal_ipn/delete/:id', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'delete'), array('id' => '[a-zA-Z0-9\-]+', 'pass' => array('id')));
  Router::connect('/paypal_ipn/add', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'edit'));
  Router::connect('/paypal_ipn', array('admin' => true, 'plugin' => 'paypal_ipn', 'controller' => 'instant_payment_notifications', 'action' => 'index'));/*
  /* End Paypal IPN plugin */
?>

Router này sẽ chuyển cách gọi các controller và action trong plugin này về cách gọi thông thường. (nhìn code bạn sẽ hiểu ngay !^_^! )

Tạo tài khoản paypal:

Để sự dụng được plugin này bạn phải có một tài khoản paypal (tham khảo cách tạo tài khoản paypal tại đây). Với các lập trình viên, paypal có hỗ trợ cho việc tạo tài khoản ảo để test, địa chỉ https://developer.paypal.com. Khi tạo xong tài khoản, bật (enable) IPN trong tài khoản của bạn.

Sử dụng trong administator (tùy chọn): đây là trường hợp bạn thêm và lưu thông tin thông qua giao diện admin

1) Bạn phải đăng nhập vào trong phần quản trị với tài khoản administrator thông qua component Auth.

2) Sử dụng plugin tại http://www.yoursite.com/paypal_ipn

Sự dụng helper paypal (tùy chọn): Trong trường hợp bạn muốn sử dụng helper hoặc các button trong helper.

1) Cấu hình lại với thông tin của bạn tại /paypal_ipn/config/paypal_ipn_config.php

2) Thêm ‘PaypalIpn.Paypal’ vào trong danh sách helper của app_controller.php:

<?php
       var $helpers = array('Html','Form','PaypalIpn.Paypal');
?>

3) cách sử dụng (tham khảo thêm tại /paypal_ipn/views/helpers/paypal.php)

$paypal->button(String tittle, Options array);

ví dụ:

<?php
//Pay Now Button
echo $paypal->button('Pay Now', array('amount' => '12.00', 'item_name' => 'test item'));
//Pay Now Button with Image
echo $paypal->button('pay_now.jpg', array('amount' => '12.00', 'item_name' => 'test item'));

//Subscribe Button
echo $paypal->button('Subscribe', array('type' => 'subscribe', 'amount' => '60.00', 'term' => 'month', 'period' => '2'));

//Donate Button
echo $paypal->button('Donate', array('type' => 'donate', 'amount' => '60.00'));

//Add To Cart
echo $paypal->button('Add To Cart', array('type' => 'addtocart', 'amount' => '15.00'));
?>

Ta cũng có thể thêm một số thuộc tính Paypal hợp lệ vào trong options của button.

Ví dụ :

<?php echo $paypal->button('Pay Now', array('amount' => '12.00', 'item_name' => 'Stuff', 'return' => 'http://www.yoursite.com/thankyou')); ?>

Ngoài việc sử dụng các helper button đẻ tạo ra các button paypal ta còn có thể tạo ra thông các các thẻ html. Khi sử dụng thẻ form html ta phải sử dụng notify_url để gán tới http://www.yoursite.com/paypal_ipn/process
ví dụ:

<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
...
...
<input type="hidden" name="notify_url" value="http://www.yoursite.com/paypal_ipn/process" />
...
</form>

Khi thông tin giao dịch được trả về từ paypal, dữ liệu sẽ được lưu vào trong cơ sở dữ liệu và hàm afterPaypalNotification sẽ được gọi (nếu nó tồn tại). Đây sẽ là nơi bạn xử lý các thao tác login khác liên quan đến giao dịch sau khi giao dịch thành công.

Tạo ra function trong /app/app_controller.php như sau:

<?php
  function afterPaypalNotification($txnId){
    //Here is where you can implement code to apply the transaction to your app.
    //for example, you could now mark an order as paid, a subscription, or give the user premium access.
    //retrieve the transaction using the txnId passed and apply whatever logic your site needs.

    $transaction = ClassRegistry::init('PaypalIpn.InstantPaymentNotification')->findById($txnId);
    $this->log($transaction['InstantPaymentNotification']['id'], 'paypal');

    //Tip: be sure to check the payment_status is complete because failure transactions
    //     are also saved to your database for review.

    if($transaction['InstantPaymentNotification']['payment_status'] == 'Completed'){
      //Yay!  We have monies!
    }
    else {
      //Oh no, better look at this transaction to determine what to do; like email a decline letter.
    }
  }
?>

Chú ý:

1) Với các bạn chưa lần nào làm về paypal, các bạn có thể tìm hiểu qua về cách tạo một trang web trực tuyển qua paypal một cách đơn giản tại đây. Sau khi làm xong ví dụ này, tôi nghĩ các bạn sẽ hiểu rõ hơn nguyên tắc hoặt động của plugin này.

2) Plugin này hiện tại (version 2.1) theo tôi được biết thì chỉ có hỗ trợ 2 button chính là Paynow và Subscribe. Còn các nút AddToCart… thì chưa hỗ trợ việc lưu dữ liệu. Hi vọng khi các bạn sử dụng thì đã hỗ trợ đủ.

Chúc các bạn thành công  !^_^!

Note Config Apache

Posted By chaubl on August 30, 2009

Cấu hình cho Apache hiển thị file Gzip .

- Cài module mod_defalte.so vào thư mục …/apache2.2/modules

- Sửa file …/apache2/conf/httpd.conf enable mod_deflate.so
LoadModule deflate_module modules/mod_deflate.so

- Add MultiViews to Options:
Options Indexes FollowSymLinks MultiViews

- Uncomment AddEncoding:
AddEncoding x-compress .Z
AddEncoding x-gzip .gz .tgz
- Comment AddType:
#AddType application/x-compress .Z
#AddType application/x-gzip .gz .tgz

- Để hiển thị file Gzip dưới dạng xml thêm dòng :
AddType text/xml .gz .tgz

- Khởi động lại Apache:
…/httpd restart

So sánh cách lấy dữ liệu tự động và lấy theo query trong cakephp

Posted By hoanbn on August 26, 2009

I. So sánh

Trong cakephp, có 2 cách lấy dữ liệu chính là lấy dự liệu tự động thông qua các hàm viết sẵn của cakephp và lấy dữ liệu từ câu lệnh query trực tiếp.

Ưu nhược điểm của 2 phương pháp trên:

1. Lấy dữ liệu tự động

a) Ưu điểm

- Lấy dữ liệu từ các bảng sẽ được thực hiện tự động thông qua khai báo quan hệ ở model

- Việc thêm quan hệ hoặc thay đổi quan hệ giữa các bảng sẽ được thực hiện ở model, vì vậy khi quan hệ với bảng khác hoặc thay đổi dữ liệu chỉ cần thay đổi quan hệ ở model.

- Dễ dàng hơn trong việc phân trang, phân trang tìm kiếm.

- Dữ liệu lấy ra đã được đưa theo cấu trúc mảng hình cây hợp lý, làm cho việc hiển thị dữ liệu trở lên đơn giản và dễ dàng hơn.

b) Nhược điểm

- Việc lấy dữ liệu sẽ trở lên vô cùng nhiều và chậm do lấy dữ liệu từ tẩt cả các bảng quan hệ nếu không sử dụng hợp lý recursive và bindModel (cách dùng sẽ có ở dưới).

c) Định dạng dữ liệu lấy ra

Dữ liệu lấy ra sẽ được hiển thị theo nhiều định dang, tùy theo từng mối quan hệ là một – một, một nhiều hay nhiều nhiều.

- Với quan hệ một – một:

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
        )
)

- Với quan hệ một nhiều:

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
                )
        )
)

- Quan hệ nhiều – một

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
        )
)

- Quan hệ nhiều nhiều

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
                )
        )
)

2. Lấy dữ liệu từ câu lệnh query

a) Ưu điểm

- Việc lấy dữ liệu sẽ không còn phụ thuộc vào quan hệ ở model, mà chỉ phụ thuộc vào quan hệ khi khai báo ở câu query

- Việc lấy dữ liệu sẽ thực hiện nhanh hơn, liên kết giữa các bảng sẽ rõ ràng hơn dựa vào câu lệnh liên kết ở query.

b) Nhược điểm

- Khi thay đổi quan hệ giữa các bảng, hoặc thêm quan hệ với một bảng mới, phải sửa lại câu query.

- Việc phân trang sẽ trở nên khó khăn phức tạp hơn

- Dữ liệu lấy ra dưới dạng mảng, nhưng chưa được sắp xếp lại theo cấu trúc.

- Khi sử dụng câu lệnh query, ta phải hiểu rất rõ quan hệ và sử dụng thành thao các lệnh trong query

c) Định dạng dữ liệu lấy ra

Khi lấy dữ liệu thông qua câu lệnh query, thì với tất cả các quan hệ dữ liệu dữ liệu lấy ra từ câu lệnh query đểu có định dạng như sau:

Array

(

   [0] => Array
      (

[Category] => Array

(

[id] => 1

[name] => Thông tin thị trường

[alias] => tin_tuc

[parent_id] =>

[root_path] =>

[level] => 0

[order] =>

[lang] =>

[represent] =>

[is_hyperlink] => 0

[active] => 0

[layout] => 0

[created] => 0000-00-00 00:00:00

)

[NewsCategory] => Array

(

[id] => 16

[news_id] => 4

[category_id] => 1

)

)

[1] => Array

(

[Category] => Array

(

[id] => 2

[name] => Phân tích thị trường

[alias] =>

[parent_id] =>

[root_path] =>

[level] => 0

[order] =>

[lang] =>

[represent] =>

[is_hyperlink] => 0

[active] => 0

[layout] => 0

[created] => 0000-00-00 00:00:00

)

[NewsCategory] => Array

(

[id] => 17

[news_id] => 4

[category_id] => 2

)

)

)

3. So sánh tốc độ

Thực tế, cách sử dụng query và cách sử dụng lấy dữ liệu tự động thông qua các hàm find, findAll… sẽ không khác nhau là mấy hay nói đúng hơn là không khác gì nhau khi ta xác định rõ ràng recursive trong từng trường hơp cụ thể, kết hợp với sự dụng bindModel và unbindModel để xác định số lượng các bảng tham gia inner join.

II. Tối ưu dữ liệu theo cách lấy tự động

1. Sử dụng Recursive

Recursive trong cakephp thể hiện mức tham chiếu quan hệ nông, sâu giữa các bảng với nhau, trong cakephp có 4 mức thể hiện tham chiếu được thể hiện qua ví dụ sau đây:

Giả sử ta có tất cả 4 bảng bao gồm: domains, groups, users và news. Và mối quan hệ giữa các bảng như sau: Một domain có rất nhiều group, trong mỗi một group lại có rất nhiều user. Một user lại có thể đăng lên rất nhiều bài viết khác nhau. Vậy là ta có thể xác định các bảng có quan hệ tham chiếu đến nhau.

Ta có thể hình dung như sau:

table

domains

groups

users

News

domains

hasMany

groups

belongsTo

hasMany

users

belongsTo

hasMany

news

belongsTo

Giả sử ta muốn lấy dữ liệu ở bảng group theo câu lệnh $this->Group->find(‘all’). Việc sử dụng giá trị recursive sẽ cho phép ta lấy dữ liệu khác nhau.

Cú pháp sử dụng recursive trong trường hợp này là:

$this->Group->recursive = 1

Deapth

Mô tả

-1

Lấy dữ liệu ở bảng Group, không lấy thêm bất cứ bảng nào khác

0

Lấy dữ liệu ở bảng Group và dữ liệu domain tương ứng

1

Lấy dữ liệu ở bảng Group, Domain và dữ liệu ở bảng User tương ứng

2

Lấy dữ liệu ở bảng Group, Domain, User và dữ liệu ở bảng News tương ứng

Nhìn qua bảng trên ta thấy tùy từng giá trị recursive khác nhau mà cakephp thực hiện liên kết với (inner join) thích hợp. Giả sử như ta cho recursive bằng 2, có nghĩa là ta lấy ra dữ liệu của các group, dữ liệu domain tương ứng với mỗi group đó, đồng thời là một danh sách các user nằm trong từng group, trong mỗi user đấy lại lấy ra các tin tức do các user ấy đăng. Vậy có nghĩa là sẽ có 4 bảng liên kết với nhau. Với recursive là 1 thì chỉ có 3 bảng thôi.

Như vậy là tùy tường trường hợp cụ thể mà ta có thể khai báo giá trị recursive khác nhau. Trong trường hợp ta chỉ cần lấy dữ liệu từ mỗi bảng group thì ta chỉ cần khai báo giá trị recursive là -1. Nếu muốn lấy thêm dữ liệu ở bảng domain thì khai báo recursive = 0…. Việc khai báo recursive cho từng trường hợp sẽ làm tăng tốc độ query vì ta sẽ kiểm soát được số lượng các bảng liên kết với nhau.

2. Sử dụng bindModel và unbindModel

Trong một số trường hợp, với cùng một model chúng ta sẽ phải khai báo thêm một số quan hệ hoặc bỏ bớt một số quan hệ với các bảng khác, điều này xảy ra khi:

- Bạn cần giảm bớ số lượng dữ liệu và mối quan hệ của các bảng lien quan cần lấy đến, trong khi khởi tạo ở model ta đã khai báo tất cả các quan hệ ấy rồi. (ví dụ như trong model group ở trên, ta chỉ muốn lấy dữ liệu từ 2 bảng là group và user, trong khi đó theo quan hệ ta sẽ phải join đồng thời cả 3 bảng user, group và domain. Như vậy việc truy xuất dữ liệu sẽ chậm hơn)

- Bạn muốn thay đổi cách liên kết của một model xác định để sẵp xếp hoặc lọc dữ liệu liên quan.

Khi muốn thêm một liên kết ta sẽ dùng đến bindModel và khi muốn xóa một liên kết ta sẽ sử dụng unbindModel. (Cách sử dụng bindModel va unbindMode sẽ được bàn sau)

Sử dụng recursive, bindModel và unbindModel trong cakephp

Posted By hoanbn on August 25, 2009

Sử dụng recursive, bindModel và unbindModel sẽ giúp mọi người kiểm soát dữ liệu lấy ra trong cakephp.

1. Sử dụng Recursive

Recursive trong cakephp thể hiện mức tham chiếu quan hệ nông, sâu giữa các bảng với nhau, trong cakephp có 4 mức thể hiện tham chiếu được thể hiện qua ví dụ sau đây:

Giả sử ta có tất cả 4 bảng bao gồm: domains, groups, users và news. Và mối quan hệ giữa các bảng như sau: Một domain có rất nhiều group, trong mỗi một group lại có rất nhiều user. Một user lại có thể đăng lên rất nhiều bài viết khác nhau. Vậy là ta có thể xác định các bảng có quan hệ tham chiếu đến nhau.

Ta có thể hình dung như sau:

table

domains

groups

users

News

domains

hasMany

groups

belongsTo

hasMany

users

belongsTo

hasMany

news

belongsTo

Giả sử ta muốn lấy dữ liệu ở bảng group theo câu lệnh $this->Group->find(‘all’). Việc sử dụng giá trị recursive sẽ cho phép ta lấy dữ liệu khác nhau.

Cú pháp sử dụng recursive trong trường hợp này là:

$this->Group->recursive = 1

Deapth

Mô tả

-1

Lấy dữ liệu ở bảng Group, không lấy thêm bất cứ bảng nào khác

0

Lấy dữ liệu ở bảng Group và dữ liệu domain tương ứng

1

Lấy dữ liệu ở bảng Group, Domain và dữ liệu ở bảng User tương ứng

2

Lấy dữ liệu ở bảng Group, Domain, User và dữ liệu ở bảng News tương ứng

Nhìn qua bảng trên ta thấy tùy từng giá trị recursive khác nhau mà cakephp thực hiện liên kết với (inner join) thích hợp. Giả sử như ta cho recursive bằng 2, có nghĩa là ta lấy ra dữ liệu của các group, dữ liệu domain tương ứng với mỗi group đó, đồng thời là một danh sách các user nằm trong từng group, trong mỗi user đấy lại lấy ra các tin tức do các user ấy đăng. Vậy có nghĩa là sẽ có 4 bảng liên kết với nhau. Với recursive là 1 thì chỉ có 3 bảng thôi.

Như vậy là tùy tường trường hợp cụ thể mà ta có thể khai báo giá trị recursive khác nhau. Trong trường hợp ta chỉ cần lấy dữ liệu từ mỗi bảng group thì ta chỉ cần khai báo giá trị recursive là -1. Nếu muốn lấy thêm dữ liệu ở bảng domain thì khai báo recursive = 0…. Việc khai báo recursive cho từng trường hợp sẽ làm tăng tốc độ query vì ta sẽ kiểm soát được số lượng các bảng liên kết với nhau.

2. Sử dụng bindModel và unbindModel

Trong một số trường hợp, với cùng một model chúng ta sẽ phải khai báo thêm một số quan hệ hoặc bỏ bớt một số quan hệ với các bảng khác, điều này xảy ra khi:

- Bạn cần giảm bớ số lượng dữ liệu và mối quan hệ của các bảng lien quan cần lấy đến, trong khi khởi tạo ở model ta đã khai báo tất cả các quan hệ ấy rồi. (ví dụ như trong model group ở trên, ta chỉ muốn lấy dữ liệu từ 2 bảng là group và user, trong khi đó theo quan hệ ta sẽ phải join đồng thời cả 3 bảng user, group và domain. Như vậy việc truy xuất dữ liệu sẽ chậm hơn)

- Bạn muốn thay đổi cách liên kết của một model xác định để sẵp xếp hoặc lọc dữ liệu liên quan.

Khi muốn thêm một liên kết ta sẽ dùng đến bindModel và khi muốn xóa một liên kết ta sẽ sử dụng unbindModel.

Giả sử giờ ta có 2 model là user và group. Một group sẽ chứa nhiều user và mỗi user nằm trong 1 group.

Trươc tiên chúng ta sẽ khai báo 2 model

<?php
//app/models/group.php
class Group extends AppModel {
    var $name = 'Group';

    var $hasMany = array(
        'User' => array(
            'className' => 'User'
        )
    );
}

?>

<?php
//app/models/user.php

class User extends AppModel {
    var $name = 'User';
}

?>

Giờ chúng ta sẽ xem cách hoạt động của bindModel và unbindModel qua ví dụ dưới đây. Trong groupController chúng ta sẽ lấy dữ liệu của group bằng $this->Group->find(), dữ liệu sẽ lấy luôn cả dữ liệu của user. Ví dụ minh họa dưới đây sẽ cho ta hiểu rõ hơn cách sử dùng và làm việc của bindModel và unbindModel.

function someAction() {
    // Lấy dữ liệu của group, ta sẽ lấy được cả dữ liệu của user trong từng group ấy
    $group = $this->Group->find('all');
    echo 'Lấy theo model'
    debug($group);

    // Bỏ quan hệ hasMany...
    $this->Group->unbindModel(
        array('hasMany' => array('User'))
    );

    // Sử dụng lại chức năng find()
    // Hiên thị group, không có user
    $group = $this->Group->find('all');
    echo 'Bỏ quan hệ với bảng user';
    debug($group);

    // Thêm quan hệ hasMany...

   $this->Group->bindModel(
        array('hasMany' => array(
                'User' => array(
                    'className' => 'User'
                )
            )
        )
    );

    // Sử dụng lại chức năng find()
    // Hiên thị group, có user
    $group = $this->Group->find('all');
    echo 'Thêm quan hệ với bảng user';
    debug($group);

    // Bỏ quan hệ hasMany lần 2...
    $this->Group->unbindModel(
        array('hasMany' => array('User'))
    );

    // Sử dụng lại chức năng find()
    // Hiên thị group, không có user
    $group = $this->Group->find('all');
    echo 'Bỏ quan hệ với bảng user lần 2';
    debug($group);

    //Chú ý: unbindModel và bindModel chỉ hiệu quả
    // duy nhất trong lần lấy dữ liệu tiếp theo,
    // sau lần thứ 2 sẽ lấy thông tin mặc định từ model

    // Chúng ta sẽ sử dụng lại hàm find('all') sau unbindModel(),
    // Dữ liệu lấy ra sẽ bao gổm cả group và user
    echo 'Lấy dữ liệu mặc định';
    $group = $this->Group->find('all');
    debug($group);
}

Cú pháp chuẩn của unbindModel

$this->Model->unbindModel(
    array('associationType' => array('associatedModelClassName'))
);

Cú pháp chuẩn của bindModel

$this->Model->bindModel(
        array('associationName' => array(
                'associatedModelClassName' => array(
                    // normal association keys go here...
                )
            )
        )
    );

Sử dụng hiệu quả recursive, bindModel và unbindModel sẽ giúp mọi người tăng tốc độ truy vấn query của cakephp vì với mỗi trường hợp lấy dữ liệu tôi đã xác định rõ các bảng cần lấy và quan hệ giữa chúng, vì vậy giảm thiều việc liên kết thừa giữa các bảng mà chúng ta không cần lấy. Chúc mọi người có một ngày vui vẻ @(^_^)@

Sử dụng plugin trong cakephp 1.2!

Posted By hoanbn on August 11, 2009

Hello cả nhà!

Hôm nay tôi xin giới thiệu với mọi người về cách sử dụng plugin trong cakephp. Như mọi người đều biết, cakephp là một framework hỗ trợ lập trình php một cách nhanh chóng và hiệu quả nhất. Sử dụng cakephp sẽ làm tăng tốc độ phát triển các dự án lên nhiều lần. Trong quá trình phát triển dự án, việc sử dụng đi sử dụng lại các đoạn code viết sẵn là đỉều tất yếu. Vậy sử dụng lại code như thế nào cho hiệu quả cũng là một bài toán đáng để quan tâm. Nếu như mọi người cứ copy nguyên code các dự án đã có rồi phát triển nên, sẽ làm cho code ngày càng nhiều khó quản lý và tái sử dụng ở các lần sau. Với cakephp, việc tái sử dụng code sẽ trở nên đơn giản hơn thông qua sử dụng tiện ích plugin. Các module chức năng sẽ được tách riêng ra thành các plugin, và khi sử dụng module chức năng nào, ta chỉ việc đưa plugin đó vào trong cakephp mà thôi. Việc sử dụng plugin sẽ làm cho các chức năng trở nên rõ ràng, tách biệt và dễ quản lý, maintain cũng như phát triên nên.

Việc tạo một plugin trong cakephp vô cùng đơn giản và dễ hiểu. Để tạo ra một plug, chúng ta sẽ đưa vào trong thư mục app/plugins. Ví dụ sau đây chúng ta sẽ tạo ra một plugin tin tức với các chức năng thêm sửa xóa. Đâu tiên sẽ là tạo ra CSDL tên là plugin trong đó có bảng news:

CREATE TABLE IF NOT EXISTS `news` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`title` varchar(255) DEFAULT NULL,
`description` text,
`content` text,
`created` datetime DEFAULT NULL,
`user_id` int(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;

CREATE TABLE IF NOT EXISTS `users` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
Việc cấu hình database kết nối đến CSDL mới tạo tôi sẽ để mọi người tự làm nhé (Đây là công việc cơ bản mà ^_^ ). Tiếp theo ta sẽ tạo ra một plugin tintuc bằng cách thêm một thư mục tintuc như sau : app/plugins/tintuc . Cấu trúc bên trong thư mục tin tức sẽ giống hệt như là cấu trúc bên trong thư mục app. Ta sẽ có một thư thư mục cơ bản cần thiết như sau:

+ Thư mục controller như sau: app/plugins/tintuc/controllers.

+ Thư mục view như sau:  app/plugins/tintuc/view

+ Thư mục models như sau:  app/plugins/tintuc/models

+ Thư mục layout như sau:  app/plugins/tintuc/layouts

+ Thư mục helpers như sau:  app/plugins/tintuc/view/helpers

+ Thư mục components như sau:  app/plugins/tintuc/controllers/components

+ Tệp tin TintucAppController: app/plugins/tintuc/tintuc_app_controller.php

+ Tệp tin TintucAppModel: app/plugins/tintuc/tintuc_app_model.php

+ …………………………………

Như đã thấy ở trên, cấu trúc các thư mục trong plugin sẽ tương tự như cấu trúc thư mục như trong phần app. Riêng 2 file tintuc_app_controller.php và tintuc_app_model.php sẽ có nội dung như sau:

//app/plugins/tintuc/tintuc_app_controller.php

<?php
class TinTucAppController extends AppController {

}
?>

//app/plugins/tintuc/tintuc_app_model.php

<?php
class TintucAppModel extends AppModel {

}
?>

Tiếp theo ta sẽ khai báo một news_controllers theo app/plugins/tintuc/controllers/news_controller.php

<?php
class NewsController extends TintucAppController
{

var $name = 'News';
var $uses = array('Tintuc.News');
var $helpers = array('Html', 'Form', 'Javascript');

function index($param=null)
{
$this->News->recursive = 0;
$this->paginate = array('limit' => 15, 'page' => 1, 'order' => array('News.created' => 'desc'));
$this->set ('news', $this->paginate ('News'));
}

function add()
{
$this->layout = 'homepage';
if(! empty ($this->data))
{
$this->News->create ();
if($this->News->save ($this->data))
{
$this->Session->setFlash (__ ('The News has been saved', true));
$this->redirect ('/tintuc/news/index');
}else
{
$this->Session->setFlash (__ ('The News could not be saved. Please, try again.', true));
}
}
}

function edit($id = null)
{
if(! $id && empty ($this->data))
{
$this->Session->setFlash (__ ('Invalid News', true));
$this->redirect (array('action' => 'index'));
}
$news = $this->News->read (null, $id);
if(! empty ($this->data))
{
if($this->News->save ($this->data))
{
$this->Session->setFlash (__ ('The News has been saved', true));
$this->redirect ('/tintuc/news/index');
}else
{
$this->Session->setFlash (__ ('The News could not be saved. Please, try again.', true));
}
}

if(empty ($this->data))
{
$this->data = $news;
}
}

function delete($id = null)
{
if(! $id)
{
$this->Session->setFlash (__ ('Invalid id for News', true));
$this->redirect ('/tintuc/news/index');
}
$del_news = $this->News->findById ($id);
if($this->News->del ($id))
{
$this->Session->setFlash (__ ('News deleted', true));
$this->redirect ('/tintuc/news/index');
}
}

}
?>

Khai báo tiếp một file model news.php theo đường dẫn app/plugins/tintuc/models/news.php

<?php
class News extends TintucAppModel {
var $name = 'News';
var $belongsTo = array('User');
}
?>

Vậy là đã xong controller và model. Giờ tôi sẽ tạo ra 3 view là index, add và edit

//app/plugins/tintuc/views/news/add.ctp

<?php
echo $form->create('News', array('url' => '/tintuc/news/add'));
echo $form->input('title');
echo $form->input('description');
echo $form->input('created');
echo $form->input('content');
echo $form->end('Submit');
?>

//app/plugins/tintuc/views/news/edit.ctp

<?php
echo $form->create('News');
echo $form->hidden('id');
echo $form->input('title');
echo $form->input('description');
echo $form->input('created');
echo $form->input('content');
echo $form->end('Submit');
?>

//app/plugins/tintuc/views/news/index.ctp

<h2>Index</h2>

<table>
<tr>
<th>Title</th>
<th>User</th>
<th>Created</th>
<th>Action</th>
</tr>
<?php
foreach ($news as $n)
{
?>
<tr>
<td><?=$n['News']['title']?></td>
<td><?=$n['User']['name']?></td>
<td><?=$n['News']['created']?></td>
<td>
<?=$html->link('Edit', '/tintuc/news/edit/'.$n['News']['id']);?>
<?=$html->link('Delete', '/tintuc/news/delete/'.$n['News']['id'], null, sprintf(__('Are you sure you want to delete # %s?', true), $n['News']['id']));?>
</td>
</tr>
<?php
}
?>
</table>

<?=$html->link('Add', '/tintuc/news/add')?>

Tôi đã vừa hoàn thành một plugin cơ bản trong cakephp. Bây giờ tôi sẽ lấy dữ liệu từ plugin thông qua một test_controller như sau:

//app/controllers/tests_controllers.php

<?php
class TestController extends AppController {

var $name = 'Test';
var $uses = array('Tintuc.News);

function index()
{
debug($this->News->find('all'));
die();
}
}
?>

Trong plugin ta còn có thể tạo ra các components, helpers, layouts riêng cho mình. Các file này sẽ nằm ở các thư mục tương ứng trong plugins. Việc tao ra các class components, helpers, layout tương tự như thêm components, helpers hoặc layout bình thường.  Sử dụng các components, helpers, layouts trong controller như sau:

var $components = array('Tintuc.Comp');

Như vậy là ta chỉ thêm tên các plugin phía trước các components và helper mà thôi, riêng với layout tao khai báo như bình thương, vì nó sẽ mặc định là chồng đề lên thư mục app/views/layouts.

var $layout = 'temp_layout';

Việc chỉ định sử dụng các file javascript, css và ảnh sẽ được lưu vào trong các thư mục tương ứng là tintuc/vendors/js, tintuc/vendors/css and tintuc/vendors/img và sẽ được gọi như sau:

<?php echo $html->image('/tintuc/img/my_image.png'); ?>

<?php echo $html->css('/tintuc/css/my_css'); ?>

<?php echo $javascript->link('/tintuc/js/do_cool_stuff'); ?>
Tôi đã trình bày mọi thứ cơ bản liên quan đến plugin với mọi người rồi, giờ mọi người hãy tự trải nghiêm nhé. Chúc cả nhà vui vẻ @(^_^)@.



Phân trang tìm kiếm đầy đủ với cakephp 1.2

Posted By hoanbn on July 24, 2009

Chào cả nhà!

Thật không nhớ nổi đây là lần thứ mấy tôi viết bài với tiêu đề phân trang tìm kiếm cho cakephp nữa. Vậy tại sao lại còn có bài viết này nữa. Việc phân trang tìm kiếm với cakephp đã không biết bao nhiêu lần làm tôi đâu đầu rồi. Sau nhiều lần tìm kiếm các giải pháp, nay tôi cũng đa tìm ra một giải pháp ứng ý trong việc tìm kiếm phân trang với cakephp. Sau đây tôi sẽ chia sẽ với mọi người giải pháp ấy, được minh họa thông qua ví dụ tìm kiếm sản phẩm dưới đây.

Việc đâu tiên là tôi phải tạo csdl. Trong ví dụ này tôi tạo csdl có tên là phantrang:

CREATE DATABASE phantrang;

CREATE TABLE IF NOT EXISTS `products` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
`model` varchar(255) NOT NULL,
`price` int(16) DEFAULT NULL,
`created` datetime DEFAULT NULL,
`type` enum(‘Loai 1′,’Loai 2′,’Loai 3′) DEFAULT NULL,
`description` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;

Vậy là tôi đã tạo xong CSDL, còn việc config để kết nối vào CSDL vừa tạo thì mọi người tự làm nhé. Dữ liệu trong đây thì mọi người tự thêm vào nhé.(^_^).

Công việc tiếp theo là tôi sẽ tạo ra một /app/controllers/products_controllers.php như sau:

/*  app/controllers/products_controller.php */

<?php
class ProductsController extends AppController {

var $name = ‘Products’;
var $scaffold;

}
?>

Với các chức năng như add, edit, delete trong ví dụ này tôi sẽ dùng chức năng scaffold của cakephp, và quả thật những trường hợp như thế này thì scaffold quá tuyệt vời. Trong bài viết này tôi sẽ chỉ chú trọng vào chức năng tìm kiếm mà thôi. Tiếp đến tôi sẽ tạo một function search trong products_controller như sau:

/*  app/controllers/products_controller.php */

<?php
class ProductsController extends AppController {

var $name = ‘Products’;
var $scaffold;

function search() {

}

}
?>

Cả nhà chú ý nhé, khi tôi thêm dữ liệu vào thì tôi sẽ copy lại nguyên nội dung của cả trang để mọi người dễ hiểu hơn, chỉ phần nào thêm mới tôi sẽ in đậm lên thôi. Bây giờ tôi sẽ tạo một trang view search như sau app/views/products/search.ctp

//  app/view/products/search.ctp

<?php
echo $form->create(‘Search’, array(‘url’ => ‘/products/dataSearch’));
echo $form->input(‘name’);
echo $form->input(‘price’);
echo $form->input(‘model’);
echo $form->input(‘type’, array(‘options’ => array(” => ”,’Loai 1′ => ‘Loại 1′, ‘Loai 2′ => ‘Loại 2′, ‘Loai 3′ => ‘Loai 3′)));
echo $form->input(‘description’);
echo $form->end(‘Search’);

?>

Phần form search vừa rồi tôi đã đề ‘url’ trỏ đến action ‘dataSearch’. Action ‘dataSearch’ này trong đây sẽ thực hiện công việc xử lý dữ liệu trong form tìm kiếm và chuyển lên url. Tôi thêm function dataSearch trong products_controller như sau:

/*  app/controllers/products_controller.php */

<?php
class ProductsController extends AppController {

var $name = ‘Products’;
var $scaffold;

function search()
{
}

function dataSearch()
{
// the page we will redirect to
$url['controller'] = ‘products’;
$url['action'] = ’search’;

// build a URL will all the search elements in it
// the resulting URL will be
// example.com/cake/posts/index/Search.keywords:mykeyword/Search.tag_id:3
foreach ($this->data as $k=>$v){
foreach ($v as $kk=>$vv){
$url[$k.'.'.$kk]=$vv;
}
}

// redirect the user to the url
$this->redirect($url, null, true);
}

}
?>

Hàm dataSearch sẽ thực hiện chức năng chuyển tòan bộ dữ liệu vừa được gửi (submit) vào trong một mảng và sau đó thông qua hàm ‘redirect’ chuyến sang một trang mới. Việc chuyển đến trang nào sẽ được quyết định thông qua 2 biến “$url['controller']” và “$url['action']” . Nếu bạn nào chưa hiểu hàm này thực hiện những công việc gì thì các bạn cũng không cần tìm hiểu đâu, vì hàm này sẽ không bào giờ thay đổi cả, chỉ cần thay đổi giá trị 2 biến đó thôi. Cả nhà có thể tạm hiểu là hàm này thực hiện việc chuyển tất cả dữ liệu được submit lên trên url.

Vậy là sau khi hàm dataSearch xử lý xong, sẽ chuyển dữ liệu về action “search” trong products_controller. Lúc này sẽ tồn tại một biến mảng “$this->passedArgs” chứa dữ liệu của trang search khi submit. Hay nói đúng hơn biến “$this->passedArgs” chứa các dữ liệu được truyền ở phía trên url và đưa vào thành các mảng tương ứng. Ta sẽ xử lý dữ liệu truyền vào để tạo điều kiện lọc như sau:

/*  app/controllers/products_controller.php */

<?php
class ProductsController extends AppController {

var $name = ‘Products’;
var $scaffold;

function search()
{
$conditions = array();
if (!empty($this->passedArgs))
{
if (isset($this->passedArgs['Search.name']))
{
$conditions[]["Product.name LIKE"] = “%{$this->passedArgs['Search.name']}%”;
$this->data['Search']['name'] = $this->passedArgs['Search.name'];
}

if (isset($this->passedArgs['Search.price']))
{
$conditions[]["Product.price "] = $this->passedArgs['Search.price'];
$this->data['Search']['price'] = $this->passedArgs['Search.price'];
}

if (isset($this->passedArgs['Search.model']))
{
$conditions[]["Product.model"] = $this->passedArgs['Search.model'];
$this->data['Search']['model'] = $this->passedArgs['Search.model'];
}

if (isset($this->passedArgs['Search.type']))
{
$conditions[]["Product.type"] = $this->passedArgs['Search.type'];
$this->data['Search']['type'] = $this->passedArgs['Search.type'];
}
}

$this->paginate = array(‘limit’ => ‘1′, ‘order’ => ‘Product.created DESC’);
$this->set(‘products’, $this->paginate(‘Product’, $conditions));

}

function dataSearch()
{
// the page we will redirect to
$url['controller'] = ‘products’;
$url['action'] = ’search’;

// build a URL will all the search elements in it
// the resulting URL will be
// example.com/cake/posts/index/Search.keywords:mykeyword/Search.tag_id:3
foreach ($this->data as $k=>$v){
foreach ($v as $kk=>$vv){
$url[$k.'.'.$kk]=$vv;
}
}

// redirect the user to the url
$this->redirect($url, null, true);
}
}
?>

Trong phần controller này ta sẽ thưc hiện phân trang như bình thường trong cakephp, chỉ khác là sẽ có thêm điều kiện tìm kiếm như ở phía trên thôi.

Việc tiếp theo sẽ là hiển thị kết quả tìm kiếm ra trang search. Ta sẽ thêm vào view search như sau:

/*  app/views/products/search.ctp */

<?php
echo $form->create(‘Search’, array(‘url’ => ‘/products/dataSearch’));
echo $form->input(‘name’);
echo $form->input(‘price’);
echo $form->input(‘model’);
echo $form->input(‘type’, array(‘options’ => array(” => ”,’Loai 1′ => ‘Loại 1′, ‘Loai 2′ => ‘Loại 2′, ‘Loai 3′ => ‘Loai 3′)));
echo $form->input(‘description’);
echo $form->end(‘Search’);

?>

<?php
echo $paginator->counter(array(
‘format’ => ‘Page %page% of %pages%, showing %current% records out of
%count% total, starting on record %start%, ending on %end%’
));
?>
<table cellpadding=”1″ cellspacing=”0″>
<tr>
<th>ID</th>
<th>Name</th>
<th>Model</th>
<th>Price</th>
<th>Created</th>
<th>Type</th>
<th>Description</th>
</tr>
<?php
foreach ($products as $product)
{
?>
<tr>
<td><?=$product['Product']['id']?></td>
<td><?=$product['Product']['name']?></td>
<td><?=$product['Product']['model']?></td>
<td><?=$product['Product']['price']?></td>
<td><?=$product['Product']['created']?></td>
<td><?=$product['Product']['type']?></td>
<td><?=$product['Product']['description']?></td>
</tr>
<?php
}
?>
</table>

<!– Shows the next and previous links –>

<?php
$paginator->options(array(‘url’ => $this->passedArgs));
echo $paginator->prev(‘« Previous ‘);
echo $paginator->numbers();
echo $paginator->next(‘ Next »’);
?>

Trong phần view trên thì dòng quan trọng nhất chính là “$paginator->options(array(‘url’ => $this->passedArgs));”. Dòng này có tác dụng là sẽ truyền toàn bộ các tham số trong mảng “$this->passedArgs” lên trên url của các link phân trang trong cake. Như vậy có nghĩa là các điều kiện tìm kiếm sẽ vẫn còn khi mọi người chuyển trang. Vậy là tôi đã thực hiện xong việc phân trang tìm kiếm trong cakephp1.2 rồi. Mọi người vào đọc thấy có gì thấy khó hiểu thì comment vào nhé. Tôi sẽ sửa lại cho dễ hiểu hơn.

Chúc cả nhà vui vẻ với cakephp nhé.


Triển khai Latex

Posted By hoangnd on July 9, 2009

Sử dụng Latex sẽ đá bay những vấn đề khó khăn gặp phải khi cần hiển thị những công thức toán học như căn bậc n, hàm số, tích phân… trên website.

Với những yêu cầu hiển thị thông thường trên website, blog, wiki thì định dạng text đã thỏa mãn được gần hết, khó khăn ở chỗ những bài viết chuyên ngành toán, lý… cần thể hiện những công thức tính toán phức tạp thì text hay thậm chí là ảnh cũng pó tay, hhuh? Vậy phải lèm seo?

Đồng thanh hô nèo

LaTeX

là gì? không phải word processor, mà là ” document markup language and document preparation system for the TeX typesetting program. Within the typesetting system, its name is styled as \LaTeX” (-wikipedia).

chào hàng thế thôi, thông tin đầy đủ có ở đây và ở đây :D

để làm gì? tất nhiên là để hỗ trợ gõ – chuyển đổi – hiển thị công thức toán học trên website.

  • gõ tức là phải … tự gõ, cũng có nghĩa là có cú pháp & định dạng riêng, cũng có nghĩa là miễn gõ tùm lum, như vậy là phải học gõ ke ke.
  • chuyển đổi nôm na như là dịch, dịch đống ký tự mình gõ sang đống gì đó mà máy nó hiểu, mà phải làm cho máy nó hiểu thì nó mới chạy được.
  • hiển thị đơn giản là show hàng, hàng là cái cục (thường là ảnh) mà máy nó trả về sau khi nó ‘chạy’, nhớ là nó ‘chạy’ được thì nó phải hiểu, để nó hiểu thì mình phải ra lệnh, ra lệnh xong phải có thằng nó dịch lệnh mình cho máy :) ) :) )

ví dụ cái,

  1. gõ như này đây [code][tex]a^2 + b^2[/tex][/code]
  2. dịch dịch dịch dịch dịch …. bịch bịch bịch …
  3. hiển thị cái này

eh, ai thèm xài cái này? thì thầy cô giáo, chuyên gia, guru viết bài giảng, blog kỹ thuật hay sinh viên thảo luận trên diễn đàn … nghe pro^` vãi :) ) :) )

xài ra làm sao? có mới xài được chứ =)). Hiển nhiên là muốn có thì phải lao động :P

bỏ qua các dịch vụ sẵn có, mình đi mua đồ về tự nấu cho nó chủ động & ngon lành. bếp = server, đồ ăn = các gói cài đặt và đầu bếp = ai đang đọc :) ) :) )

thực hiện nấu nướng

đi chợ nhớ mua các gói sau

ubuntu server

[code]sudo apt-get install texlive texmaker[code]

centOS 5.x

[code]yum install tetex tetex-fonts tetex-dvips tetex-latex ghostscript

yum install ImageMagick[code]
(cài imageMagick nếu chưa có)

dung lượng kiếm về khoảng 60 - 200M, chế biến cài đặt xong khoảng 200M :) ) :) ) vãi hàng, nấu cho cả xóm ăn.

xong rùi thì chiến thôi, kiếm thêm gia vị & bày bàn. giả sử tại VPS này có thư mục tên latex trong /var/www/html. trong đó có 2 thư mục pictures & tmp, quan trọng nữa là 2 file php class.latexrender.php và latex.php. Như vậy là ngon rồi, viết them file demo.php nữa để test thôi, nhớ là phải refer đến 2 file trên.

[bonus]

trên đây là bộ latex render viết bằng code php, tác giả là Benzamin Mayer (http://www.mayer.dial.pipex.com/tex.htm), xài ngon, được làng xóm đánh giá cao. khi sử dụng chỉ cần để ý đến các tham số cơ bản sau trong file latex.php

  • $latexrender_path = "đường dẫn chứa bộ latex render (gồm file class.latexrender.php)";
  • $latexrender_path_http = "đường dẫn hiển thị website" - phải chính xác để có thể show ảnh công thức được render.
  • $imageformat = "định dạng ảnh - png hoặc gif" - có nghĩa là phải có thư viện render ảnh trên server, đang xài ImageMagick.

[/bonus]

tóm tắt hoạt động

để hình thành công thức, người dùng phải gõ nội dung theo quy tắc định trước của latex. khi dữ liệu gửi đi, regular expression sẽ được gọi để bóc tách các phần chính trong nội dung nhận được để render ra dưới dạng ảnh, lưu vào một vị trí trên server & đặt đường dẫn hiển thị trên website.

tham khảo thêm

  • trang chủ dự án latex: http://www.latex-project.org/guides/
  • trên wiki: http://en.wikipedia.org/wiki/LaTeX
  • thư viện của mayer: http://www.mayer.dial.pipex.com/tex.htm
  • một bài hướng dẫn hay: http://www.linuxjournal.com/article/7870
  • demo: http://khuvuc.com/demo.php (/var/www/html/latex)

Actionscript 3 coding conventions and best practices

Posted By ngocbd on July 5, 2009

http://opensource.adobe.com/wiki/display/flexsdk/Coding+Conventions

Liên kết dữ liệu trong CakePHP

Posted By tungnd on July 4, 2009

hello ngày mới…

hôm nay tôi xin giới thiếu cho những bạn đang và sắp học CakePHP về chức năng liên kết dữ liệu của Cake.

Chắc hẳn các bạn cũng đã biết việc liên kết dữ liệu gồm có 3 loại liên kết : Một – Một, Một – Nhiều,  Nhiều – Nhiều.

Công việc liên kết này khá phức tạp, làm theo cách thủ công thì ta phải liên kết các bảng dữ liệu với nhau trong cơ sở dữ liệu,điều này thì không khó lắm. Nhưng đâu đầu là ở chỗ sau đó ta phải viết hàng loạt các câu query để join các dữ liệu với nhau, nào là Join, Inner Join, Left Join, Right Join…. Riêng việc nhớ mấy câu lệnh này đã đủ tung thủ rồi chứ đừng nói đến việc nghĩ sao join cho dúng.

Nhưng giờ đây, bạn dùng Cake thì sẽ không phải ghi nhớ những câu lệnh chết tiết ấy, Cake đã làm thay cho bạn công việc đó.

Công việc của bạn bây giờ chỉ là khai báo cho Cake biết bạn định liên kết dữ liệu của bảng nào với bảng nào thôi.

Điều đó được thực hiện trong Models,cụ thể như sau :

Liên kết Một – Một (1-1) :

đầu tiên, ta tạo 2 bảng CSDL liên kết với nhau trong MySQL.

sau đó bạn tạo Model User với nội dung như sau :

<?php
class User extends AppModel {
    var $name = 'User';
    var $hasOne = 'Profile';
}
?>

*Chú ý : tất cả thì chắc bạn đã rõ rồi, chỉ có var $hasOne = ‘Profile’; dòng chắc vẫn mù mờ, tôi giải thích như sau :

-$hasOne : câu lệnh liên kết 1-1.

-‘Profile’ : tên models chứa bảng liên kết đến.

Tiếp đến, trong Users_controller ta sử dụng câu lệnh :

<?php
class UsersController extends AppController {
    var $name = 'Users';
    function index()
    {
        $this->set('user',$this->User->find());
    }
?>

Như vậy là khi debug($user) ta sẽ thấy cấu trúc dữ liệu được gọi như sau :

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

Liên kết Một – Nhiều (1-m) :

Việc đầu tiên cũng vẫn là tạo bảng cơ sở dữ liệu trong MySQL.

Liên kết 1-m có vẻ đặc biệt hơn 2 liên kết còn lại. Ví dụ bạn có 2 bảng CSDL là News và Categories.

Theo logic liên kết thì, 1 category sẽ có nhiều bản ghi new, và 1 bản ghi new chỉ thuộc 1 category. Do đó liên kết sẽ là categories là 1 và news là nhiều.

Trong trường hợp bạn chọn bảng Categories để liên kết thì ta sẽ sử dụng câu lệnh 1-m : hasMany.

trong Model Category thêm câu lệnh : var $hasMany = ‘New’;


<?php
 class Category extends AppModel
 {
 	var $name="Category";
        var $hasMany = 'New';
 }
?>

Ngược lại, bạn chon bảng News để liên kết thì sẽ là m-1 : belongsTo.

trong Model New thêm câu lệnh : var $hasMany = ‘Category’;


<?php
 class News extends AppModel
 {
 	var $name="New";
        var $hasMany = 'Category';
 }
?>

giải thích về câu lệnh thì cũng như trên, tôi không cần phải nói lại nhé.

Như vậy, thì bạn sử dụng câu lệnh

$this->set('category',$this->Category->find());

trong Categories_controller, khi debug($category) bạn sẽ thấy mảng dữ liệu như sau :

Array
(
    [Category] => Array
        (
            [id] => 11
            [name] => gia dinh & be
        )

    [News] => Array
        (
            [0] => Array
                (
                    [id] => 54
                    [category_id] => 11
                    [title] => bi hai chuyen o vien nhi
                    [pic] =>
                    [content] => bi hai chuyen o vien nhi
                )

            [1] => Array
                (
                    [id] => 53
                    [category_id] => 11
                    [title] => khi nao ko nen cho be bu
                    [pic] =>
                    [content] => khi nao ko nen cho be bu
                )

        )

)

còn khi bạn sử dụng câu lệnh tương tự trong News_controller thì sẽ có kết quả như sau :

Array
(
    [News] => Array
        (
            [id] => 61
            [category_id] => 15
            [title] => nam hoc moi
            [pic] => 7b0b5e66db4e6e4e17162cb8eb7248cdimg_hello.jpg
            [content] =>

    * bcbcb
    * truong mam non ban cong huong duong ung dung tin hoc trong giang day

            [lang] => 0
        )

    [Category] => Array
        (
            [id] => 15
            [name] => thong tin tuyen sinh
            [lang] => 0
        )

)

bạn có thể để ý câu lẹnh của Cake hiện ra ở dưới cùng, qua đó bạn có thể thấy, để có được kết quả này Cake đã phải thực hiện bao nhiêu câu query. Thử xem không sử dụng Cake thì bạn sẽ phải vật lộn với 1 mớ Select như thế nào ??

Liên kết Nhiều – Nhiều (n-m) :

Liên kết n-m nếu không có Cake thì ôi thôi, quá phức tạp. Bạn chỉ có thể liên kết n-m với nhau thông qua 1 bảng trung gian. Lấy ví dụ : tôi muốn liên kết bảng Users và bảng Groups với nhau thông qua bảng Groups_Users.

Trong bản Group_Users sẽ có Group_id và User_id.

Khi này, trong Model ta sẽ phải khai báo thêm câu lệnh để liên kết : hasAndBelongsToMany.

ở models Group :

<?php
	class Group extends AppModel {
	    var $name = 'Group';
	    var $useTable = 'groups';
	    );
	    var $hasAndBelongsToMany = array(
	            'User' => array('className' => 'User',
	                        'joinTable' => 'groups_users',
	                        'foreignKey' => 'group_id',
	                        'associationForeignKey' => 'user_id',
	                        'unique' => true
	            )
	    );
	}

?>

tại models User :

<?php
    class User extends AppModel {
        var $name = 'User';
        var $hasAndBelongsToMany = array(
                'Group' => array('className' => 'Group',
                            'joinTable' => 'groups_users',
                            'foreignKey' => 'user_id',
                            'associationForeignKey' => 'group_id',
                            'unique' => true
                )
        );
?>

không hề phải quá loằng ngoằng phức tạp tý nào, chỉ với vài dòng code trên 2 bảng Groups và Users đã liên kết n-m với nhau thông qua bảng Groups_users. Việc tiếp theo thì quá đơn giản, bạn lại find() và debug để xem kết quả liên kết thôi :

-Tại Groups_controller :  $this->set(‘group’,$this->Group->find());

-> kết quả :

Array
(
    [Group] => Array
        (
            [id] => 1
            [name] => Toàn Quyền
        )

    [User] => Array
        (
            [0] => Array
                (
                    [id] => 12
                    [acc] => tungnd
                    [psword] => 81379f1d1e62c9a1291708e526f3b062591de0a4
                    [name] => fdsf
                    [email] => fds
                    [address] => ds
                    [active] => 1
                )

        )

)

-tại Users_controller : $this->set (‘user’, $this->User->find());

Array
(
    [User] => Array
        (
            [id] => 12
            [acc] => tungnd
            [psword] => 81379f1d1e62c9a1291708e526f3b062591de0a4
            [name] => fdsf
            [email] => fds
            [address] => ds
            [active] => 1
        )

    [Group] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [name] => Toàn Quyền
                )
        )
)

Như vậy là tôi đã giới thiệu xong cho bạn 3 loại liên kết dữ liệu trong Cake, việc của bạn bầy giờ là hãy đọc lại, viết lại giống như tôi và biến đổi các câu lệnh find(), vận dụng linh hoạt theo ý mình.

Chúc bạn thành công……………………

Element, Component trong CakePHP

Posted By tungnd on July 2, 2009

Element :

trong CakePHP, Element được sử dụng khá giống với “include”. Nó dùng để lưu trữ 1 đoạn code được dùng đi dùng lại nhiều lần, thay vì ta phải copy/paste  đoạn code đó qua các trang thì ta chỉ việc viết 1 câu lệnh ngắn gọn :

<?php echo $this->renderElement('<elementName>');?>

chỉ như cần 1 đoạn code như vậy ta có thể thay thế việc vất vả copy rồi paste liên tục, mất thời gian lại khiến code của bạn nhìn rất tối, khó chỉnh sửa sau này !

VD cụ thể như sau :

trong controller của bạn, bạn thực hiện thêm công việc kiểm tra xem element có được gọi hay ko :

function index() {
            $posts = $this->Session->setFlash('hello world');
            if (isset($this->params['requested']))
            {
                return $posts;
            }
        }

Nếu Element được gọi, giá trị giả về sẽ là dòng text ‘hello world’. (bạn cũng có thể thay thế bằng những câu lệnh theo ý của bạn như :  find(), read() …..)

tiếp theo, trong app\views\element\ chúng ta tạo 1 file php, tên tùy ý bạn đặt. Ở ví dụ này tôi đặt tên là test.php :

<?php
$posts = $this->requestAction('posts/index');
echo $posts;

?>

Trong file này, câu lệnh  $this->requestAction(‘posts/index’) là bắt buộc phải có,đây là câu lệnh lấy giá trị được trả về từ controler trên.

Cuối cùng là công việc cho hiển thị element ta vừa tạo được ra trang index, đó là câu lệnh thay thế việc copy/paste mà tôi đã nói ở trên :

<?php echo $this->renderElement('posts');?>

Nếu bạn vẫn cảm thấy khó hiểu và không biết làm thế nào để hiển thị các bản ghi trong CSDL của mình ra thay cho đoạn text ‘hello world’ thì bạn có thể tham khảo thêm bài viết của hoanbn : http://i-php.net/2008/11/s%E1%BB%AD-d%E1%BB%A5ng-element-trong-cakephp/

Component :

Component là nơi thực hiện các công việc phức tạp như upload…, nó cũng được dùng đi dung lại nhiều lần ! thay vì việc copy/paste lại công việc thực thi đó ta chỉ cần truyền dữ vào cho Component từ controller. Sau đó dữ liệu sẽ được đưa đến Component xử lý .

VD :

trong app\views\posts\ ta tạo file index.ctp (cakephp 1.2) hay index.thtml (cakePHP 1.1)

<h1>hello</h1>
<?php
    echo $form -> create('Post',array('action'=>'index'));
    echo $form -> input('text');
    echo $form -> end('save');
?>

trong app\controller\components\ ta tạo 1 file php tên j` j` đó chẳng hạn như : test.php

<?php
class TestComponent extends Object	{

	function startup(&$controller)	{
		// This method takes a reference to the controller which is loading it.
        // Perform controller initialization here.

	}
	function hello($text)	{
		return $text;
	}
}
?>

cuối cung, trong post controller ta chỉ việc truyền dữ liệu text vào để component xử lý :

function index() {
            if (!empty($this->data))
            {
                if($this->test->hello($this->data['Post']['text']))
                {
                    $this->Session->setFlash($this->test->hello($this->data['Post']['text']));
                    $this->redirect (array('action' => 'index'));
                }

            }
        }

chú ý : test là tên file component bạn tạo ở trên, hello là tên function thực thi mệnh lệnh, còn

$this->data['Post']['text'] là dữ liệu bạn nhập vào !

bây giờ bạn có thể xem kết quả mình vừa tạo ra….!

hi vọng là chạy được :D