新手,写了基本功能,未写排序等相关操作;求高手改进,
数据库:
类库文件:
Category.class.php
<?php
/**
应用基于thinkphp的左右值无限分类
**/
class Category
{
//传入实化的对象【M('表名')】
private $objCategory;
//基础节点ID号
public $intCurrentId;
//设置制表符样式
private $arrTabsStyle = array(
'indent' => ' ',
'process' => '├ ',
'end'=>'└ '
);
//构造函数初始化
public function __construct($objCategory)
{
$this->objCategory = $objCategory;
}
//验证传入ID【大于0的数字】
private function checkFun($intId)
{
//$intId优先验证
if(isset($intId))
{
$this->intCurrentId = $intId;
return true;
}
//如果$this->intCurrentId 已设置,验证
else
{
if(isset($this->intCurrentId))
{
return true;
}
else
{
return false;
}
}
}
//根据ID号获取当前节点左右值
private function setCurrentData($intId)
{
if(false == $this->checkFun($intId))
{
return false;
}
$map['id'] = $this->intCurrentId;
return $this->objCategory->field(array('lft','rgt'))->where($map)->find();
}
/*
*作用:
设置输出列表数据的制表符样式
*参数:
$key:arrTabsStyle的KEY
$value:arrTabsStyle的值
*/
public function setTabStyle($key, $value = '')
{
if(isset($this->arrTabsStyle[$key]))
{
$this->arrTabsStyle[$key] = $value;
}
}
/*
*作用:
根据ID号获取当前节点数据
*参数:
$intId:可设置的,需读取节点ID号
*/
public function getCurrentData($intId)
{
if(false == $this->checkFun($intId))
{
return false;
}
$map['id'] = $this->intCurrentId;
return $this->objCategory->field(array('id','title'))->where($map)->find();
}
/*
*作用:
获取当前节点的父节点数据
*参数:
$intId:需要读取节点的ID
*/
public function getParentCategoryData($intId)
{
$arrRoot = $this->setCurrentData($intId);
if($arrRoot)
{
$map['lft'] = array('LT', $arrRoot['lft']);
$map['rgt'] = array('GT', $arrRoot['rgt']);
return $this->objCategory->where($map)->find();
}
else
{
return false;
}
}
/*
*作用:
获取ID下节点列表
*参数:
$intId:需要读取节点的父ID
$intLevel:目录等级默认到100级
*/
public function getCategoryList($intId = 1, $intLevel = 100)
{
//获取选定节点左右值,得出取值区间
$arrRoot = $this->setCurrentData($intId);
if($arrRoot)
{
//读取数据库符合条件的数据
$map['lft'] = array('BETWEEN', array($arrRoot['lft'], $arrRoot['rgt']));
$arrChildList = $this->objCategory->where($map)->order('lft')->select();
//return $arrChildList;
//对取出数据进行格式化
$arrRight = array();
foreach($arrChildList as $v)
{
if(count($arrRight))
{
while ($arrRight[count($arrRight) - 1] < $v['rgt'])
{
array_pop($arrRight);
}
}
//设置读取目录等级
if($intLevel > count($arrRight))
{
$title = $v['title'];
//设置输出时的样式
if(count($arrRight))
{
$title = $this->arrTabsStyle['process'].$title;
}
$title = str_repeat($this->arrTabsStyle['indent'], count($arrRight)).$title;
$returnCategoryList[] = array('id'=>$v['id'],'title'=>$title,'lft'=>$v['lft'],'rgt'=>$v['rgt']);
$arrRight[] = $v['rgt'];
}
}
return $returnCategoryList;
}
return false;
}
/*
*作用:
获取节点的子节点数
*参数:
$intId:需要读取节点的父ID
*/
public function getCategoryCount($intId)
{
$arrRoot = $this->setCurrentData($intId);
return ($arrRoot['rgt'] - $arrRoot['lft'] - 1) / 2;
}
/*
*作用:
添加节点
*参数:
$bolType:true添加到节点前面,false添加到节点尾部
$intId:添加到的父节点
*/
public function insertCategory($bolType = false, $intPid)
{
$data = I('param.');
if(!isset($intPid))
{
$intPid = $data['pid'];
}
$arrRoot = $this->setCurrentData($intPid);
if($arrRoot)
{
if($bolType)
//true添加到节点前面
{
$this->objCategory->where('rgt>'.$arrRoot['lft'])->setInc('rgt',2);
$this->objCategory->where('lft>'.$arrRoot['lft'])->setInc('lft',2);
//设置当前节点的左右值
$data['lft'] = $arrRoot['lft'] + 1;
$data['rgt'] = $arrRoot['lft'] + 2;
}
else
//false添加到节点尾部
{
$this->objCategory->where('rgt>='.$arrRoot['rgt'])->setInc('rgt',2);
$this->objCategory->where('lft>'.$arrRoot['rgt'])->setInc('lft',2);
$data['lft'] = $arrRoot['rgt'];
$data['rgt'] = $arrRoot['rgt'] + 1;
}
return $this->objCategory->add($data);
}
else
{
return false;
}
}
/*
*作用:
删除节点
*参数:
$intId:被删除的节点ID
*/
public function deleteCategory($intId)
{
$arrRoot = $this->setCurrentData($intId);
if($arrRoot)
{
$ints = $arrRoot['rgt'] - $arrRoot['lft'] + 1;
$map['lft'] = array('BETWEEN', array($arrRoot['lft'], $arrRoot['rgt']));
$this->objCategory->where($map)->delete();
$this->objCategory->where('lft>'.$arrRoot['rgt'])->setDec('lft',$ints);
$this->objCategory->where('rgt>'.$arrRoot['rgt'])->setDec('rgt',$ints);
return true;
}
else
{
return false;
}
}
/*
*作用:
更新节点
*参数:
$intId:被删除的节点ID
*/
public function updateCategory()
{
//读取POST数据存入数组
$data = I('param.');
//父ID等于子ID,直接跳出
if($data['pid'] == $data['id']){return false;}
//post.pid和当前父post.old相等说明未改变目录,不更新左右值
if($data['pid'] !== $data['oldpid'])
{
/**********************************【读取所需的相关值】********************************/
//获取新的父节点的数据
$arrParent = $this->setCurrentData($data['pid']);
//取当前节点的数据
$arrCurrent = $this->setCurrentData($data['id']);
/* 任务:删除节点 */
/**********************************【A-1:隔离数据】************************************/
//将需要调整位置的左右值+100000
$map['lft'] = array(
array('EGT', $arrCurrent['lft']),
array('ELT', $arrCurrent['rgt'])
);
$this->objCategory->where($map)->setInc('lft',100000);
//因为左值已更新,所以条件变化+100000
$map['lft'] = array(
array('EGT', $arrCurrent['lft'] + 100000),
array('ELT', $arrCurrent['rgt'] + 100000)
);
$this->objCategory->where($map)->setInc('rgt',100000);
unset($map);
/**********************************【A-2:更新正常节点值】******************************/
//获取隔离节点后续更新的步长值
$intStep = $arrCurrent['rgt'] - $arrCurrent['lft'] + 1;
//更新节点左右值
$map['lft'] = array(
array('GT', $arrCurrent['rgt']),
array('LT', 100000)
);
$this->objCategory->where($map)->setDec('lft',$intStep);
unset($map);
$map['rgt'] = array(
array('GT', $arrCurrent['rgt']),
array('LT', 100000)
);
$this->objCategory->where($map)->setDec('rgt',$intStep);
unset($map);
/* 完成:删除节点 */
/* 任务:更新节点 */
/**********************************【B-1:新父节目点提供下级节点的空间】****************/
$map['lft'] = array(
array('GT', $arrParent['lft']),
array('LT', 100000)
);
$this->objCategory->where($map)->setInc('lft',$intStep);
unset($map);
$map['rgt'] = array(
array('GT', $arrParent['lft']),
array('LT', 100000)
);
$this->objCategory->where($map)->setInc('rgt',$intStep);
unset($map);
/**********************************【B-2:将节点放入指定下级的空间】********************/
//获取隔离节点后续更新的步长值
$intStep = 100000 + ($arrCurrent['lft'] - ($arrParent['lft'] + 1));
//更新左右值大于父节点左值的节点的左右值
$map['lft'] = array(
array('EGT', $arrCurrent['lft'] + 100000),
array('ELT', $arrCurrent['rgt'] + 100000)
);
$this->objCategory->where($map)->setDec('lft',$intStep);
unset($map);
$map['rgt'] = array(
array('EGT', $arrCurrent['lft'] + 100000),
array('ELT', $arrCurrent['rgt'] + 100000)
);
$this->objCategory->where($map)->setDec('rgt',$intStep);
}
return $this->objCategory->where('id='.$data['id'])->setField('title', $data['title']);
}
}
?>
使用:
<?php
class CategoryAction extends CommonAction {
private $objCG;
public function _initialize(){
//导入分类库
import('@.ORG.Util.Category');
$this->objCG = new Category(M('CommonCategory'));
}
//目录列表
public function index($id = 1){
$this->cateorylist = $this->objCG->getCategoryList($id);
$this->display();
}
//添加目录
public function add($id=1){
$this->cateorylist = $this->objCG->getCategoryList($id);
$this->display();
}
//编辑目录
public function edit($id){
if (!empty($id)){
//输出所有的节点
$this->cateorylist = $this->objCG->getCategoryList(1);
//读取当前节点数据
$vo = $this->objCG->getCurrentData($id);
if ($vo){
//读取当前节点的父节点数据
$arrParent = $this->objCG->getParentCategoryData($id);
$vo['pid'] = $arrParent['id'];
$this->assign('vo',$vo);
$this->display();
}else{
$this->error('数据不存在!');
}
}else{
$this->error('数据不存在!');
}
}
//添加目录:操作
public function insert(){
$list = $this->objCG->insertCategory();
if ($list !== false)
{
$this->success('数据保存成功!');
}
else
{
$this->error('数据写入错误!');
}
}
public function delete($id){
if (!empty($id))
{
$result = $this->objCG->deleteCategory($id);
if ($result)
{
$this->success('删除成功!');
}
else
{
$this->error('删除出错!');
}
}
else
{
$this->error('ID错误!');
}
}
public function update(){
$list = $this->objCG->updateCategory();
if ($list !== false)
{
$this->success('更新成功!');
}
else
{
$this->error("操作失败!");
}
}
}