PHP-电商项目-2

六、 RBAC权限管理

1、RABC概念和原理

RBAC:全称叫做Role-Based Access Control,中文翻译叫做基于角色的访问控制。其主要的作用是实现项目的权限控制。
效果:让不同的管理员,能够访问的页面不一样。比如运营人员 只能看到运营相关模块。财务人员只能看到财务相关模块。
传统权限管理:

在这里插入图片描述
RBAC权限管理:
在这里插入图片描述
RBAC权限管理:
权限的管理相对规范,角色拥有的权限可以按照一定的标准定义好。
新增管理员,只需要指定角色,即可拥有对应的权限。

2、数据表设计

基本数据表:管理员表、角色表、权限表
对应关系:管理员对应一个角色,一个角色对应多个权限。(一个管理员也可以对应多个角色)
对应关系的维护:
第一种:三表结构,在管理员表增加角色id字段,在角色表增加权限ids字段,最终三张表。
第二种:五张表,新增一张管理员角色关联表,新增一张角色权限关联表。最终五张表。
在这里插入图片描述这里以三表结构为例:
查询一个管理员拥有的权限:
先查询管理员表,获取到角色id
再查询角色表,获取到角色拥有的权限ids
最后根据权限ids查询权限表,where id in (1,2,3)

特殊情况:超级管理员拥有所有的权限
设置 超级管理员的角色id为1,超级管理员拥有的权限,直接查询权限表所有的数据。

3、表之间的关系

管理员表pyg_admin中的role_id字段对应角色表pyg_role表主键id字段
在这里插入图片描述

4、模拟数据

管理员表、角色表和权限表都有一些默认的模拟数据

创建模型:

php think make:model common/Role
php think make:model common/Auth

七、权限管理

1、权限列表

用到的返回父子级或者无限级别列表函数用到递归和索引

if (!function_exists('get_cate_list')) {
    //递归函数 实现无限级分类列表
    function get_cate_list($list,$pid=0,$level=0) {

        static $tree = array();
        foreach($list as $row) {
            if($row['pid']==$pid) {
                $row['level'] = $level;
                $tree[] = $row;
                get_cate_list($list, $row['id'], $level + 1);
            }
        }
        return $tree;
    }
}

if(!function_exists('get_tree_list')){
    //引用方式实现 父子级树状结构
    function get_tree_list($list){
        //将每条数据中的id值作为其下标
        $temp = [];
        foreach($list as $v){
            $v['son'] = [];
            $temp[$v['id']] = $v;
        }
        //获取分类树
        foreach($temp as $k=>$v){
            $temp[$v['pid']]['son'][] = &$temp[$v['id']];
        }
        return isset($temp[0]['son']) ? $temp[0]['son'] : [];
    }
}

1.1 无限级分类列表

定义路由
创建控制器方法
接收参数
查询数据
无限级分类列表
返回数据
实现

/**
     * 显示资源列表
     *
     * @return 列表  普通列表;无限级分类列表;父子级树状列表
     */
    public function index()
    {
        //接收参数 keyword || type
        $params=input();

        $where=[];
        if(!empty($params['keyword'])){
            $where['auth_name']=['like',"%{$params['keyword']}%"];
        }
        //查询数据
        $list=\app\common\model\Auth::field('id,auth_name,pid,pid_path,auth_c,auth_a,is_nav,level')->where($where)->select();
        //转化为标准的二维数组
        $list=(new \think\Collection($list))->toArray();

        if(!empty($params['type'])&&$params['type']=='tree'){
           //父子级树状列表
            $list=get_tree_list($list);
        }else{
            //无限级分类列表
           $list=get_cate_list($list);
        }
        //返回数据
        $this->ok($list);
    }

1.2 父子级树状列表

在1.1基础上
接收参数判断
父子级树状列表
同1.1 见$params[‘type’]的判断

2、权限详情

定义路由
创建控制器方法
查询数据
返回数据
实现

  /**
     * 显示指定的资源
     *
     * @param  int  $id
     * @return \think\Response
     */
    public function read($id)
    {
        //查询数据
        $auth=\app\common\model\Auth::field('id,auth_name,pid,pid_path,auth_c,auth_a,is_nav,level')->find($id);
        //返回数据
        $this->ok($auth);
    }

3、权限新增

定义路由(已定义资源路由)
创建控制器方法
接收数据
参数检查
添加数据(是否顶级,级别和pid_path处理)
返回数据

实现

 /**
     * 保存新建的资源
     *
     * @param  \think\Request  $request
     * @return \think\Response
     */
    public function save(Request $request)
    {
        //接收数据
        $params=input();
        //参数检测
        $validate=$this->validate($params,[
            'auth_name|权限名称'=>'require',
            'pid|上级权限'=>'require',
            'is_nav|菜单权限'=>'require',
            //'auth_c|控制器名称'=>'',
            //'auth_a|方法名称'=>'',
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //添加数据(是否顶级,级别和pid_path处理)
        if($params['pid']==0){
            $params['level']=0;
            $params['pid_path']=0;
            $params['auth_c']='';
            $params['auth_a']='';
        }else{
            //不是顶级权限
            //查询上级信息
            //$p_info=\app\common\model\Auth::where('id',$params['pid'])->find();
            $p_info=\app\common\model\Auth::find($params['pid']);
            if(empty($p_info)){
                $this->fail('数据异常');
            }
            //设置级别+1 家族图谱拼接
            $params['level']=$p_info['level']+1;
            $params['pid_path']=$p_info['pid_path'].'_'.$p_info['id'];
        }
        //实际开发看情况 一般不需要返回数据
        //\app\common\model\Auth::create($params,true);
        //$this->ok();
        //restful 严格风格
        $auth=\app\common\model\Auth::create($params,true);
        $info=\app\common\model\Auth::find($auth['id']);
        //返回数据
        $this->ok($info);
    }

4、权限修改

定义路由(已定义资源路由)
创建控制器方法
接收数据
参数检测
添加数据(是否顶级,级别和pid_path处理)
返回数据

实现

 /**
     * 保存更新的资源
     *
     * @param  \think\Request  $request
     * @param  int  $id
     * @return \think\Response
     */
    public function update(Request $request, $id)
    {
        //接收参数
        $params=input();
        //参数检测
        $validate=$this->validate($params,[
            'auth_name|权限名称'=>'require',
            'pid|上级权限'=>'require',
            'is_nav|菜单权限'=>'require',
            //'auth_c|控制器名称'=>'',
            //'auth_a|方法名称'=>'',
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //修改数据(是否顶级,级别和pid_path处理)
        $auth=\app\common\model\Auth::find($id);
        if(empty($auth)){
            $this->fail('数据异常');
        }
        if($params['pid']==0){
            //说明是修改顶级权限
            $params['level']=0;
            $params['pid_path']=0;
        }else if($params['pid']!=$auth['pid']){
            //如果修改其上级权限pid 重新设置level级别和pic_path家族图谱
            $p_auth=\app\common\model\Auth::find($params['pid']);
            if(empty($p_auth)){
                $this->fail('数据异常');
            }
            //设置级别+1 家族图谱拼接
            $params['level']=$p_auth['level']+1;
            $params['pid_path']=$p_auth['pid_path'].'_'.$p_auth['id'];
        }
        \app\common\model\Auth::update($params,['id'=>$id],true);
        //返回数据
        $info=\app\common\model\Auth::find($id);
        $this->ok($info);
    }

5、权限删除

定义路由(已定义资源路由)
创建控制器方法
权限下是否有子权限
删除数据
返回数据
实现

 public function delete($id)
    {
        //判断是否有子权限
        $total=\app\common\model\Auth::where('pid',$id)->count();
        if($total>0){
            $this->fail('有子权限,无法删除');
        }
        //删除数据
        \app\common\model\Auth::destroy($id);
        //返回数据
        $this->ok();
    }

6、菜单权限列表

定义路由
创建控制器方法
获取当前管理员的角色id
查询权限
超级管理员:role_id==1,直接查询权限表

获取当前管理员的角色id

查询权限:

超级管理员: role_id == 1 ,直接查询权限表

普通管理员: role_id !=1, 查询角色表,获取role_auth_ids字段,根据role_auth_ids值,查询权限表,使用where id in (1,2,3)条件

菜单权限: is_nav = 1

父子级树状列表
返回数据

public function nav(){
        //获取登录的管理员用户id
        $user_id=input('user_id');
        //查询管理员的角色id role_id
        $info=\app\common\model\Admin::find($user_id);
        $role_id=$info['role_id'];
        //判断是否超级管理员
        if($role_id==1){
            //超级管理员 直接查询权限表 菜单权限 is_nav=1
            $data=\app\common\model\Auth::where('is_nav',1)->select();
        }else{
            //先查询角色表 role_auth_ids
            $role=\app\common\model\Role::find($role_id);
            $role_auth_ids=$role['role_auth_ids'];
            //再查询权限表
            $data=\app\common\model\Auth::where('is_nav',1)->where('id','in',$role_auth_ids)->select();
        }
        //先转化为标准的二维数组
        $data=(new \think\Collection($data))->toArray();
        //再转化为 父子级树状结构
        $data=get_tree_list($data);
        //返回数据
        $this->ok($data);
    }

八、角色管理

1、角色列表

定义路由
创建控制器方法
查询数据
返回数据

   public function index()
    {
        //查询数据 (不需要查询超级管理员)
        $list=\app\common\model\Role::where('id','>',1)->select();
        //对每条角色数据,查询对应权限,增加role_auths下标的数据 (父子级树状结构)
        foreach ($list as $k=>$v){
            //$v['role_auth_ids']
            //查询权限表
            $auths=\app\common\model\Auth::where('id','in',$v['role_auth_ids'])->select();
           // $auths=\app\common\model\Auth::select($v['role_auth_ids']);
            //先转化为标准的二维数组
            $auths=(new \think\Collection($auths))->toArray();
            //再转化为父子级树状结构
            $auths=get_tree_list($auths);
            //$v['role_auth_ids']=$auths
            $list[$k]['role_auths']=$auths;
        }
        unset($v); //特别是 $v前面有&(引用时)强烈建议 unset
        //返回数据
        $this->ok($list);

    }

2、角色详情

定义路由
创建控制器方法
查询数据
返回数据

   public function read($id)
    {
        //查询数据
        $info=\app\common\model\Role::field('id,role_name,desc,role_auth_ids')->find($id);
        //返回数据
        $this->ok($info);
    }

3、角色新增

定义路由
创建控制器方法
接收数据
参数检测
添加数据
返回数据

public function save(Request $request)
    {
        //接收数据
        $params=input();
        //参数检测
        $validate=$this->validate($params,[
            'role_name'=>'require',
            //'desc'=>'',
            'auth_ids'=>'require',
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //添加数据
        $params['role_auth_ids']=$params['auth_ids'];
        $role=\app\common\model\Role::create($params,true);
        $info=\app\common\model\Role::find($role['id']);
        //返回数据
        $this->ok($info);

    }

4、角色修改

定义路由
创建控制器方法
接收数据
参数检测
添加数据
返回数据

    public function update(Request $request, $id)
    {
        //接收数据
        $params=input();
        //参数检测
        $validate=$this->validate($params,[
            'role_name'=>'require',
            //'desc'=>'',
            'auth_ids'=>'require',
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //添加数据
        $params['role_auth_ids']=$params['auth_ids'];
        \app\common\model\Role::update($params,['id'=>$id],true);
        $info=\app\common\model\Role::find($id);
        //返回数据
        $this->ok($info);

    }

5、角色删除

定义路由
创建控制器方法
接收数据
参数检测
添加数据
返回数据

 public function delete($id)
    {
        //如果角色下有管理员,不能删除
        //根据角色id 查询管理员表的role_id字段
        $total=\app\common\model\Admin::where('role_id',$id)->count();
        if($total>0){
            $this->fail('角色正在使用中,无法删除');
        }
        //删除数据
        \app\common\model\Role::destroy($id);
        //返回数据
        $this->ok();
    }

九、管理员管理

1、管理员列表

定义路由
创建控制器方法
查询数据
返回数据

    public function index()
    {
        //接收参数 keyword page
        $params=input();
        $where=[];
        //搜索条件
        if(!empty($params['keyword'])){
            $keyword=$params['keyword'];
            $where['t1.username']=['like',"%$keyword%"];
        }
        //分页查询(包含搜索)
        //$list=\app\common\model\Admin::where($where)->paginate(2);
        //SELECT t1.*,t2.role_name FROM pyg_admin t1 left join pyg_role t2 on t1.role_id=t2.id where username like '%a%' limit 0,2;
        $list=\app\common\model\Admin::alias('t1')
            ->join('pyg_role t2','t1.role_id=t2.id','left')
            ->field('t1.*,t2.role_name')
            ->where($where)->paginate(2);
        //返回数据
        $this->ok($list);
    }

2、管理员详情

定义路由
创建控制器方法
查询数据
返回数据

public function read($id)
    {
        //查询数据
        $info=\app\common\model\Admin::find($id);
        //返回数据
        $this->ok($info);
    }

3、管理员新增

定义路由
创建控制器方法
接收数据
参数检测
添加数据
返回数据

 public function save(Request $request)
    {
        //接收参数
        $params = input();
        $validate=$this->validate($params,[
            'username|用户名'=>'require|unique:admin',
            //'username|用户名'=>'require|unique:admin,username',
            'email|邮箱'=>'require|email',
            'role_id|所属角色'=>'require|integer|gt:0',
            'password|密码'=>'length:6,20',
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //添加数据
        if(empty($params['password'])){
            $params['password']='123456';
        }
        $params['password']=encrypt_password($params['password']);
        $params['nickname']=$params['username'];
        $info=\app\common\model\Admin::create($params,true);
        //查询刚才添加的数据
        $data=\app\common\model\Admin::find($info['id']);
        //返回数据
        $this->ok($data);
    }

4、管理员修改

定义路由
创建控制器方法
接收数据
参数检测
修改数据
返回数据


public function update(Request $request, $id)
    {
        if($id==1){
            $this->fail('超级管理员,不能修改');
        }
        //接收参数
        $params=input();
        if(!empty($params['type'])&&$params['type']=='reset_pwd'){
            //修改密码
            $password=encrypt_password('123456');
            \app\common\model\Admin::update(['password'=>$password],['id'=>$id],true);
        }else{
            //参数检测
            $validate=$this->validate($params,[
                'email|邮箱'=>'email',
                'role_id'=>'integer|gt:0',
                'nickname|昵称'=>'max:50'
            ]);
            if($validate!==true){
                $this->fail($validate);
            }
            //修改数据 (用户名不让改)
            unset($params['username']);
            unset($params['password']);
            \app\common\model\Admin::update($params,['id'=>$id],true);
        }
        $data=\app\common\model\Admin::find($id);
        //返回数据
        $this->ok($data);
    }

5管理员删除

删除数据
返回数据

public function delete($id)
    {
        //删除数据(不能删除超级管理员admin、不能删除自己)
        if($id==1){
            $this->fail('不能删除超级管理员');
        }
        if($id==input('user_id')){
            $this->fail('不能删除自己');
        }
        \app\common\model\Admin::destroy($id);
        //返回数据
        $this->ok();
    }

十、权限检测

管理员登录后,访问每个页面时,需要进行权限检测:
判断当前管理员是否拥有当前访问页面的权限。

原理:
查询当前管理员所拥有的权限role_auth_ids
查询到当前访问页面对应的权限id(控制器名称和方法名称为条件)
判断权限id和role_auth_ids,是否拥有当前页面访问权限

特殊情况:
超级管理员不需要检测
所有管理员都可以访问的页面,不需要检测(比如首页)

思路:
判断是否特殊页面(比如首页、不需要检测)
获取到管理员的角色id
判断是否超级管理员(超级管理员不需要检测)
查询当前管理员所拥有的权限ids(从角色表查询对应的role_auth_ids)
根据当前访问的控制器、方法名称查询到具体的权限id
判断当前权限id是否在role_auth_ids范围中

实现:

将权限检测的逻辑 封装到 application/adminapi/logic/AuthLogic.php中

<?php
namespace app\adminapi\logic;

class AuthLogic{
    public static function check(){
        //判断是否是特殊页面(比如首页,不需要检测)
        $controller=request()->controller();//返回的是首字母大写
        $action=request()->action();
        if($controller=='Index'&&$action=='index'){
            //不需要检测(有权限访问)
            return true;
        }
        //获取到管理员的角色id
        $user_id=input('user_id');
        $info=\app\common\model\Admin::find($user_id);
        $role_id=$info['role_id'];
        //判断是否是超级管理员 (超级管理员不需要检测)
        if($role_id==1){
            //不需要检测(有权限访问)
            return true;
        }
        //查询当前管理员所拥有的权限ids(从角色表查询对应的role_auth_ids)
        $role=\app\common\model\Role::find($role_id);
        //取出权限ids 分隔为数组
        $role_auth_ids=explode(',',$role['role_auth_ids']);
        //根据当前访问的控制器、方法名称查询到具体的权限id
        $auth=\app\common\model\Auth::where('auth_c',$controller)->where('auth_a',$action)->find();
        $auth_id=$auth['id'];
        //判断当前权限id是否在role_auth_ids范围中
        if(in_array($auth_id,$role_auth_ids)){
            //有权限
            return true;
        }
        return false;
    }
}

BaseApi中调用
在这里插入图片描述

十一、商品分类管理

商品相关数据表
多条线表示箭头起始表有多条记录对应箭头终止表一条记录。
箭头起始表中包含有xxx_id字段,对应箭头终止表主键id字段

1、商品分类、商品品牌、商品、商品相册

在这里插入图片描述
2、商品、商品模型、商品属性

在这里插入图片描述
3、商品、商品模型、商品SKU
SPU:最小产品单元,包含多种可选规格的某种商品的集合。iphone6就是一个SPU。
SKU:最小库存单元,不可再拆分的产品。32G的黑色的iphone6就是一个SKU。

在这里插入图片描述

完整版
在这里插入图片描述

1、商品分类列表

定义路由
创建控制器方法
查询数据
返回数据(无限级分类列表、父子级树状列表)

 public function index()
    {
        //接收pid参数 影响查询的数据
        //$pid=input('pid','');
        //if($pid===''){}
        $params=input();
        $where=[];
        if(isset($params['pid'])){
            $where['pid']=$params['pid'];
        }
        //接收type参数 影响返回的数据
        //查询数据
        $list=\app\common\model\Category::where($where)->select();
        //转化为无限级分类列表
        $list=(new \think\Collection($list))->toArray();
      /*  if(isset($params['type'])&&$params['type']=='list'){

        }else{
            $list=get_cate_list($list);
        }*/
        if(!isset($params['type'])||$params['type']!='list'){
            $list=get_cate_list($list);
        }
        //返回数据
        $this->ok($list);
    }

2、商品分类详情

定义路由
创建控制器方法
查询数据
返回数据

 public function read($id)
    {
        //查询数据
        $info=\app\common\model\Category::find($id);
        //返回数据
        $this->ok($info);
    }

3、商品分类新增

定义路由
创建控制器方法
接收数据
参数检测
添加数据
返回数据

   public function save(Request $request)
    {
        //接收参数
        $params=input();
        //参数检测
        $validate=$this->validate($params,[
           'cate_name'=>'require|length:2,20',
           'pid'=>'require|integer|egt:0',
           'is_show'=>'require|in:0,1',
            'is_hot'=>'require|in:0,1',
            'sort'=>'require|between:0,9999',
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //添加数据 (处理pid_path pid_path_name level)
        if($params['pid']==0){
            //顶级分类
            $params['pid_path']=0;
            $params['pid_path_name']='';
            $params['level']=0;
        }else{
            //不是顶级分类,查询其上级分类
            $p_info=\app\common\model\Category::where('id',$params['pid'])->find();
            if(empty($p_info)){
                //没有查到数据
                $this->fail('数据异常,请稍后再试');
            }
            $params['pid_path']=$p_info['pid_path'].'_'.$p_info['id'];
            $params['pid_path_name']=$p_info['pid_path_name'].'_'.$p_info['cate_name'];
            $params['level']=$p_info['level']+1;
        }
        $cate=\app\common\model\Category::create($params,true);
        $info=\app\common\model\Category::find($cate['id']);
        //返回数据
        $this->ok($info);
    }

4、商品分类修改

定义路由
创建控制器方法
接收数据
参数检测
修改数据
返回数据
实现:

 public function update(Request $request, $id)
    {
        //接收参数
        $params=input();
        //参数检测
        $validate=$this->validate($params,[
            'cate_name'=>'require|length:2,20',
            'pid'=>'require|integer|egt:0',
            'is_show'=>'require|in:0,1',
            'is_hot'=>'require|in:0,1',
            'sort'=>'require|between:0,9999',
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //添加数据 (处理pid_path pid_path_name level)
        if($params['pid']==0){
            //顶级分类
            $params['pid_path']=0;
            $params['pid_path_name']='';
            $params['level']=0;
        }else{
            //不是顶级分类,查询其上级分类
            $p_info=\app\common\model\Category::where('id',$params['pid'])->find();
            if(empty($p_info)){
                //没有查到父级
                $this->fail('数据异常,请稍后再试');
            }
            $params['pid_path']=$p_info['pid_path'].'_'.$p_info['id'];
            $params['pid_path_name']=$p_info['pid_path_name'].'_'.$p_info['cate_name'];
            $params['level']=$p_info['level']+1;
        }
        //logo图片处理
        if(isset($params['logo'])&&!empty($params['logo'])){
            $params['image_url']=$params['logo'];
        }
        \app\common\model\Category::update($params,['id'=>$id],true);
        $info=\app\common\model\Category::find($id);
        //返回数据
        $this->ok($info);
    }

5、商品分类删除

删除数据
返回数据

 public function delete($id)
    {
        //删除数据
        //判断分类下是否有子分类
        $total=\app\common\model\Category::where('pid',$id)->count();
        if($total>0){
            $this->fail('分类下有子分类,无法删除');
        }
        \app\common\model\Category::destroy($id);
        //返回数据
        $this->ok();
    }

十三、文件上传

1、单图片上传

定义路由
创建控制器方法
图片上传
返回数据
实现:
在这里插入图片描述
在这里插入图片描述

//单图片上传
    public function logo(){
        //接收参数
        $type=input('type');
        if(empty($type)){
            $this->fail('缺少参数');
        }
        //获取文件
        $file=request()->file('logo');
        if(empty($file)){
            $this->fail('必须上传文件');
        }
        //图片移动 /public/uploads/goods  /public/uploads/categroy public/uploads/brand
        $info=$file->validate(['size'=>10*1024*1024,'ext'=>'jpg,jpeg,png,gif'])->move(ROOT_PATH.'public'.DS.'uploads'.DS.$type);
        if($info){
            //返回图片路径  /uploads/ccategroy/2021/12/06/dawdw.jpg
            $logo=DS.'uploads'.DS.$type.DS.$info->getSaveName();
            $this->ok($logo);
        }else{
            //返回报错
            $msg=$file->getError();
            $this->fail($msg);
        }


    }

postman测试
在这里插入图片描述
总结:
管理员 增删改查接口

权限检测

能够说清RBAC究竟咋回事

商品相关数据表介绍
单品分类 增删改查(三级分类)
单图片上传接口

2、多图片上传

定义路由
创建控制器方法
图片上传
返回数据
实现:

  //多图上传
    public function images()
    {
        //接收type参数 图片分组
        $type = input('type', 'goods');
        //$type=request()->param('type','goods');
        //获取上传的文件(数组)
        $files = request()->file('images');
        //遍历数组逐个上传文件
        $data = ['success' => [], 'error' => []];
        foreach ($files as $file) {
            //移动文件到指定目录下 /public/uploads/goods/目录下
            $dir = ROOT_PATH . 'public' . DS . 'uploads' . DS . $type;
            if (!is_dir($dir)) {//如果没有这个文件夹就创建
                mk_dir($dir);
            }
            $info = $file->validate(['size' => 10 * 1024 * 1024, 'ext' => 'jpg,jpeg,png,gif'])->move($dir);
            if ($info) {
                //成功 拼接图片路径
                $path = DS . 'uploads' . DS . $type . DS . $info->getSaveName();
                $data['success'][] = $path;
            } else {
                //失败获取错误信息
                $data['error'][] = [
                    'name' => $file->getInfo('name'),
                    'msg' => $file->getError(),
                ];
            }
        }
        $this->ok($data);
    }

postman测试
在这里插入图片描述

十四、商品品牌管理

1、商品品牌列表

定义路由
创建控制器方法
查询数据
返回数据(分页+搜索列表、分类下的品牌列表)

    public function index()
    {
        //接收参数 cate_id; keyword page
        $params=input();
        $where=[];
        if(isset($params['cate_id'])&&!empty($params['cate_id'])){
            //分类下的品牌列表
            $where['t1.cate_id']=$params['cate_id'];
            //查询数据
            //SELECT t1.*,t2.cate_name FROM `pyg_brand` t1 left join pyg_category t2 on t1.cate_id=t2.id where cate_id=72;
            //$list=\app\common\model\Brand::where($where)->field('id,name')->select();
            /*$list=\app\common\model\Brand::alias('t1')
                ->join('pyg_categroy t2','t1.cate_id=t2.id','left')
                ->field('t1.*,t2.cate_name')
                ->where($where)
                ->select();*/
            $list=\app\common\model\Brand::alias('t1')
                ->join(config('database.prefix').'category t2','t1.cate_id=t2.id','left')
                ->field('t1.*,t2.cate_name')
                ->where($where)
                ->select();
        }else{
            //分页+搜索列表
            if(isset($params['keyword'])&&!empty($params['keyword'])){
                $keyword=$params['password'];
                $where['t1.name']=['like',"%$keyword%"];
            }
            //分页查询数据
            //SELECT t1.*,t2.cate_name FROM `pyg_brand` t1 left join pyg_category t2 on t1.cate_id=t2.id where name like '%亚%' limit 0,10;
            //$list=\app\common\model\Brand::where($where)->paginate(10);
            $list=\app\common\model\Brand::alias('t1')
                ->join('pyg_category t2','t1.cate_id=t2.id','left')
                ->field('t1.*,t2.cate_name')
                ->where($where)
                ->paginate(10);
        }
        $this->ok($list);
    }

2、商品品牌详情

定义路由
创建控制器方法
查询数据
返回数据

  public function read($id)
    {
        //查询数据
        $info=\app\common\model\Category::find($id);
        //返回数据
        $this->ok($info);
    }

3、商品品牌新增

定义路由

//安装生成缩略图  如果是完整版tp框架不用安装
php composer.phar require topthink/think-image 1.*
  public function save(Request $request)
    {
        //接收参数
        $params=input();
        //参数检测
        $validate=$this->validate($params,[
           'cate_name'=>'require|length:2,20',
           'pid'=>'require|integer|egt:0',
           'is_show'=>'require|in:0,1',
            'is_hot'=>'require|in:0,1',
            'sort'=>'require|between:0,9999',
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //添加数据 (处理pid_path pid_path_name level)
        if($params['pid']==0){
            //顶级分类
            $params['pid_path']=0;
            $params['pid_path_name']='';
            $params['level']=0;
        }else{
            //不是顶级分类,查询其上级分类
            $p_info=\app\common\model\Category::where('id',$params['pid'])->find();
            if(empty($p_info)){
                //没有查到父级
                $this->fail('数据异常,请稍后再试');
            }
            $params['pid_path']=$p_info['pid_path'].'_'.$p_info['id'];
            $params['pid_path_name']=$p_info['pid_path_name'].'_'.$p_info['cate_name'];
            $params['level']=$p_info['level']+1;
        }
        //logo图片处理
        $params['image_url']=isset($params['logo'])?$params['logo']:'';
        //生成缩略图
        if(isset($params['image_url'])&&!empty($params['image_url'])&&is_file('.'.$params['image_url'])){
            \think\Image::open('.'.$params['image_url'])->thumb(200,100)->save('.'.$params['image_url']);
        }
        $cate=\app\common\model\Category::create($params,true);
        $info=\app\common\model\Category::find($cate['id']);
        //返回数据
        $this->ok($info);
    }

4、商品品牌修改

定义路由
创建控制器方法
接收数据
参数检测
修改数据
返回数据
实现

  public function update(Request $request, $id)
    {
        //接收参数
        $params=input();
        //参数检测
        $validate=$this->validate($params,[
           'name'=>'require',
           'cate_id'=>'require|integer|gt:0',
            'is_hot'=>'require|in:0,1',
            'sort'=>'require|between:0,9999'
        ]);
        if($validate!==true){
            $this->fail($validate);
        }
        //修改数据(logo图片缩略图)
        if(isset($params['logo'])&&!empty($params['logo'])&&is_file('.'.$params['logo'])){
            //生成缩略图
            \think\image::open('.'.$params['logo'])->thumb(200,100)->save('.'.$params['logo']);
        }
        \app\common\model\Brand::update($params,['id'=>$id],true);
        $info=\app\common\model\Brand::find($id);
        //返回数据
        $this->ok($info);
    }

5、商品品牌删除

删除数据
返回数据
实现

  public function delete($id)
    {
        //判断 品牌下是否有商品
        $total=\app\common\model\Goods::where('brand_id',$id)->count();
        if($total>0){
            $this->fail('品牌下有商品,不能删除');
        }
        //删除品牌
        \app\common\model\Brand::destroy($id);
        //返回结果
        $this->ok();
    }

十五、连表查询与关联模型

关联模型 见手册–模型–关联(一对一关联,一对多关联,关联预载入)

1、连表查询

需求:查询所有商品品牌信息及其所属的分类名称

连表查询一个品牌及分类名称
SELECT t1.*,t2.cate_name FROM 'pyg_brand' t1 left join pyg_categroy t2 on t1.cate_id=t2.id where t1.id=1;
连表查询所有品牌以及对应的分类名称
SELECT t1.*,t2.cate_name FROM 'pyg_brand' t1 left join pyg_categroy t2 on t1.cate_id=t2.id;

对应框架中的代码:

连表查询一个品牌及分类名称
$info=\app\common\model\Brand::alias('t1')
->join('pyg_category t2','t1.cate_id=t2.id','left')
->field('t1.*,t2.cate_name')
->where('t1.id',$id)
->find();
连表查询所有品牌以及对应的分类名称
$list=\app\common\model\Brand::alias('t1')
->join('pyg_categroy t2','t1.cate_id=t2.id','left')
->field('t1.*,t2.cate_name')
->select();

数组形式的结果:

$info=['id'=>1,'name'=>'华为',...,'cate_name'=>'手机'];

$list=[
	['id'=>1,'name'=>'华为',...,'cate_name'=>'手机'],
	['id'=>2,'name'=>'小米',...,'cate_name'=>'手机'],
]

2、一对一关联

新增管理员档案表pyg_profile,保存每个管理员的详细信息(身份证号、银行卡号)。

CREATE TABLE `pyg_profile` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `uid` int(11) NOT NULL DEFAULT '0' COMMENT '用户id',
  `idnum` varchar(30) DEFAULT NULL COMMENT '身份证号',
  `card` varchar(255) DEFAULT NULL COMMENT '银行卡号',
  `create_time` int(11) DEFAULT NULL,
  `update_time` int(11) DEFAULT NULL,
  `delete_time` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

添加测试数据

INSERT INTO `pyg`.`pyg_profile` (`id`, `uid`, `idnum`, `card`, `create_time`, `update_time`, `delete_time`) VALUES ('1', '1', '232332198008083321', '421656421254789', '1520408547', '1520408547', NULL);
INSERT INTO `pyg`.`pyg_profile` (`id`, `uid`, `idnum`, `card`, `create_time`, `update_time`, `delete_time`) VALUES ('2', '2', '435332198108083312', '521656421254777', '1520408547', '1520408547', NULL);
INSERT INTO `pyg`.`pyg_profile` (`id`, `uid`, `idnum`, `card`, `create_time`, `update_time`, `delete_time`) VALUES ('3', '3', '655332198108083357', '681656421254787', '1520408547', '1520408547', NULL);
INSERT INTO `pyg`.`pyg_profile` (`id`, `uid`, `idnum`, `card`, `create_time`, `update_time`, `delete_time`) VALUES ('4', '4', '987067198208083734', '843123421257829', '1520408547', '1520408547', NULL);
INSERT INTO `pyg`.`pyg_profile` (`id`, `uid`, `idnum`, `card`, `create_time`, `update_time`, `delete_time`) VALUES ('5', '5', '657067198408083256', '753623421259523', '1520408547', '1520408547', NULL);
INSERT INTO `pyg`.`pyg_profile` (`id`, `uid`, `idnum`, `card`, `create_time`, `update_time`, `delete_time`) VALUES ('6', '6', '746067198608089463', '534623421259125', '1520408547', '1520408547', NULL);
INSERT INTO `pyg`.`pyg_profile` (`id`, `uid`, `idnum`, `card`, `create_time`, `update_time`, `delete_time`) VALUES ('7', '7', '745367198708089414', '514623426449165', '1520408547', '1520408547', NULL);

创建模型

php think make:model common/Profile

1)关联查询

需求:查询管理员信息及其档案信息

①定义关联关系

档案表pyg_profile中的uid对应于管理员表中的id

以管理员表为主,一个管理员有一个档案,管理员模型中定义关联关系:

//定义管理员-档案关联关系
public function profile()
{
	return $this->hasOne('Profile', 'uid', 'id');
}

注:方法名,一般和关联的模型名对应,采用首字母小写的驼峰命名法。

return $this->hasOne(关联model,关联model的联系键,本model的联系键);

第二个参数,可选,默认为 本模型名_id

第三个参数,可选,默认为id
在这里插入图片描述
②查询数据

需求:查询管理员数据时,也要查询档案数据

控制器中

$info = \app\common\model\Admin::with('profile')->find(1);
dump($info);
$data = \app\common\model\Admin::with('profile')->select();
dump($data);

在这里插入图片描述

1)定义相对的关联

需求:查询档案信息及管理员信息
档案表pyg_profile中的uid对应于管理员表中的id
以档案表为主,一个管理员有一个档案,管理员模型中定义关联关系:

//定义管理员-档案关联关系
public function admin()
{
	return $this->belongsTo('Admin', 'uid', 'id');
}

注:方法名,一般和关联的模型名对应,采用首字母小写的驼峰命名法。

return $this->hasOne(关联model,关联外键,关联主键);

第二个参数,可选,默认为 模型名_id

第三个参数,可选,默认为id

在这里插入图片描述
②查询数据

需求:查询档案数据时,也要查询管理员数据

控制器中

$info = \app\common\model\Profile::with('admin')->find(1);
dump($info);
$data = \app\common\model\Profile::with('admin')->select();
dump($data);

在这里插入图片描述

3、一对多关联

1)关联查询

需求:查询商品分类及其下的商品品牌信息

①定义关联关系

品牌表中的cate_id对应于分类表中的id

以分类表为主,一个分类下有多个品牌,分类模型中定义关联关系:

//定义分类-品牌关联关系
public function brands()
{
	return $this->hasMany('Brand', 'cate_id', 'id');
}

注:方法名,一般和关联的模型名对应,采用首字母小写的驼峰命名法,取复数形式。

return $this->hasMany(关联model,关联外键,关联主键);

第二个参数,可选,默认为 模型名_id

第三个参数,可选,默认为id
在这里插入图片描述
②查询数据

需求:查询分类数据时,也要查询其下的品牌数据

控制器中

$info = \app\common\model\Category::with('brands')->find(72);
dump($info);
$data = \app\common\model\Category::with('brands')->select();
dump($data);

在这里插入图片描述

2)定义相对的关联

需求:查询商品品牌及其所属的商品分类信息

品牌表中的cate_id对应于分类表中的id

以品牌表为主,一个品牌属于一个分类,品牌模型中定义关联关系:(和一对一的相对关联,语法一模一样)

//定义品牌-分类关联关系
public function category()
{
	return $this->belongsTo('Category', 'cate_id', 'id');
}

注:方法名,一般和关联的模型名对应,采用首字母小写的驼峰命名法。

return $this->BelongsTo(关联model,关联外键,关联主键);

第二个参数,可选,默认为 模型名_id

第三个参数,可选,默认为id

在这里插入图片描述
②查询数据

需求:查询查询商品品牌信息时,也要查询及其所属的商品分类数据

控制器中

$info = \app\common\model\Brand::with('category')->find(1);
dump($info);
$data = \app\common\model\Brand::with('category')->select();
dump($data);

在这里插入图片描述

4、绑定属性到父模型

hasOne() 和belongsTo方法后面,调用bind方法,可将属性绑定到父模型中。

注:hasMany方法后不能调用bind方法。

比如,品牌模型中:将分类名称cate_name绑定到品牌模型数据中

public function category()
{
	return $this->belongsTo('Category', 'cate_id')->bind('cate_name');
}

控制器中

$info = \app\common\model\Brand::with('category')->find(1)->toArray();
dump($info);

结果结构如下: cate_name和品牌信息属于同一级

$info = ['id'=>1, 'name'=>'华为', 'cate_name'=>'手机'];

对比绑定之前:

$info = ['id'=>1, 'name'=>'华为', 'category'=>['cate_name'=>'手机']];

十六、商品模型(类型)管理

1、商品模型列表

定义路由

创建控制器方法

查询数据

返回数据

实现:

定义路由
在这里插入图片描述
创建控制器方法,继承BaseApi

php think make:controller adminapi/Type

在这里插入图片描述
创建模型

php think make:model common/Type

查询数据

    public function index()
    {
        //查询数据
        $list=\app\common\model\Type::select();
        //返回数据
        $this->ok($list);
    }

2、商品模型详情

定义路由
创建控制器方法
查询数据
返回数据
创建模型(规格名称模型、规格值模型、属性模型)
在这里插入图片描述
定义关联模型
在这里插入图片描述
在这里插入图片描述
查询数据
在这里插入图片描述

3、商品模型删除

删除数据

返回数据

注:事务操作 见手册-数据库-事务操作
在这里插入图片描述

实现:

商品类型下有商品,则不能删除

删除了商品类型,类型下的规格名、规格值、属性都可以删除了。

普通的删除:
在这里插入图片描述

使用事务操作进行删除:
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值