左右值

  • 1.优点:查询数据非常方便,极大降低数据库压力,不用传统递归就可以查询
  • 2.缺点:更新数据操作较为繁琐
  • 3.适用场景:查询较多的情况,但是移动分类的操作非常复杂,消耗过大,尽量不做这个操作,适用于无限级评论
  • 4.保持左右值的连续!!! 中间不能有断掉的!!!

数据库:

示例代码

//添加
public function add($name, $parentId = 0)
{
    // 如果没有指定父分类ID,则默认为0(根分类)
    $parent = \app\common\model\Test::where('id', $parentId)->find();
    if (!$parent) {
        // 插入根分类,并设置初始的左右值,插入一级分类
        \app\common\model\Test::create([
            'name' => $name,
            'left' => 1,
            'right' => 2,
            'pid' => 0,
            'level' => 1,
        ]);
        return true;
    }

    // 查找父分类的右值
    $right = $parent['right'];

    // 更新所有右值大于当前父分类右值的分类的右值
    \app\common\model\Test::where('right', '>=', $right)
        ->setInc('right', 2);
    \app\common\model\Test::where('left', '>', $right)
        ->setInc('left', 2);


    // 插入新分类
    \app\common\model\Test::create([
        'name' => $name,
        'left' => $right,
        'right' => $right + 1,
        'pid' => $parentId,
        'level' => $parent->level + 1,
    ]);
    return true;
}

//查询
public function index($pid = 0)
{
    //当前节点子孙总数=(当前节点右值-当前节点左值-1)/2
    $categoryModel = new \app\common\model\Test();
    return $this->displayCategories($pid, $categoryModel);
}

protected function displayCategories($parentId, $categoryModel, $prefix = '')
{
    $tree = [];
    $categories = $categoryModel->where('pid', $parentId)->order(['left' => 'asc'])->select();
    foreach ($categories as $category) {
        $children = $this->displayCategories($category['id'], $categoryModel, $prefix . '--');
        if ($children) {
            $category['children'] = $children; // 将子分类添加到当前分类的children字段
        }
        $tree[] = $category; // 将当前分类添加到树中
    }
    return $tree;
}

//删除
public function deleteCategory($categoryId)
{
    // 获取要删除的节点信息
    $category = \app\common\model\Test::where('id', $categoryId)->find();
    if (!$category) {
        return false; // 节点不存在
    }

    // 获取要删除节点的左右值范围
    $left = $category->left;
    $right = $category->right;

    // 计算要移动的节点数(即要删除的范围大小)--子树的宽度
    $shift = $right - $left + 1;

    // 删除节点及其所有子节点
    \app\common\model\Test::where('left', '>=', $left)
        ->where('right', '<=', $right)
        ->delete();

    // 更新所有右值大于要删除节点右值的节点的左右值
    \app\common\model\Test::where('right', '>', $right)
        ->setDec('right', $shift);
    \app\common\model\Test::where('left', '>', $right)
        ->setDec('left', $shift);

    return true;
}

这个图片很有用,可以认真查看