Aug
12

Tạo danh mục đa cấp với behavior Tree

Author admin    Category Chia sẻ, Tutorial     Tags ,

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']; ?>&nbsp;</td>
		<td><?php echo $productCategory['ProductCategory']['name']; ?>&nbsp;</td>
		<td><?php echo $productCategory['ParentCat']['name']; ?>&nbsp;</td>
		<td><?php echo $productCategory['ProductCategory']['published']; ?>&nbsp;</td>
		<td><?php echo $productCategory['ProductCategory']['created']; ?>&nbsp;</td>
		<td><?php echo $productCategory['ProductCategory']['updated']; ?>&nbsp;</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

Danh sách danh mục

2. Form thêm danh mục

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”

  • gui admin 27/09/2010 at 10:31 pm

    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.

  • admin 06/10/2010 at 2:48 pm

    - 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

  • Thái Thanh Phong 28/04/2011 at 11:22 am

    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 :( (

  • admin 28/04/2011 at 10:22 pm

    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?

  • datgs 09/05/2011 at 9:30 am

    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ì?

  • tungnd 08/08/2011 at 1:42 pm

    Nếu mình xóa các parent Laptop hoặc Thiết bị mạng đi thì sao?

  • admin 04/09/2011 at 6:38 pm

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

  • phùng ngọc lan 12/11/2011 at 8:45 pm

    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ỉ ?

  • admin 14/11/2011 at 4:55 pm

    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!

Post comment

Follow us on Twitter! Follow us on Twitter!
Diễn đàn CakePHP cho người Việt Nam

Bài viết mới

Thảo luận mới

TAG

Calendar

August 2010
M T W T F S S
« Jul   Sep »
 1
2345678
9101112131415
16171819202122
23242526272829
3031  

Lưu trữ

Blogroll

Thống kê

Danh sách: 4 khách