# thinkphp框架权限rule表管理[增删改查]文档

# 一、权限列表

# 1. 接口说明

  1. 请求方式:GET [用postman测试]
  2. 接口示例:
    本地路由地址:http://thinkphp.shop/admin/rule/:page?limit=[:limit]
    本地路由示例:http://thinkphp.shop/admin/rule/1?limit=100 (opens new window) 1代表第1页,100代表每页100条数据,由于本数据涉及无限极循环,可以不用分页的,就是列出全部数据即可。
  3. header头
参数 是否必填 类型 说明
token String token值
  1. 请求参数
参数 是否必填 类型 说明
page int 页码,默认1
limit int 每页多少条数据,默认100
  1. 返回
  1. 关于数据返回的说明: 原本查询的权限数据类似这样的数据:
[
 {"id": 6,"pid": 0,"status": 1,"name": "管理员管理",...},
 {"id": 7, "pid": 6,"status": 1,"name": "删除管理员",...},
 {"id": 8, "pid": 6,"status": 1,"name": "管理员列表",...},
 {"id": 9, "pid": 0,"status": 1,"name": "角色管理",...},
 {"id": 10,"pid": 9,"status": 1,"name": "角色列表",...},
]

为了方便后续配置权限,需要将数据转成树形结构,方便前端使用

  1. 一维数组的树形结构,会增加一个level体现等级
[
    {"id": 6,"pid": 0,"status": 1,"name": "管理员管理",...,"level": 0},
    {"id": 7, "pid": 6,"status": 1,"name": "删除管理员",...,"level": 1},
    {"id": 8, "pid": 6,"status": 1,"name": "管理员列表",...,"level": 1},
    {"id": 9, "pid": 0,"status": 1,"name": "角色管理",...,"level": 0},
    {"id": 10,"pid": 9,"status": 1,"name": "角色列表",...,"level": 1},
]
  1. 二维数组的树形结构,增加一个children字段,体现子集
[
    {
        "id": 6,
        "pid": 0,
        "status": 1,
        "name": "管理员管理",
        ...
        "children": [
            {
                "id": 7,
                "pid": 6,
                "status": 1,
                "name": "删除管理员",
                ...
                "children": []
            },
            {
                "id": 8,
                "pid": 6,
                "status": 1,
                "name": "管理员列表",
                ...
                "children": []
            }
        ]
    },
    {
        "id": 9,
        "pid": 0,
        "status": 1,
        "name": "角色管理",
        ...
        "children": [
            {
                "id": 10,
                "pid": 9,
                "status": 1,
                "name": "角色列表",
                ...
                "children": []
            }
        ]
    }
]

# 2. 创建控制器和验证器

模型已在之前创建过了

# 1. 创建控制器

php think make:controller admin/Rule

# 2. 创建验证器

php think make:validate admin/Rule

# 3. 控制器代码

app/controller/admin/Rule.php

...
use app\BaseController;

class Rule extends BaseController
{
    //权限列表
    public function index()
    {
        //拿到参数数组, 如:页码等
        // $param = $request ->param();
        $param = $this->request->param();
        //可选参数,如limit:每页多少条,查询keyword:搜索关键字
        $limit = getValueByKey('limit',$param,100);
        $page = getValueByKey('page',$param,1);

        //计算一下一共查了多少条数据
        $totalCount = $this->model -> count();

        //列表数据
        $list = $this->model ->
               //分页
               page($page,$limit) ->
               //排序
               // order('id','desc') ->
               order(['id'=>'asc']) ->
               //查询
               select() 
               // 转成数组输出要用
               ->toArray();

        return apiSuccess([
            'list' => list_to_tree2($list,'pid'),
            'totalCount' => $totalCount,
            'rules' => list_to_tree($list,'pid')
        ]);
    }
}

# 4. 公共方法

app/common.php

/**
* 数据集组合分类树(一维数组)
* @return    array
*/
function list_to_tree($array,$field = 'pid',$pid = 0,$level = 0){
    //声明静态数组,避免递归调用时,多次声明导致数组覆盖
    static $list = [];
    foreach ($array as $key => $value){
        if ($value[$field] == $pid){
            $value['level'] = $level;
            $list[] = $value;
            unset($array[$key]);
            list_to_tree($array,$field,$value['id'], $level+1);
        }
    }
    return $list;
}

/**
* 数据集组合分类树(多维数组)
* @return    array
*/
function list_to_tree2($cate,$field = 'pid',$child = 'children',$pid = 0,$callback = false){
	if(!is_array($cate)) return [];
    $arr = [];
    foreach($cate as $v){
    	$extra = true;
    	if(is_callable($callback)){
        	$extra = $callback($v);
        }
        if($v[$field] == $pid && $extra){
            $v[$child] = list_to_tree2($cate,$field,$child,$v['id'],$callback);
            $arr[]     = $v;
        }
    }
    return $arr;
}

# 5. 验证器代码

app/validate/admin/Rule.php

...
use app\validate\BaseValidate;

class Rule extends BaseValidate
{
    protected $rule = [
        'page' => 'require|integer|>:0',
        'limit' => 'integer|>:0',
    ];

    ...

    //定义一个场景(场景名称可自定义,方便我们观察,可用控制器的方法名称)
    protected $scene = [
        //权限列表验证场景
        'index' => ['page','limit'],
    ];
}

# 6. 路由

route/admin.php

// 必须是登录之后,才能访问(管理员身份)
Route::group('admin',function(){
    ...

    //权限列表
    Route::get('rule/:page','admin.Rule/index');
    
//加入中间件代码
})->middleware(\app\middleware\checkShopManagerToken::class);

# 二、创建权限

# 1. 接口说明

  1. 请求方式:POST [用postman测试]
  2. 接口示例:
    本地路由地址:http://thinkphp.shop/admin/rule
    本地路由示例:http://thinkphp.shop/admin/rule (opens new window)
  3. header头
参数 是否必填 类型 说明
token String token值
  1. 请求参数
参数 是否必填 类型 说明
pid int 父级id,必填
status int 可用状态,0不可用,1可用,可不填,默认:1
name string 权限名称(后台栏目或者功能名称),最多100个字符,必填
frontname string 前端路由name值,最多100个字符,可不填
frontpath string 前端路由路径,最多100个字符,可不填
condition string 路由方法,最多255个字符,可不填
menu int 是否为菜单,0不是,1是,可不填,默认:1
order int 排序,大于等于0,可不填,默认:50
icon string 图标名称,最多100个字符,可不填
method string 可不填,要填只能是:POST,GET,PUT,DELETE 中的一个
  1. 返回
{
    "msg": "ok",
    "data": true
}

# 2. 控制器代码

app/controller/admin/Rule.php

public function save(Request $request)
{
    // $param = $request -> only(['name','condition','status']);
    $param = $request->param();
    $res =  $this->model -> save($param);
    return apiSuccess($res);
    // 由于它和Role控制器的代码一样的,因此可以考虑放到基类控制器文件中,然后继承
}

# 3. 验证器代码

app/validate/admin/Rule.php

...
use app\validate\BaseValidate;

class Rule extends BaseValidate
{
    /**
     * 定义验证规则
     * 格式:'字段名' =>  ['规则1','规则2'...]
     *
     * @var array
     */
    protected $rule = [
        ...

        //isExist是我们自定义的一个规则
        'id|权限id' => 'require|integer|>:0|isExist:Rule',

        'pid|父级id' => 'require|integer|>=:0|isExist:Rule,false',//pid无需挂载这条数据,防止挂载冲突
        'status' => 'integer|in:0,1',
        'name' => 'require|max:100',
        'frontname' => 'max:100',
        'frontpath' => 'max:100',
        'condition' => 'max:255',
        'menu' => 'integer|in:0,1',
        'order' => 'integer|>=:0',
        'icon' => 'max:100',
        'method' => 'in:POST,GET,PUT,DELETE',
    ];

    /**
     * 定义错误信息
     * 格式:'字段名.规则名' =>  '错误信息'
     *
     * @var array
     */
    protected $message = [];

    //定义一个场景(场景名称可自定义,方便我们观察,可用控制器的方法名称)
    protected $scene = [
        //权限列表验证场景
        'index' => ['page','limit'],
        //创建权限场景
        'save' => ['pid', 'status', 'name', 'frontname', 'frontpath', 
                   'condition', 'menu', 'order', 'icon', 'method'],
    ];
}

# 4. 改写一下基类验证器

app/validate/BaseValidate.php

...

class BaseValidate extends Validate
{
    //isExist是我们自定义的一个规则,用于判断id的数据是否存在
    // 验证记录是否存在
    protected function isExist($value, $rule='', $data='', $field='', $title='', $message=''){
        //  halt($value, $rule, $data, $field, $title, $message);
         // $value id的值,如35
        // $rule 即:isExist:ShopManager冒号后面这部分 如ShopManager
        // $data 验证的数据,即你提交的数据
        // $field 字段名称,如 id
        // $title 字段别名,如 管理员id,用于提示作用
        // 'id|管理员id' => 'require|integer|>:0|isExist:ShopManager',

        // $rule 有可能这样:isExist:Rule,false
        $arr = explode(',', $rule);// ['Rule','false']

        //如果$value不存在或者为0
        if(!$value){
            return true;//则不往下继续验证了
        }
        // 拿到模型
        // $model = '\app\model\\'.$rule;
        $model = '\app\model\\'.$arr[0];
        //静态调用,查找数据库
        $_m = $model::find($value);
        if(!$_m){
            return  '该'.$title.'不存在';
        }

        //当然如果存在,既然我们已经查询了一次,没必要在控制器再次查询
        //可以考虑挂载到 request类里面
        // request() -> Model = $_m;
        if(count($arr) == 1 || count($arr) == 2 && $arr[1] !== 'false'){
           request() -> Model = $_m;
        }

        return true;
    }
}

# 5. 路由

route/admin.php

// 必须是登录之后,才能访问(管理员身份)
Route::group('admin',function(){
    ...

    //创建权限
    Route::post('rule','admin.Rule/save');
    //权限列表
    Route::get('rule/:page','admin.Rule/index');

//加入中间件代码
})->middleware(\app\middleware\checkShopManagerToken::class);

# 三、修改权限

# 1. 接口说明

  1. 请求方式:POST [用postman测试]
  2. 接口示例:
    本地路由地址:http://thinkphp.shop/admin/rule/:id
    本地路由示例:http://thinkphp.shop/admin/rule/23 (opens new window) 23表示的是权限id
  3. header头
参数 是否必填 类型 说明
token String token值
  1. 请求参数
参数 是否必填 类型 说明
pid int 父级id,必填
status int 可用状态,0不可用,1可用,可不填,默认:1
name string 权限名称(后台栏目或者功能名称),最多100个字符,必填
frontname string 前端路由name值,最多100个字符,可不填
frontpath string 前端路由路径,最多100个字符,可不填
condition string 路由方法,最多255个字符,可不填
menu int 是否为菜单,0不是,1是,可不填,默认:1
order int 排序,大于等于0,可不填,默认:50
icon string 图标名称,最多100个字符,可不填
method string 可不填,要填只能是:POST,GET,PUT,DELETE 中的一个
  1. 返回
{
    "msg": "ok",
    "data": true
}

# 2. 控制器代码

app/controller/admin/Rule.php

public function update(Request $request, $id)
{
    // $param = $request -> only([
    //     'id',
    //     'name',
    //     'status',
    //     'desc'
    // ]);
    $param = $request -> param();
    $res = $request -> Model -> save($param);
    return apiSuccess($res);
    //可以放到基类控制器,然后继承
}

# 3. 验证器代码

app/validate/admin/Rule.php

//定义一个场景(场景名称可自定义,方便我们观察,可用控制器的方法名称)
protected $scene = [
    ...
    //修改权限场景
    'update' => ['id','pid','status','name','frontname','frontpath',
    'condition','menu','order','icon','method'],
];

# 4. 路由

route/admin.php

// 必须是登录之后,才能访问(管理员身份)
Route::group('admin',function(){
    ...

    //更新权限
    Route::post('rule/:id','admin.Rule/update');
    //创建权限
    Route::post('rule','admin.Rule/save');
    //权限列表
    Route::get('rule/:page','admin.Rule/index');
    
//加入中间件代码
})->middleware(\app\middleware\checkShopManagerToken::class);

# 四、修改权限可用状态

# 1. 接口说明

  1. 请求方式:post [用postman测试]
  2. 接口示例:
    本地路由地址:http://thinkphp.shop/admin/rule/:id/update_status
    本地路由示例:http://thinkphp.shop/admin/rule/23/update_status (opens new window) 23代表权限id
  3. header头
参数 是否必填 类型 说明
token String token值
  1. 请求参数
参数 是否必填 类型 说明
status int 状态值:0不可用,1可用
  1. 返回
{
    "msg": "ok",
    "data": true
}

# 2. 控制器代码

app/controller/admin/Rule.php

//修改权限状态
public function updateStatus(){
    // 由于传递了id,在验证器里面已经将查询结果挂载到了request() -> Model
    $m = $this -> request -> Model;
    $m -> status = $this -> request -> param('status');
    return apiSuccess($m -> save());
}

# 3. 验证器代码

app/validate/admin/Rule.php

//定义一个场景(场景名称可自定义,方便我们观察,可用控制器的方法名称)
protected $scene = [
    ...
    //修改权限状态
    'updateStatus'=> ['id','status'],
];

# 4. 路由

route/admin.php

// 必须是登录之后,才能访问(管理员身份)
Route::group('admin',function(){
    ...

    //修改权限状态
    Route::post('rule/:id/update_status','admin.Rule/updateStatus');
    //更新权限
    Route::post('rule/:id','admin.Rule/update');
    //创建权限
    Route::post('rule','admin.Rule/save');
    //权限列表
    Route::get('rule/:page','admin.Rule/index');
      
//加入中间件代码
})->middleware(\app\middleware\checkShopManagerToken::class);

# 五、删除权限

# 1. 接口说明

  1. 请求方式:POST [用postman测试]
  2. 本地路由: http://thinkphp.shop/admin/rule/:id/delete
    本地路由地址:http://thinkphp.shop/admin/rule/6/delete (opens new window) 6为权限的id
  3. header头
参数 是否必填 类型 说明
token String token值
  1. 请求参数:
    请求体body无需传递参数、只需传递id即可,已经在网址传递了id值
  2. 返回
{
   "msg": "ok",
   "data": true
}

# 2. 控制器代码

app/controller/admin/Rule.php

public function delete($id)
{
    $m = $this->request -> Model;
    return apiSuccess($m -> delete());
    //但是注意,我们删除了权限,中间表role_rule中的数据
    // 跟rule_id相关的数据也应该删除,因为权限不存在了
}

# 3. 验证器代码

app/validate/admin/Rule.php

protected $scene = [
    ...
    //删除权限
    'delete' => ['id'],
];

# 4. 路由

route/admin.php

// 必须是登录之后,才能访问(管理员身份)
Route::group('admin',function(){
    ...

    //删除权限
    Route::post('rule/:id/delete','admin.Rule/delete');
    //修改权限状态
    Route::post('rule/:id/update_status','admin.Rule/updateStatus');
    //更新权限
    Route::post('rule/:id','admin.Rule/update');
    //创建权限
    Route::post('rule','admin.Rule/save');
    //权限列表
    Route::get('rule/:page','admin.Rule/index');
    
    
    
//加入中间件代码
})->middleware(\app\middleware\checkShopManagerToken::class);

# 5. 模型中处理删除权限对应的中间表数据

app/model/admin/Rule.php

    //删除权限之前的操作:onBeforeDelete 钩子函数:删除之前可以做的操作
    //1. 删除权限之前,先删除role_rule表里面对应的权限id,通过角色id查询删除

    public function delRoles($roleIds){
       return $this -> roles() -> detach($roleIds);
    }
    // 删除子分类(下一级分类)
    public function children(){
        return $this -> hasMany('Rule','pid','id');
    }
    //2. 删除权限之前,先删除rule表里面的子分类
    public static function onBeforeDelete($rule){
        // 拿到所有的角色id
        $roleIds = $rule -> roles -> map(function($v){
            return $v -> id;
        }) -> toArray();
        //根据我们的角色id通过关联关系删除中间表role_rule里面的数据
        if(count($roleIds) > 0){
          $rule -> delRoles($roleIds);
        }

        // 删除子分类(下一级分类)
        $rule -> children -> each(function($v){
            $v -> delete(); // 删除子分类(下一级分类)
        });
    }
更新时间: 2025年3月28日星期五晚上8点03分