Tạo danh mục đa cấp với behavior Tree
Hôm nay tôi sẽ hướng dẫn các bạn làm một danh mục đa cấp sử dụng behavior Tree của CakePHP
Đầu tiên, bạn chạy câu sql sau để tạo bảng chứa danh mục sản phẩm
–
– Table structure for table `product_categories`
–
CREATE TABLE IF NOT EXISTS `product_categories` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(150) NOT NULL, `parent_id` int(11) NOT NULL, `published` tinyint(1) NOT NULL, `created` datetime NOT NULL, `updated` datetime NOT NULL, `lft` int(11) NOT NULL, `rght` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; |
Bạn chú ý, table này có 3 trường quan trọng sau:
- parent_id: giữ id của danh mục cha
- lft: giữ giá trị bên trái của danh mục
- rght: giữ giá trị bên phải của danh mục
Bạn nào học về thuật toán duyệt cây sẽ hiểu về 2 trường lft và rght
1. Model
- Tạo model product_category.php
- Code:
<?php class ProductCategory extends AppModel { var $name = 'ProductCategory'; var $displayField = 'name'; var $actsAs = array('Tree'); var $validate = array( 'name' => array( 'notempty' => array( 'rule' => array('notempty'), //'message' => 'Your custom message here', //'allowEmpty' => false, //'required' => false, //'last' => false, // Stop validation after this rule //'on' => 'create', // Limit validation to 'create' or 'update' operations ), ), 'published' => array( 'numeric' => array( 'rule' => array('numeric'), //'message' => 'Your custom message here', //'allowEmpty' => false, //'required' => false, //'last' => false, // Stop validation after this rule //'on' => 'create', // Limit validation to 'create' or 'update' operations ), ) ); var $belongsTo = array( 'ParentCat' => array( 'className' => 'ProductCategory', 'foreignKey' => 'parent_id' ) ); } ?> |
Bạn chú ý khai báo:
var $actsAs = array('Tree'); |
và đoạn thiết lập quan hệ để lấy tên danh mục cha hiển thị lên danh sách
var $belongsTo = array( 'ParentCat' => array( 'className' => 'ProductCategory', 'foreignKey' => 'parent_id' ) ); |
2. Controller
- Tạo controller product_categories_controller.php
- Code:
<?php class ProductCategoriesController extends AppController { var $name = 'ProductCategories'; function index() { $this->ProductCategory->recursive = 0; $this->set('productCategories', $this->paginate()); } function add() { if (!empty($this->data)) { $this->ProductCategory->create(); if ($this->ProductCategory->save($this->data)) { $this->Session->setFlash(__('The product category has been saved', true)); $this->redirect(array('action' => 'index')); } else { $this->Session->setFlash(__('The product category could not be saved. Please, try again.', true)); } } $this->set('list_cat',$this->_find_list()); } function _find_list() { return $this->ProductCategory->generatetreelist(null, null, null, '__'); } } ?> |
Chú ý hàm lấy danh sách danh mục để đưa vào list:
function _find_list() { return $this->ProductCategory->generatetreelist(null, null, null, '__'); } |
Ở đây mình chỉ tạo 2 hàm index và add, các hàm khác các bạn tự làm thêm
3. View
- Tạo view cho 2 action index và add ở trên
- index.ctp
<div class="productCategories index"> <h2><?php __('Product Categories');?></h2> <table cellpadding="0" cellspacing="0"> <tr> <th><?php echo $this->Paginator->sort('id');?></th> <th><?php echo $this->Paginator->sort('name');?></th> <th><?php echo $this->Paginator->sort('parent_id');?></th> <th><?php echo $this->Paginator->sort('published');?></th> <th><?php echo $this->Paginator->sort('created');?></th> <th><?php echo $this->Paginator->sort('updated');?></th> <th class="actions"><?php __('Actions');?></th> </tr> <?php $i = 0; foreach ($productCategories as $productCategory): $class = null; if ($i++ % 2 == 0) { $class = ' class="altrow"'; } ?> <tr<?php echo $class;?>> <td><?php echo $productCategory['ProductCategory']['id']; ?> </td> <td><?php echo $productCategory['ProductCategory']['name']; ?> </td> <td><?php echo $productCategory['ParentCat']['name']; ?> </td> <td><?php echo $productCategory['ProductCategory']['published']; ?> </td> <td><?php echo $productCategory['ProductCategory']['created']; ?> </td> <td><?php echo $productCategory['ProductCategory']['updated']; ?> </td> <td class="actions"> <?php echo $this->Html->link(__('View', true), array('action' => 'view', $productCategory['ProductCategory']['id'])); ?> <?php echo $this->Html->link(__('Edit', true), array('action' => 'edit', $productCategory['ProductCategory']['id'])); ?> <?php echo $this->Html->link(__('Delete', true), array('action' => 'delete', $productCategory['ProductCategory']['id']), null, sprintf(__('Are you sure you want to delete # %s?', true), $productCategory['ProductCategory']['id'])); ?> </td> </tr> <?php endforeach; ?> </table> <p> <?php echo $this->Paginator->counter(array( 'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true) )); ?> </p> <div class="paging"> <?php echo $this->Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?> | <?php echo $this->Paginator->numbers();?> | <?php echo $this->Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?> </div> </div> |
- add.ctp
<div class="productCategories form"> <?php echo $this->Form->create('ProductCategory');?> <fieldset> <legend><?php __('Add Product Category'); ?></legend> <?php echo $this->Form->input('name'); echo $this->Form->input('parent_id',array('type'=>'select','options'=>$list_cat,'empty'=>'--Choose parent--')); echo $this->Form->input('published'); ?> </fieldset> <?php echo $this->Form->end(__('Submit', true));?> </div> |
Một số hình ảnh minh họa:
1. Danh sách
2. Form thêm danh mục
Trên đây mới là hướng dẫn cơ bản, bạn có thể làm nhiều thứ với cái behavior Tree này, chẳng hạn: sắp xếp thứ tự hiển thị của danh mục (di chuyển lên, di chuyển xuống), tìm danh mục con, tìm danh mục cha, tạo path tới 1 danh mục nào đó…
Các bạn xem thêm tại: http://book.cakephp.org/view/1339/Tree
11 Comments to “Tạo danh mục đa cấp với behavior Tree”
Post comment
Bài viết mới
- CakePHP version 1.3.12
- Tạo chuỗi ngẫu nhiên với 1 dòng code
- Kỹ thuật “bit field” trong phân quyền
- Làm việc với File và Folder
- CakePHP 1.3.8
- CakePHP 1.3.7 Released
- Ajax trong CakePHP
- Tạo và load file config trong CakePHP
- Làm site đa ngôn ngữ với CakePHP (Phần 1)
- CakePHP 1.3.6 and 1.2.9 released
- CakePHP 1.3.5 released
- Type hinting trong PHP
- CakePHP ra phiên bản mới 1.3.4
- Tích hợp Zend framework vào CakePHP
- Tạo virtual host trên local
- Sử dụng Acl trong cakephp – Phần 2
- Sử dụng Acl trong cakephp – Phần 1
- Sinh code tự động với cake console
- Tự động xóa record ở bảng con khi reocord ở bảng cha bị xóa
- Xác thực người dùng với component Auth
Thảo luận mới
- admin on Cách viết plugin cho CakePHP
- vinh on Xác thực người dùng với component Auth
- vinh on Sử dụng Acl trong cakephp – Phần 1
- hoaipt on Cách viết plugin cho CakePHP
- tuyền on Kỹ thuật “bit field” trong phân quyền
- admin on Tạo danh mục đa cấp với behavior Tree
- admin on Làm việc với File và Folder
- admin on Sinh code tự động với cake console
- admin on Kỹ thuật “bit field” trong phân quyền
- phùng ngọc lan on Tạo danh mục đa cấp với behavior Tree
TAG
Calendar
Lưu trữ
- September 2011 (3)
- July 2011 (1)
- March 2011 (1)
- February 2011 (1)
- November 2010 (4)
- October 2010 (1)
- September 2010 (2)
- August 2010 (9)
- July 2010 (9)
- June 2010 (22)
Blogroll
- Bakery
- Biển đảo Việt Nam
- CakePHP
- CakePHP Google Group
- CakePHP Manual
- CakePHP Questions
- Diễn đàn CakePHP VN

admin



ah cho e nhờ a với ạ.làm sao để có được đuôi .ctp khi viết code trên eclipse ạ.e ko tìm thấy định dạng file đó.Xin các anh pro chỉ dẫn giùm e ạ.e cảm ơn nh.
- Bạn vào Windows->Preferences
- Mở nhánh General ra, mở tiếp nhánh Editors, chọn mục File Associations
- Nhấn nút Add ở khung trên, gõ vào *.ctp
- Nhấn vào link Content Types ở dòng
- Chọn mục PHP Content Type ở khung trên
- Chọn nút Add, nhập vafp *.ctp
Khởi động lại eclipse
Chào bạn , cảm ơn bài viết của bạn .
Mình xin góp ý thêm cho những ai quan tâm trong chủ đề này. Mình đã viết trên phiên bản 1.7
- Nếu viết hàm : generatetreelist() thì nó sẽ báo lỗi
- Ta phải viết là : generateTreeList()
Cũng nhờ có IDE gợi nhớ , chứ tra trong menual nó cũng dùng : generatetreelist() , viết xong chạy không được
(
Mình code trên local, host windows thì nó vẫn chạy bình thường, bản 1.3.5
Làm gì có bản 1.7 bạn?
Bạn giải thích rõ các dòng sau:
- lft: giữ giá trị bên trái của danh mục
- rght: giữ giá trị bên phải của danh mục
Nếu mình chưa biết về tree sẽ không hiểu “giá trị bên trái” và “giá trị bên phải” của danh mục là giá trị gì?
Bạn xem hình này sẽ rõ, các con số đánh ở phía trái và phải của item chính là cái mà mình đang nói tới:
http://dev.mysql.com/tech-resources/articles/hierarchical-data-4.png
Vậy thì đó sẽ là các số thể hiện thứ tự duyệt cây.
Nếu mình xóa các parent Laptop hoặc Thiết bị mạng đi thì sao?
Nếu xóa parent thì sẽ có 2 kiểu ứng xử:
- Xóa con
- Đưa con lên làm cha
Bạn thử xem sao
Mình đang có 1 thắc mắc, mình tính viết 1 cái shop cơ bản nhưng hiện tại yêu cầu của nó là
danh mục A,B,C,D và sản phẩm N đều thuộc 4 danh mục đó. thì làm ntn nhỉ ?
1 sản phẩm thuộc về nhiều danh mục, 1 danh mục có nhiều sản phẩm, quan hệ nhiều-nhiều. Bạn có thể làm theo chuẩn là tạo table thứ 3 hoặc lưu category_id trong products dạng string, cách nhau bằng ký tự đặc biệt nào đó cho trường hợp sp thuộc nhiều danh mục!