Thứ Sáu, 24 tháng 7, 2009

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

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é.





























7 nhận xét:

  1. Thực ra để tạo ra view không cần phải chỉ định bảng cũng được.
    P/a 1 bạn tự viết 1 form thuần html
    P/a 2: dùng Form helper của cake nhưng trong hàm create() viết lại với cú pháp như sau(ở đây mình viết theo cake 1.3)

    create(null,array('url'=>'/products/dataSearch'))

    như thế cake sẽ tự động generate to html as below

    Trả lờiXóa
  2. chao ban ban co the huong dan cho minh cach phan quyen trong cake php khong minh dang lam phan do ma chua biet lam the nao ca ban giup minh som nhe minh dang can gap

    Trả lờiXóa
  3. chào bạn, cám ơn bạn đã chỉ dẫn.Mình thắc mắc là mỗi controller đều cần có model đi kèm, sao ở ví dụ này mình không thấy có model mà vẫn chạy được?Cám ơn bạn!

    Trả lờiXóa
  4. một người thấy chán thì kêu01:13 9 tháng 6, 2010

    hình như bạn hướng dẫn làm bài này đang bị vợ nhốt trong phòng rồi hay sao ấy mà sao mọi người ý kiến nhiều vậy mà chẳng thấy nói năng gì chán thật

    Trả lờiXóa
  5. chủ topic mới lấy vợ thật :D
    Lỗi model product dòng 9 kìa bạn.

    Trả lờiXóa
  6. Thanks alot! :D mình tìm cái này mãi mà không thấy> thanks

    Trả lờiXóa
  7. Xin admin cho mình hỏi, muốn dùng Routes để viết lại link khi phân trang thì phải làm như thế nào. Hiện tại mình làm phần search thì kết quả trang 1 ok, nhưng qua trang 2 thì link khác.

    Admin hỗ trợ giúp nha

    Trả lờiXóa