先看数据库 ( 第二个字段是用于联表操作 可以忽略 )
// 无限分类算法
function listTree($list, $pk = 'id', $pid = 'pid', $child = 'children', $root = 0)
{
if (!is_array($list)) {
return [];
}
//创建基于主键的数组引用
$aRefer = [];
$tree = [];
foreach ($list as $k => $v) {
$aRefer[$v[$pk]] = &$list[$k]; // 主键id 作为数组下标
}
foreach ($list as $k => $v) {
//判断是否存在parent
$parentId = $v[$pid];
if ($root === $parentId) { // 当父id = 0 则是最外层
$tree[] = &$list[$k];
} else { // 当父id != 0 就创建 孩子层
if (isset($aRefer[$parentId])) { // 当该数据 的父亲数据存在时
$parent = &$aRefer[$parentId];
$parent[$child][] = &$list[$k]; // 为该父亲创建一个孩子层数据,孩子层数据就是该数据本身
}
}
}
return $tree;
}
测试 记得->toArray()
$list = $this->detail->where(['planpvc_id' => $planpvc_id])->field($field)->select()->toArray();
$data = listTree($list); // 转为无限分类
return json($data);
先查询出要复制的无限分类
遍历 unset 他们的id
saveAll() 批量插入
如果是像我这个项目这样,涉及到联表的,那么思路如下**
( 1 是父表 n是子表 )
先查询出要复制的父表的内容 a
unset() a 的主键 oldId
,然后插入到父表 ,得到新id newId
查询子表 planpvc_id = oldId 的数据 b (通过layer 升序查询)
使用遍历把 b 里面的planpvc_id 换成 newId
使用遍历 + if 判断 , 并创建数组 存放无限分类 第一层、第二层的id, topId_arr ndId_arr
( 数组格式是 【旧数据的id】=> 【新数据的id】)
if(pid = 0) 则是最外层,插入数据到子表,并且把插入后的id 放到 topId_arr
if(layer = 2) 则是第二层,pid = topId_arr [ 旧的pid ] , 因为第二层旧的 pid ==
第一层旧的pid
插入数据到子表,并且把插入后的id 放到 ndId_arr
if(layer= 3) 则是第三层,pid =ndId_arr [ 旧的pid ], 插入数据到子表
ps: 下面是参考代码,这次项目主要联表有点多会用到多个遍历, 所以大家可以从 3.clone 到详情表 开始看
public function copy()
{
$id = input('plan_id');
$title = input('title');
if (!is_numeric($id) || strlen($title) < 3)
return failApi('参数错误');
$planProvince = new ErPlanProvince();
$detail = new ErDetail();
Db::startTrans();
try {
// 1. clone 到计划表
$this->plan->save(['title' => $title]); // clone
$plan_id = $this->plan->id; // clone 后的plan_id
// 2. clone 到省份表
$pvc_arr = $planProvince->where(['plan_id' => $id])->field('create_time,update_time', true)->select()->toArray();
if (!count($pvc_arr))
return failApi("无省份数据");
// 交换id
array_walk($pvc_arr, function (&$v, $k) use (&$oldPvcId_arr, $plan_id) {
$v['plan_id'] = $plan_id; // 换成clone 后的plan_id
$oldPvcId_arr[] = $v['id']; // 获取旧的的 planpvc_id
unset($v['id']);
});
$ins_arr = $planProvince->saveAll($pvc_arr); // clone
foreach ($ins_arr as $k => $v) {
// key: old_id value : new_id
$old_new_PvcID[$oldPvcId_arr[$k]] = $v['id']; // 获取clone后的 planpvc_id
}
unset($ins_arr);
unset($pvc_arr);
// 3. clone 到详情表
array_walk($oldPvcId_arr, function ($oldId, $keys) use ($detail, $old_new_PvcID, &$detail_arr) {
// 1.根据 planpvc_id 查看每个省是否有详情信息
$detail_arr = $detail->where('planpvc_id', $oldId)->order('layer inc')->field('create_time,update_time', true)->select()->toArray();
if (count($detail_arr)) {
// detail表有数据
//
$topIdArr = []; // 存放顶层id
$ndIdArr = []; // 存放二级的id
array_walk($detail_arr, function (&$v, $key) use ($old_new_PvcID, $oldId, $detail, &$topIdArr, &$ndIdArr) {
// 2.该planpvc_id 下的detail数据:
$v['planpvc_id'] = $old_new_PvcID[$oldId]; // 3. 赋上新的planpvc_id
if ($v['pid'] == 0) {
// 最外层id
$detail->create(['planpvc_id' => $v['planpvc_id'], 'pid' => $v['pid'], 'title' => $v['title'], 'count' => $v['count'], 'layer' => $v['layer']]);
$topIdArr[$v['id']] = $detail->getLastInsID(); // 存入最高层的 id 旧Id => 新Id
// dump($topIdArr) ;
}
if ($v['layer'] == 2) {
// 第二层
$v['pid'] = $topIdArr[$v['pid']]; // 查找最高层id
$detail->create(['planpvc_id' => $v['planpvc_id'], 'pid' => $v['pid'], 'title' => $v['title'], 'count' => $v['count'], 'layer' => $v['layer']]);
$ndIdArr[$v['id']] = $detail->getLastInsID(); // 存入第二层的 id 旧Id => 新Id
//dump($ndIdArr);
}
if ($v['layer'] == 3) {
// 底层
$v['pid'] = $ndIdArr[$v['pid']]; // 查找第二层id
$detail->create(['planpvc_id' => $v['planpvc_id'], 'pid' => $v['pid'], 'title' => $v['title'], 'count' => $v['count'], 'layer' => $v['layer']]);
}
unset($v['id']);
});
}
});
Db::commit();
return sucApi('复制成功');
} catch (Exception $e) {
Db::rollback();
failApi($e->getMessage());
}
}