实现无限级分类一般只用一个数据表,通常可通过递归和非递归两种方法来实现。递归方法必须使用递归调用方式才能进行数据遍历,删除等操作,所以需要发送多次查询数据库语句,非常影响执行效率。那么非递归该怎样来实现无限分类呢?简单来说可用一张表四个字段和一条语句来实现。
1、一张表四个字段
1 | DROP TABLE IF EXISTS `wb_columns`; |
2 | CREATE TABLE `eway_columns` ( |
3 | `colId` smallint (5) unsigned NOT NULL AUTO_INCREMENT, |
4 | `colPid` smallint (5) unsigned NOT NULL DEFAULT '0' , |
5 | `colPath` varchar (100) NOT NULL DEFAULT '' , |
6 | `colTitle` varchar (100) NOT NULL DEFAULT '' , |
7 | PRIMARY KEY (`colId`), |
8 | KEY `colPath` (`colPath`) |
9 | ) ENGINE=MyISAM CHARSET=utf8; |
2、一条语句
1 | SELECT concat(colPath, '-' ,colId) AS bpath, colId,colPid,colPath, colTitle, FROM " . C('DB_PREFIX') . " columns ORDER BY bpath, colId; |
在上面的一条语句的SQL查询中,使用MYSQL中的concat函数将colPath和colId字段通过字符"-"连接起来,并将该字段设置为bpath别名。然后先通过bpathpb 字段进行排序,如果有相同的路径再通过colId字段进行排序,这样就会以分类的各级层次结构将结果返回。
下面是在thinkphp3.1中非递归无限级分类的实现代码
01 | <?php |
02 | /** |
03 | * 分类Columns的控制器ColumnsAction.class.php |
04 | */ |
05 | class ColumnsAction extends Action{ |
06 | //分类列表 |
07 | public function index(){ |
08 | |
09 | $catarray = $this ->Catlist(); |
10 | |
11 | $this ->assign( 'catarray' , $catarray ); |
12 | |
13 | $this ->display(); |
14 | } |
15 | |
16 | //分类添加表单 |
17 | public function insert() { |
18 | $catarray = $this ->Catlist(); |
19 | |
20 | $this ->assign( 'catarray' , $catarray ); |
21 | |
22 | $this ->display(); |
23 | |
24 | } |
25 | |
26 | public function add() { |
27 | $D = D( $module ); |
28 | if ( $vo = $D ->create()) { //因为使用模型类处理,自动完成必须通过create方法才能生效。 |
29 | $list = $D ->add(); |
30 | if ( $list !==false) { |
31 | $this ->success( "添加成功" ); |
32 | } else { |
33 | $this ->error( '添加失败' ); |
34 | } |
35 | |
36 | } else { |
37 | $this ->error( $D ->getError()); |
38 | } |
39 | } |
40 | //实现树型层级的分类 |
41 | function Catlist() { |
42 | $Columns = new Model; |
43 | $Module = M( "News" ); |
44 | $list = $Columns ->query( "SELECT concat(colPath,'-',colId) AS bpath, colId,colPid,colPath, colTitle, FROM " . C( 'DB_PREFIX' ) . "columns ORDER BY bpath, colId" ); |
45 | |
46 | foreach ( $list as $k => $v ) { |
47 | $list [ $k ][ 'count' ] = count ( explode ( '-' , $v [ 'bpath' ])); |
48 | $list [ $k ][ 'total' ] = $Module ->where( 'catid=' . $v [ 'colId' ])-> count (); |
49 | $str = '' ; |
50 | if ( $v [ 'colPid' ] <> 0) { |
51 | for ( $i = 0; $i < $list [ $k ][ 'count' ] * 2; $i ++) { |
52 | $str .= ' ' ; |
53 | } |
54 | $str .= '|-' ; |
55 | } |
56 | $list [ $k ][ 'space' ] = $str ; |
57 | } |
58 | |
59 | return $list ; |
60 | } |
61 | |
62 | |
63 | /** |
64 | * 分类Columns的模型类ColumnsModel.class.php |
65 | * 作用:在添加分类或修改分类时自动处理colPath字段并保存到数据库中 |
66 | * callback :回调方法 ,表示填充的内容是一个当前模型的方法 |
67 | * Model:: MODEL_INSERT 或者1新增数据时候验证 |
68 | * Model:: MODEL_UPDATE 或者2编辑数据时候验证 |
69 | * Model:: MODEL_BOTH 或者3 全部情况下验证(默认),这里选择该验证。 |
70 | */ |
71 | <?php |
72 | class ColumnsModel extends Model{ |
73 | protected $_auto = array ( //thinkphp的自动填充 |
74 | array ( 'colPath' , 'colPath' ,3, 'callback' ), |
75 | |
76 | ); |
77 | |
78 | function colPath(){ |
79 | $colPid =isset( $_POST [ 'colPid' ])?(int) $_POST [ 'colPid' ]:0; |
80 | $colId = $_POST [ 'colId' ]; |
81 | if ( $colPid ==0){ |
82 | return 0; |
83 | } |
84 | |
85 | $fat = $this ->where( 'colId=' . $colPid )->find(); //查询的是父级ID |
86 | $data = $fat [ 'colPath' ]. '-' . $fat [ 'colId' ]; //得到父级的colPath,连上父级ID,返回的是子级的colPath |
87 | return $data ; |
88 | } |
89 | } |
需要注意的是,这是使用模型的自动完成功能,所以必须通过create方法才能生效,Create方法创建的数据对象是保存在内存中,并没有实际写入到数据库中,直到使用add方法才真正写入数据库中。