实现无限级分类一般只用一个数据表,通常可通过递归和非递归两种方法来实现。递归方法必须使用递归调用方式才能进行数据遍历,删除等操作,所以需要发送多次查询数据库语句,非常影响执行效率。那么非递归该怎样来实现无限分类呢?简单来说可用一张表四个字段和一条语句来实现。
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方法才真正写入数据库中。