数据表结构和数据
表结构
[sql] view plaincopy
php
- CREATE TABLE `classify` (
- `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
- `name` VARCHAR(20) NOT NULL COLLATE 'utf8_general_ci',
- `lft` INT(11) NOT NULL,
- `rgt` INT(11) NOT NULL,
- `parentId` INT(11) NOT NULL,
- PRIMARY KEY (`id`),
- INDEX `scope` (`lft`, `rgt`)
- )
- COLLATE='utf8_bin'
- ENGINE=InnoDB
- AUTO_INCREMENT=13;
测试数据
[sql] view plaincopy
html
- INSERT INTO `classify` VALUES (1, '郑州', 1, 16, -1);
- INSERT INTO `classify` VALUES (19, '荥阳', 10, 15, 1);
- INSERT INTO `classify` VALUES (20, '荥阳东', 13, 14, 19);
- INSERT INTO `classify` VALUES (21, '荥阳西', 11, 12, 19);
- INSERT INTO `classify` VALUES (22, '开封', 2, 9, 1);
- INSERT INTO `classify` VALUES (23, '开封东', 7, 8, 22);
- INSERT INTO `classify` VALUES (24, '开封西', 5, 6, 22);
- INSERT INTO `classify` VALUES (25, '开封府', 3, 4, 22);
文件结构
[html] view plaincopy
mysql
- /——
- |--index.php 入口文件
- |--conf.php 配置文件
- /db
- |--DB.class.php 数据库操做类
- /lib
- |--ClassifyTree.class.php 左右树操做文件【core】
index.php 代码
[php] view plaincopy
sql
- <?php
- /**
- * action
- * showAll 查看整个分类树
- * showOne 查看某个分类的子类
- * showPath 查看某个子类到根分类的路径
- * showAdd 显示增长分类的界面
- * add 增长子分类
- * delete 删除分类
- * showModify 显示修改分类信息的界面
- * modify 修改分类信息
- *
- * 假设已经有个 根分类 郑州
- */
- (isset($_GET['action']) && $action = $_GET['action'] ) || $action = 'showAll';
- header('Content-type:text/html;charset=utf-8');
-
- //实例化分类操做类
- include_once './db/DB.class.php';
- $conf = include_once './conf.php';
- include_once './lib/ClassifyTree.class.php';
- $tree = new ClassifyTree($conf);
-
- /**
- * [显示增长分类的界面]
- * @return [boolean] [插入成功,返回true;不然,返回false]
- */
- function add(){
- global $tree;
- $parentId = $_GET['parent'];
- $name = $_GET['name'];
- $result = $tree->insertNew($parentId, $name);
- return $result;
- }
-
- /**
- * [显示增长分类页面]
- */
- function showAdd(){
- $parentId = $_GET['parent'];
- echo '<form action="." method="get">';
- echo '<input type="hidden" name="action" value="add">';
- echo '<br/>名称:<input type="text" name="name" style="width:200px;">';
- echo '<input type="hidden" name="parent" value="'.$parentId.'">';
- echo '<br/><input type="submit" style="width:130px;height:25px;"></form>';
- }
-
- /**
- * [显示一个子分类下的全部分类]
- */
- function showOne(){
- global $tree;
- $id = $_GET['id'];
- $classifyInfo = $tree->getOne($id);
- //递归显示分类信息
- displayClassify($classifyInfo);
- }
-
- /**
- * [显示某个分类到根分类的路径]
- */
- function showPath(){
- global $tree;
- $id = $_GET['id'];
- $pathArr = $tree->getPath($id);
- displayPath($pathArr);
- }
-
- function getPath($id){
- global $tree;
- $pathArr = $tree->getPath($id);
- displayPath($pathArr);
- }
-
- /**
- * [显示全部的分类信息]
- * @return [type] [description]
- */
- function showAll(){
- global $tree;
- $classifyArr = $tree->getAll();
- displayClassify($classifyArr);
- }
-
- /**
- * [删除一个分类]
- * @return [boolean] [删除成功,则返回true;不然,则返回false]
- */
- function delete(){
- global $tree;
- $id = $_GET['id'];
- $result = $tree->delete($id);
- return $result;
- }
-
- /**
- * [显示修改id的界面]
- * @return [bolean] [若是查询失败,则返回false]
- */
- function showModify(){
- global $tree;
- $id = $_GET['id'];
- $info = $tree->searchById($id);
- if(false === $info){
- return false;
- }
- echo '<form action="." method="get">';
- echo '<input type="hidden" name="action" value="modify">';
- echo '名称:<input type="text" name="name" value="'.$info['name'].'" style="width:200px;height:25px;">';
- echo '<input type="hidden" name="id" value="'.$info['id'].'">';
- echo '<br/><input type="submit" style="width:120px;height:25px;">';
- echo '</form>';
- }
-
- /**
- * [修改分类信息]
- * @return [boolean] [修改为功,则返回true;不然,返回false]
- */
- function modify(){
- global $tree;
- $name = $_GET['name'];
- $id = $_GET['id'];
- $result = $tree->modify($name, $id);
- return $result;
- }
- /**
- * [输出路径数组]
- * @param [array] $path [路径数组]
- */
- function displayPath($path){
- foreach($path as $oneStep){
- echo '<a href="?action=showPath&id='.$oneStep['id'].'">'.$oneStep['name'].'</a> >> ';
- }
- }
-
- /**
- * [递归显示分类信息]
- * @param [array] $classify [分类信息]
- * @param [int] $interval [缩进长度]
- */
- function displayClassify($classify, $interval=0){
- foreach($classify as $key=>$val){
- for($i=0;$i<$interval;$i++){
- echo ' ';
- }
- echo $key;
- if(is_array($val)){
- echo ' => array(<br/>';
- displayClassify($val, $interval+1);
- indentation($interval);
- echo ')<br/>';
- }else{
- echo ' => '.$val;
- if('id' == $key){
- echo ' <a href="?action=showAdd&parent='.$val.'">增长子节点</a>';
- echo ' <a href="?action=showModify&id='.$val.'">修改节点</a>';
- echo ' <a href="?action=delete&id='.$val.'">删除节点</a>';
- echo '<br/>';
- indentation($interval);
- getPath($val);
- }
- echo '<br/>';
- }
- }
- }
-
- function indentation($interval){
- for($i=0;$i<$interval;$i++){
- echo ' ';
- }
- }
- //执行请求
- $result = $action();
-
- if(false === $result){
- echo 'failed<br/>';
- echo $tree->getError();
- }else{
- echo 'success';
- }
conf.php 文件
[php] view plaincopy
数据库
- <?php
- return array(
- 'dbHost'=>'localhost',
- 'dbName'=>'classify_infinite',
- 'dbUser'=>'root',
- 'dbPass'=>'root',
- 'dbCharset'=>'utf8'
- );
DB.class.php 文件
[php] view plaincopy
数组
- <?php
- /**
- * 数据库操做类
- * 执行数据库的增删改查操做
- */
- class DB {
- private $dbHost;//数据库主机名
- private $dbName;//数据库名称
- private $username;//数据库用户
- private $password;//数据库密码
- private $charset;//数据库字符集编码
- private $link;//数据库链接资源
- private $error = null;//错误信息
- /**
- * 构造函数
- * 根据传递进来的conf数组给局部变量赋初值
- * 链接数据库
- * @param array $conf
- */
- public function __construct($conf) {
- if(!isset($conf['dbHost']) || !isset($conf['dbName']) || !isset($conf['dbUser']) || !isset($conf['dbPass']) || !isset($conf['dbCharset'])){
- $this->error = '配置不完整';
- }else{
- $this->dbHost = $conf['dbHost'];
- $this->dbName = $conf['dbName'];
- $this->username = $conf['dbUser'];
- $this->password = $conf['dbPass'];
- $this->charset = $conf['dbCharset'];
- //链接数据库服务器
- $this->link = mysql_connect($this->dbHost,$this->username,$this->password);
- mysql_query("SET NAMES '{$this->charset}'");
- if(false === $this->link){
- $this->error = '链接数据库失败';
- }elseif(!mysql_select_db($this->dbName,$this->link)){//选择数据库
- $this->error = '链接数据库失败';
- }
- }
- }
- /**
- * 执行查询操做
- * @param string $sql 要执行的sql
- * @param [boolean] $key [若是标记为true,将结果以id为主键返回;若是标记为false,将结果以数字为主键返回]
- * @return boolean|array 若是执行出错,则记录错误,返回false;不然,返回查询获得的结果集
- */
- public function queryList($sql, $key=false){
- $resource = mysql_query($sql);
- if(false === $resource){
- $this->error = mysql_error();
- return false;
- }
- $result = array();
- while ($row = mysql_fetch_assoc($resource)) {
- if(false === $key){
- array_push($result,$row);
- }else{
- $result[$row['id']] = $row;
- }
- }
- return $result;
- }
- /**
- * [执行查询操做,返回一个结果数组]
- * @param [string] $sql [要执行的sql]
- * @return [array|false] [查询获得的结果集;若是查询出错,返回false]
- */
- public function queryOne($sql){
- $resource = mysql_query($sql);
- if(false === $resource){
- $this->error = mysql_error();
- return false;
- }
- $result = mysql_fetch_assoc($resource);
- return $result;
- }
- /**
- * 执行插入操做
- * @param string $sql 要执行的sql
- * @return boolean 若是执行出错,则记录错误并返回false;若是执行成功,则直接返回插入的数据的id
- */
- public function insert($sql){
- $result = mysql_query($sql);
- if(false === $result){
- $this->error = mysql_error();
- return false;
- }else{
- return mysql_insert_id();
- }
- }
- /**
- * 执行更新操做
- * @param string $sql 要执行的sql
- * @return boolean 若是执行出错,则记录错误信息并返回false;若是执行成功,则直接返回所影响的行数
- */
- public function update($sql){
- $result = mysql_query($sql);
- if(false === $result){
- $this->error = mysql_error();
- return false;
- }else{
- return mysql_affected_rows();
- }
- }
- /**
- * 执行删除操做
- * 调用更新操做来完成
- */
- public function delete($sql){
- return $this->update($sql);
- }
- /**
- * 获取错误信息
- * 若是错误信息不存在,则返回null
- * @return string 返回值;返回当前的错误信息
- */
- public function getError(){
- return $this->error;
- }
- public function __destruct(){
- mysql_close($this->link);
- }
- /**
- * 开启事务
- */
- public function begin()
- {
- mysql_query('begin');
- }
- /**
- * 事务回滚
- */
- public function rollBack()
- {
- mysql_query('rollback');
- }
- /**
- * 事务提交
- */
- public function submit()
- {
- mysql_query('commit');
- }
- }
ClassifyTree.class.php 文件
[php] view plaincopy
服务器
- <?php
- class ClassifyTree
- {
- private $db;
- private $error;
- public function __construct($conf){
- $this->db = new DB($conf);
- $this->error = $this->db->getError();
- }
- /**
- * [返回错误信息]
- * @return [string] [错误信息]
- */
- public function getError(){
- return $this->error;
- }
- /**
- * [获取整个分类树结构]
- * @return [array|boolean] [若是查询失败,则返回false;不然,返回格式化后的分类数组]
- */
- public function getAll(){
- $sql = 'SELECT `id`,`name`,`lft`,`rgt`,`parentId` FROM `classify`';
- $classifyInfo = $this->db->queryList($sql);
- if(false === $classifyInfo){
- $this->error = '查询出错。'.$this->db->getError();
- return false;
- }
- //格式化数组
- $result = $this->format($classifyInfo);
- return $result;
- }
- /**
- * [格式化检索到的分类数据库中的数据,将信息组织成
- * array(
- * array(** 分类a **)
- * 'childrens'=>array(
- * array(** 分类b **)
- * 'childrens'=>array(
- * ......
- * )
- * )
- * )
- * 的形式
- * ]
- * @param [array] $classifyInfo [须要格式化的数据]
- * @param [integer] $parentId [父分类的id]
- * @return [array] [格式化后的数据]
- */
- private function format(&$classifyInfo, $parentId=-1){
- $result = array();//须要返回的结果数组
- foreach($classifyInfo as $key=>$oneInfo){
- if($parentId == $oneInfo['parentId']){
- $childrens = $this->format($classifyInfo, $oneInfo['id']);
- if(!empty($childrens)){
- $oneInfo['childrens'] = $childrens;
- }
- $result[] = $oneInfo;
- }
- }
- return $result;
- }
- /**
- * [获取某个分类到根分类的路径]
- * @param [int] $id [分类id]
- * @return [array|boolean] [若是查询失败,则返回false;不然,返回路径数组]
- */
- public function getPath($id){
- //查询$id的分类和根分类的左右值
- $sql = 'SELECT `id`,`lft`,`rgt` FROM `classify` WHERE `id`='.$id.' or `parentId`=-1';
- $classifyInfo = $this->db->queryList($sql, true);
- if(false === $classifyInfo){
- $this->error = '查询失败:'.$this->db->getError();
- return false;
- }
- if(1 != count($classifyInfo)){
- $left = $classifyInfo[$id]['lft'];
- $right = $classifyInfo[$id]['rgt'];
- unset($classifyInfo[$id]);
- $classifyInfo = array_pop($classifyInfo);
- $rootLeft = $classifyInfo['lft'];
- $rootRight = $classifyInfo['rgt'];
- }else{
- $rootLeft = $left = $classifyInfo[$id]['lft'];
- $rootRight = $right = $classifyInfo[$id]['rgt'];
- }
- //查询当前节点到根节点的距离
- $sql = 'SELECT `id`,`name`,`lft`,`rgt`,`parentId` '
- .'FROM `classify` '
- .'WHERE `lft`>='.$rootLeft.' AND `lft`<='.$left.' AND `rgt`<='.$rootRight.' AND `rgt`>='.$right
- .' ORDER BY `lft` ';
- $classifyPath = $this->db->queryList($sql);
- if(false === $classifyPath){
- $this->error = '查询失败:'.$this->db->getError();
- return false;
- }
- return $classifyPath;
- }
- /**
- * [获取指定分类下的分类]
- * @param [int] $id [分类id]
- * @return [array|boolean] [若是查询失败,则返回false;不然,返回格式化后的分类数组]
- */
- public function getOne($id){
- //查询$id分类的左右值
- $sql = 'SELECT `lft`,`rgt` FROM `classify` WHERE `id`='.$id;
- $oneInfo = $this->db->queryOne($sql);
- if(false === $classifyInfo){
- $this->error = '查询失败:'.$this->db->getError();
- return false;
- }
- $left = $oneInfo['lft'];
- $right = $oneInfo['rgt'];
- //查询该分类下的全部分类
- $sql = 'SELECT `id`,`name`,`lft`,`rgt`,`parentId` FROM `classify` WHERE `lft`>='.$left.' AND `rgt`<='.$right;
- $classifyInfo = $this->db->queryList($sql);
- if(false === $classifyPath){
- $this->error = '查询失败:'.$this->db->getError();
- return false;
- }
- //格式化数组
- $result = $this->format($classifyInfo);
- return $result;
- }
- /**
- * [在一个分类下添加子分类]
- * @param [int] $parentId [父分类的id]
- * @param [string] $name [增长的分类的名称]
- * @return [boolean] [增长成功,则返回true;不然,返回false]
- */
- public function insertNew($parentId, $name){
- $this->db->begin();
- //查询当前分类的左右值
- $sql = 'SELECT `lft` FROM `classify` WHERE `id`='.$parentId;
- $oneInfo = $this->db->queryOne($sql);
- if(false === $oneInfo){
- $this->error = '查询失败:'.$this->db->getError();
- $this->db->rollBack();
- return false;
- }
- $left = $oneInfo['lft'];
-
- //将全部左值大于当前分类左值的分类左右值加2
- $sql = 'UPDATE `classify` SET `lft`=`lft`+2,`rgt`=`rgt`+2 WHERE `lft`>'.$left;
- $result = $this->db->update($sql);
- if(false === $result){
- $this->error = '更新节点左右值失败.'.$this->db->getError();
- $this->db->rollBack();
- return false;
- }
- //更新右节点大于当前分类左值的分类节点
- $sql = 'UPDATE `classify` SET `rgt`=`rgt`+2 WHERE `rgt`>'.$left.' AND `lft`<='.$left;
- $result = $this->db->update($sql);
- if(false === $result){
- $this->error = '更新节点右值失败.'.$this->db->getError();
- $this->db->rollBack();
- return false;
- }
- //插入新的节点
- $left += 1;
- $right = $left+1;
- $sql = "INSERT INTO `classify` VALUES(null, '{$name}', {$left}, {$right}, {$parentId})";
- $result = $this->db->insert($sql);
- if(false === $result){
- $this->error = '插入新节点失败.'.$this->db->getError();
- $this->db->rollBack();
- return false;
- }
- $this->db->submit();
- return true;
- }
- /**
- * [删除一个分类信息]
- * @param [int] $id [分类id]
- * @return [boolean] [删除成功,则返回true;不然,返回true]
- */
- public function delete($id){
- $this->db->begin();
- //查询当前分类的左右值
- $sql = 'SELECT `lft`,`rgt` FROM `classify` WHERE `id`='.$id;
- $oneInfo = $this->db->queryOne($sql);
- if(false === $oneInfo){print_r(debug_backtrace());
- $this->error = '查询失败:'.$this->db->getError();
- $this->db->rollBack();
- return false;
- }
- $left = $oneInfo['lft'];
- $right = $oneInfo['rgt'];
- $dValue = $right - $left + 1;
- //删除当前分类及其子分类
- $sql = 'DELETE FROM `classify` WHERE `lft`>='.$left.' AND `rgt`<='.$right;
- $result = $this->db->delete($sql);
- if(false === $result){
- $this->error = '删除失败:'.$this->db->getError();
- $this->db->rollBack();
- return false;
- }
- //将全部左值大于当前分类左值的分类左右值加2
- $sql = 'UPDATE `classify` SET `lft`=`lft`-'.$dValue.' , `rgt`=`rgt`-'.$dValue.' WHERE `lft`>'.$right;
- $result = $this->db->update($sql);
- if(false === $result){
- $this->error = '更新节点左值失败.'.$this->db->getError();
- $this->db->rollBack();
- return false;
- }
- //更新右节点大于当前分类左值的分类节点
- $sql = 'UPDATE `classify` SET `rgt`=`rgt`-'.$dValue.' WHERE `lft`<'.$left.' AND '.' `rgt`>'.$left;
- $result = $this->db->update($sql);
- if(false === $result){
- $this->error = '更新节点右值失败.'.$this->db->getError();
- $this->db->rollBack();
- return false;
- }
- $this->db->submit();
- return true;
- }
- /**
- * [根据id查询一个分类的信息]
- * @param [int] $id [分类id]
- * @return [array|boolean] [查询失败,则返回false;不然,返回分类信息数组]
- */
- public function searchById($id){
- //查询当前分类的左右值
- $sql = 'SELECT `id`,`name`,`lft`,`rgt`,`parentId` FROM `classify` WHERE `id`='.$id;
- $oneInfo = $this->db->queryOne($sql);
- if(false === $oneInfo){
- $this->error = '查询失败:'.$this->db->getError();
- return false;
- }
- return $oneInfo;
- }
- /**
- * [保存修改过的分类信息]
- * @param [string] $newName [分类的新名称]
- * @param [int] $id [分类id]
- * @return [boolean] [若是修改为功,则返回true;不然,返回false]
- */
- public function modify($newName, $id){
- $sql = "UPDATE `classify` SET `name`='{$newName}' WHERE `id`={$id}";
- $result = $this->db->update($sql);
- if(false === $result){
- $this->error = '更新失败:'.$this->db->getError();
- return false;
- }
- return true;
- }
- }