數據表結構和數據
表結構
[sql] view plaincopyphp
- 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 plaincopyhtml
- 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 plaincopymysql
- /——
- |--index.php 入口文件
- |--conf.php 配置文件
- /db
- |--DB.class.php 數據庫操做類
- /lib
- |--ClassifyTree.class.php 左右樹操做文件【core】
index.php 代碼
[php] view plaincopysql
- <?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;
- }
- }