# Thinkphp学习笔记

扩展包推荐

composer require thans/tp-jwt-auth

composer require yunpian/yunpian-php-sdk

composer require overtrue/wechat

phpoffice/phpspreadsheet //excel表单处理

官方文档:https://www.kancloud.cn/manual/thinkphp6_0/1037479

# Http 常用返回状态码

200 : (OK) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。 201 : (Created) 请求成功并且服务器创建了新的资源。 301 : (Moved Permanently) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。 300 : (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。 303 : (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。 304 : (Not Modified) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。 400 : (Bad Request) 服务器不理解请求的语法。 401 : (Unauthorized) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。 403 : (Forbidden) 服务器拒绝请求。 404 : (Not Found ) 服务器找不到请求的网页。 500 : (Internal Server Error) 服务器遇到错误,无法完成请求。

# 数据返回

laravel, 在thinkphp中吧json 改为 data

/**
 * 成功返回消息
 * @param string $msg
 * @param array $data
 * @param int $code
 * @return \Illuminate\Http\JsonResponse
 */
public function success($msg="ok",$data=[],$code=0){
    if (!empty($data)) return response()->json(["code"=>$code,"data"=>$data,"msg"=>$msg]);
    return response()->json(["code"=>$code,"msg"=>$msg]);
}

/**
 * 失败返回消息
 * @param string $msg
 * @param int $code
 * @return \Illuminate\Http\JsonResponse
 */
public function error($msg="请求错误",$code=202){
    return response()->json(["code"=>$code,"msg"=>$msg]);
}

/**
 * 数据返回
 * @param array $data
 * @param string $count
 * @param string $msg
 * @param int $code
 * @return \Illuminate\Http\JsonResponse
 */
public function resData($data=[],$count = '',$msg="ok",$code=0){
    if (empty($count)) return response()->json(["code"=>$code,"msg"=>$msg,"data"=>$data]);
    return response()->json(["code"=>$code,"data"=>$data,"count"=>$count,"msg"=>$msg]);
}

# 查询技巧

# join

$data = Score::alias('s')
    ->join("gift g",'s.sid=g.id')
    ->field("g.id,g.title,g.pic,s.stime") //需要那个表的字段就假如对应表的字段
    ->where("uid",$request->uid)
    ->limit(($page * $limit) - $limit, (int)$limit)
    ->select()->toArray();

# 别名查询

$data = Articles::where("del",0)
            ->alias('a')
            ->join('wy_comment c','a.id=c.aid')
            ->field("a.id,a.title,,COUNT(c.aid) as comCount")
            ->limit(($page * $limit) - $limit, (int)$limit)
            ->order("id","desc")->select()->toArray();
            
$data = Articles::where("del",0)
            ->field("id,title,keyword,pic,createtime,click")
            ->limit(($page * $limit) - $limit, (int)$limit)
            ->withCount('ArcToCom')
            ->order("id","desc")->select()->toArray();
            
//关联查询
 ->with(['user','parent'])
 ->visible(['user'=>['realname'],'parent'=>['realname']])
 
//关联统计


http://localhost:8082/ArticleDetail?eid=26&puid=100

# 关联查询

 ->with(['user','parent']) //模型关联方法,不是模型的名字
 ->visible(['user'=>['realname'],'parent'=>['realname']])

# 分页查询

// contoller
public function list(){
    $limit = $request->param("limit", 15);
    $data = User::order("id","desc")->paginate($limit);
    //获取查询数据
    $list = $data->items();
    // 获取总条数
    $count = $data->total();
    // json 返回
    return json(["code"=>201,"data"=>$list,"count"=>$count]);
}

# 时间段查询

/**
 * 时间段查询:2020-10-01 - 2020-11-30
 * @param string $datebt
 * @return array
 */
protected function getBetweenTime(string $datebt){
    $datearr=explode(" - ",$datebt);
    $datebegin=strtotime($datearr['0']);
    $dateend=strtotime($datearr['1']);
    return ['create_time','between',[$datebegin,$dateend]];
}

# A表关联B表统计B表信息

关联模型

//cate->school

/**
     * 分类关联资源
     */
public function school()
{
    return $this->hasMany(School::class,'cate_id','id');
}

分类关联资源统计资源的状态为1和2的总数

$data = SchoolCate::withCount([
    "school"=>function($query,&$alias){ //这里有一个&符号
        $query->where("status",2)->where("check_user_id",session("admin_id"));
        $alias='valid';
    }
],false)
    ->withCount([
        "school"=>function($query,&$alias){
            $query->where("status",4)->where("check_user_id",session("admin_id"));
            $alias='unvalid';
        }
    ],false)->where("id","in",$school->getMySchoolIds())->select();

# 获取器

获取器的作用是在获取数据的字段值后自动进行处理,例如,我们需要对状态值进行转换,1 代表:正常

在model下定义: 语法:get + 字段名+Attr

class User extends Model
{
      public function getStatusAttr($value)
      {
	    $status = [-1=>'删除',0=>'禁用',1=>'正常',2=>'待审核'];
            return $status[$value];
      }
}
// 查询输出
$user = User::find()->status; //例如输出“正常”

class User extends Model 
{
    public function getStatusAttr($value)
    {
       $status = [-1=>'删除',0=>'禁用',1=>'正常',2=>'待审核'];
       return ['val'=>$value,'text'=>$status[$value]];
  }
}

$user = User::find()->status; //例如输出“正常”
$user = User::find()->status.text; //例如输出“1”

$user = User::find();
$user->getData("status"); //例如输出“1”

# 远程一对一查询

/**
     * 【座位表】通过【班级表】去查【教室】
     * 座位关联班级,班级关联教室: 通过【座位】关联【班级】去查【教室】
     * 参数:教室模型(目标表),班级模型(中间表),座位表id(目标表),班级表id(中间表),座位表关联班级的关联id(起始表),班级表关联教室的id(中间表)
     */
public function room()
{
    return $this->hasOneThrough(Room::class,RoomBj::class,"id","id","bj_id","room_id");
}

# 多字段统计

//model
public function status2()
{
	return $this->hasMany(Student::class,"cate_id","id");
}
public function status4()
{
	return $this->hasMany(Student::class,"cate_id","id");
}
    
// controller
 public function info()
 {
     $data = SchoolCate::field("id,cate")
         ->withCount([
             "status2" => function($query){
                 $query->where('status',2);
             },
             "status4" => function($query){
                 $query->where('status',4);
             }
         ])->select()->toArray();
     return view("",["data"=>$data]);
 }

# 插入并返回插入id

$resId = Mode::insertGetId();

# 去重查询并统计人数

Gw::where("gwssd",$defaultGwssd)
    ->field("id,zldw,SUM(zlrs) as zlrs")
    ->group("zldw")
    ->withCount("zw") //关联方法
    ->select()->toArray();

# 时间转化

 $data['bmstime'] = strtotime($data['bmstime']);
 date('Y-m-d H:i:s',$data['bmstime']);

# 多字段统计

->fieldRaw('Sum(prize_value) as totle,SUM(unum) as unum')

# 二维数组排序

$dataKey = array_column($data,"team_count");
array_multisort($dataKey,SORT_DESC,$data);

array_multisort(array_column($Account,'px'),SORT_ASC,$Account);

# ip地址

$request->server("REMOTE_ADDR")

# fieldRaw多字段统计

->fieldRaw('Sum(prize_value) as totle,SUM(unum) as unum')

# 二维数组排序

$dataKey = array_column($data,"team_count");
array_multisort($dataKey,SORT_DESC,$data);

array_multisort(array_column($Account,'px'),SORT_ASC,$Account);

# 验证器使用

/**
     * 验证数据正确
     * @param array $data
     * @param string $scene
     * @param bool $batch
     * @return array|bool
     */
    private function checkNull($data=[],$scene='',$batch=false)
    {
        $code = 2;
        $msg = '';
        try {
            validate(VoteValidate::class)
                ->batch($batch)
                ->scene($scene)
                ->check($data);
            $code = 1;
        }catch (ValidateException $e){
            $msg = $e->getMessage();
        }
        if ($code == 1) return true;
        return ["code"=>$code,"msg"=>$msg];
    }

# 搜索

$limit = $request->param("limit",15);
$search = $request->param('search_word');
 $where = [];
 $where['vid']=$request->param("vid");
 if (!empty($search)) $where['fullname']=['like',"%$search%"];
$data = VoteBm::where($where)->order("id","desc")->paginate();
return json(["code"=>201,"data"=>$data->items(),"count"=>$data->$data->total()]);
User::whereLike("nickname", $keywords.'%')->column("id")

# Php处理Excel

https://phpspreadsheet.readthedocs.io/en/latest/#getting-started

public function importDo(Request $request)
    {
        $excelFile = $request->file("file");
        $check = new ValidateCheck();
        $checkRes = $check->checkNull(["uploadExcel"=>$excelFile],'excel');
        if ($checkRes !== true) return json($checkRes);
        $year = $request->param("year");

        $objRead = IOFactory::createReader('Xlsx');
        if (!$objRead->canRead($excelFile)) {
            $objRead = IOFactory::createReader('Xls');
            if (!$objRead->canRead($excelFile)) {
                return resMsg(0, '只支持导入Excel文件!', 'reserve' );
            }
        }
        $objPHPExcel = $objRead->load($excelFile);  //$file可以是上传的表格,或者是指定的表格
        $sheet = $objPHPExcel->getSheet(0);   //excel中的第一张sheet
        $highestRow = $sheet->getHighestRow();       // 取得总行数
        $i = 0; //无效数据
        $k=0; //有效数据
        $rem='';
        for ($j = 2; $j <= $highestRow; $j++) { //从第几行开始导入
            $data[$k] = [
                'id' => $objPHPExcel->getActiveSheet()->getCell("A" . $j)->getValue(),
                'name' => $objPHPExcel->getActiveSheet()->getCell("B" . $j)->getValue(),
                'content' => $objPHPExcel->getActiveSheet()->getCell("C" . $j)->getFormattedValue(),
                'year' => $year,
                'create_time' => time(),
            ];
            $k++;
        }
        //排除空值
        foreach ($data as $j => $v){
            if ($v['code'] == null){
                unset($data[$j]);
                $i +=1;
            }
        }
        try {
            Bm::insertAll($data);
        }catch (\ErrorException $e){
            return resMsg(2, $e->getMessage(),'index' );
        }
        if($i !== 0){
            return resMsg(1, '导入成功!总计导入'.$k.'条数据!,本次Excel存在无效数据'.$i.'条,岗位代码为空!','index' );
        }else {
            return resMsg(1, '导入成功!本次导入数据总计'.$k.'条','index' );
        }
    }

# 一次性插入大量数据处理

$count = ceil(count($data)/500);
    for ($h=1;$h<$count+1;$h++){
        $offset=($h-1)* 500;
        $ids=array_slice($data,$offset,500);
        Gw::insertAll($ids);
    }

简单粗暴方法

// $list 是一个1W 条二维数组数据,每次插入 1000条
Model::limit(1000)->insertAll($list);

# 动态查询

// 根据邮箱(email)查询用户信息
User::whereEmail('thinkphp@qq.com')
    ->find();

// 根据昵称(nick_name)查询用户
User::whereNickName('like', '%流年%')
    ->select();
    
// 根据邮箱查询用户信息
User::getByEmail('thinkphp@qq.com');
    
// 根据昵称(nick_name)查询用户信息
User::getByNickName('流年');
    
// 根据邮箱查询用户的昵称
User::getFieldByEmail('thinkphp@qq.com', 'nick_name');
    
// 根据昵称(nick_name)查询用户邮箱
User::getFieldByNickName('流年', 'email');

# 字段比较

可以直接比较两个字段的大小进行查询

User::whereColumn('update_time', '>', 'create_time')
    ->select();
User::whereColumn('score1', '>', 'score2')
    ->select();

如果需要比较两个字段相同,可以使用

User::whereColumn('score1', 'score2')
    ->select();

# 时间表达式查询

对于一些非具体的时间查询,比较适合使用时间表达式进行查询,例如:

// 获取今天的博客
Blog::whereTime('create_time', 'today')
    ->select();
    
// 获取昨天的博客
Blog::whereTime('create_time', 'yesterday')
    ->select();
    
// 获取本周的博客
Blog::whereTime('create_time', 'week')
    ->select();   
    
// 获取上周的博客
Blog::whereTime('create_time', 'last week')
    ->select();    
    
// 获取本月的博客
Blog::whereTime('create_time', 'month')
    ->select();   
    
// 获取上月的博客
Blog::whereTime('create_time', 'last month')
    ->select();      
    
// 获取今年的博客
Blog::whereTime('create_time', 'year')
    ->select();    
    
// 获取去年的博客
Blog::whereTime('create_time', 'last year')
    ->select();     

# 关联删除

/**
     * 删除
     */
    public function delete(Request $request)
    {
        $id = $request->param("id/d");
        $delData = Dks::with(["dkUser","theme","bm","prize","prize"])->find($id);
        try {
            $delData->together(["dkUser","theme","bm","prize"])->delete();
        }catch (\ErrorException $e){
            return error($e->getMessage());
        }
        return success("删除成功!");
    }

    public function batchDel(Request $request)
    {
        $ids = $request->param("ids"); //[1,2,3]
        try {
            foreach ($ids as $item){
                Dks::with(["dkUser","theme","bm","prize","prize"])->find($item)->together(["dkUser","theme","bm","prize","prize"])->delete();
            }
        }catch (\ErrorException $e){
            return error($e->getMessage());
        }
        return success("删除成功!");
    }

# 排名统计

假设一个用户去玩一款游戏,每次结束后会产生一个分数,那么一个用户就有多条记录分值的记录,如何在同一张表中统计 每个玩家最高分在总玩家的排名

条件:一张用户表(user),一个记录玩家成绩的记录表(score)(一个玩家有多条记录,我们要取最高分进行排名)

1、去重查询所有用户的id (score)

$allUserIds = Score::distinct(true)->field("uid")->column("uid");

2、通过关联统计的方式查询所有用户的最高分

$data = User::whereIn("id",$allUserIds)->field("id")->withMax("boy","score")->field("id")->select()->toArray(); // boy为关联方法,score为score表的分数字段
// user模型关联方法
public function boy()
{
    return $this->hasMany(Score::class,"uid","id");//用 用户表的id,关联积分表的uid
}

3、使用一个foreach 循环

$myTop = 0;
foreach ($data as $item){
    if ($item['boy_max'] > $score){
        $myTop +=1;
    }
}
echo $myTop = $myTop+1;

# JWT-AUTH使用方发

https://gitee.com/thans/jwt-auth

中间件形式:

// app/config/middleware

'alias'    => [
        "Auth" => thans\jwt\middleware\JWTAuth::class,
    ],
// controller
protected $middleware = ['Auth'];
$user = [
	"name" => "orangbus"
];
// thans/tp-jwt-auth/src/claim/Expiration 15行修改
return ["code" => 1,"msg" => "token已失效!"];
  • 获取toke

    $token = JWTAuth::builder($user);
    echo $token['name']; // orangbus
    
  • 验证token

    //登录验证
    JWTAuth::auth();
    
    // token验证
    JWTAuth::validate()
    
  • 刷新token

    JWTAuth::refresh(); //返回 token信息,之前的数据依旧存在
    

# 神兽保护

/**
 * _ooOoo_
 * o8888888o
 * 88" . "88
 * (| -_- |)
 *  O\ = /O
 * ___/`---'\____
 * .   ' \\| |// `.
 * / \\||| : |||// \
 * / _||||| -:- |||||- \
 * | | \\\ - /// | |
 * | \_| ''\---/'' | |
 * \ .-\__ `-` ___/-. /
 * ___`. .' /--.--\ `. . __
 * ."" '< `.___\_<|>_/___.' >'"".
 * | | : `- \`.;`\ _ /`;.`/ - ` : | |
 * \ \ `-. \_ __\ /__ _/ .-` / /
 * ======`-.____`-.___\_____/___.-`____.-'======
 * `=---='
 *			.............................................
 *			佛曰:bug泛滥,我已瘫痪!
 */