用户分类权限更新异常:如何保留原有分类ID并新增权限?
看起来你遇到的核心问题是当前更新逻辑会删除用户所有原有分类权限,然后替换为新的权限列表,而不是保留原有并新增。这和你使用updateCategoryAccess函数的方式无关,而是更新流程的逻辑设计出了问题——另外你的updateCategoryAccess函数本身并不适合处理“批量追加权限”的场景,因为它是用来更新单条特定记录的,而你的需求是管理一对多的权限关系(一个用户对应多个分类权限)。
先分析现有代码的问题
你当前的更新分支里先执行了$deleteold = $category_permitted->deleteCategoryAccess($id);,这会直接删除该用户的所有分类权限记录,之后再新增提交的权限,自然会把原有数据完全覆盖掉。
另外你的updateCategoryAccess函数逻辑是修改某用户下所有记录的category_id值,这本身就不符合权限表的设计逻辑——因为category_permitted应该是一个用户对应多条权限记录(每条记录对应一个分类权限),用UPDATE批量修改所有记录的category_id只会把该用户的所有权限都改成同一个分类,这显然不是你想要的效果。
解决方案
根据你的需求(保留原有分类权限,新增新的分类ID),可以选择以下两种方案:
方案1:仅追加新权限(完全保留原有权限)
如果你的需求是不删除任何原有权限,只添加提交的新权限中用户还未拥有的部分,可以按以下步骤修改更新逻辑:
- 先获取用户已拥有的所有分类ID:
// 假设你有一个方法可以获取用户已有的分类权限列表 $existingCats = $category_permitted->getUserCategoryAccess($id); // 提取出纯分类ID数组,比如得到 [2, 3] $existingCatIds = array_column($existingCats, 'category_id');
- 从提交的权限列表中筛选出未存在的分类ID:
// 找出提交的分类ID中不在已有列表里的部分 $newCatIds = array_diff($temp['cat_access'], $existingCatIds);
- 逐个添加这些新权限:
foreach ($newCatIds as $catId) { $accessData = [ 'user_id' => $id, 'category_id' => $catId ]; $category_permitted->addCategoryAccess($accessData); }
方案2:同步权限列表(保留提交的所有权限,移除多余旧权限)
如果你的需求是让用户的权限完全匹配提交的列表(即提交的权限全部保留,原有但不在提交列表的权限会被删除),可以这样实现:
- 获取用户已有的分类ID列表:
$existingCats = $category_permitted->getUserCategoryAccess($id); $existingCatIds = array_column($existingCats, 'category_id');
- 删除用户已拥有但不在提交列表中的权限:
// 需要新增一个根据user_id和category_id删除单条权限的方法 $catsToDelete = array_diff($existingCatIds, $temp['cat_access']); foreach ($catsToDelete as $catId) { $category_permitted->deleteCategoryAccessByUserAndCat($id, $catId); }
- 添加提交列表中用户还未拥有的权限:
$catsToAdd = array_diff($temp['cat_access'], $existingCatIds); foreach ($catsToAdd as $catId) { $accessData = [ 'user_id' => $id, 'category_id' => $catId ]; $category_permitted->addCategoryAccess($accessData); }
关键优化:给权限表加联合唯一索引
为了避免同一个用户重复添加同一个分类权限,建议给category_permitted表添加user_id和category_id的联合唯一索引:
ALTER TABLE category_permitted ADD UNIQUE INDEX idx_user_category (user_id, category_id);
这样即使重复调用addCategoryAccess添加同一个权限,数据库也会自动忽略重复插入(你也可以在addCategoryAccess的insert方法里使用INSERT IGNORE来避免报错)。
内容的提问来源于stack exchange,提问作者Alisha Lamichhane

