thinkphp8使用指南

基础和空控制器

07. 基础和空控制器

1. 基础控制器

  • 一般来说,创建控制器后,推荐继承基础控制器来获得更多的功能方法;

  • 基础控制器仅仅提供了控制器验证功能,并注入了think\App和think\Request;

  • 这两个对象后面会有章节详细讲解,下面我们继承并简单使用一下;

    namespace app\controller;
    use app\BaseController;  class User extends BaseController
    {
        public function index()
        {
            // 返回实际路径
            return $this->app->getBasePath();
            // 返回当前方法名
            return $this->request->action();
        }
    }
    

2. 空控制器

  • 空控制器一般用于载入不存在的控制器时,进行错误提示;

    class Error
    {
        public function __call(string $name, array $arguments)
        {
            return "当前控制器不存在!";
        }
    }
    

    08. 创建数据表及填充

1. 创建数据表

  • 我们直接使用phpEnv自带的MySQL操作软件:HeidiSQL,简称HS;

  • 登录的时候,注意修改root和密码后,保存,下次方可直接打开;

  • 首先,我们创建一个数据库:demo,用于测试:

    image-20231009153158426

2. 创建用户表

  • 设置好数据库后,我们创建一个user表,包含id、name、age、gender、details等字段;

    image-20231009154005270

  • 然后,我们填充一些数据,方便查询测试:

    image-20231009154404157

  • 最后,我们通过SQL语句来测试一下:

    image-20231009154542782

09. 连接数据库和查询

1. 连接数据库

  • 我们可以在 config\database.php 配置文件中设置与数据库的连接信息:

    • 如果是一般性数据库连接,在 ‘’connections‘’ 配置区设置即可;

    • 如果是本地测试,它会优先读取 .env 配置,然后再读取 database.php 的配置;

      # .env文件,部署服务器,请禁用我
      APP_DEBUG = true
      
      DB_TYPE = mysql
      DB_HOST = 127.0.0.1
      DB_NAME = demo
      DB_USER = root
      DB_PASS = 123456
      DB_PORT = 3306
      DB_CHARSET = utf8
      
      DEFAULT_LANG = zh-cn
      
    • 如果禁用了 .env 配置,则会读取数据库连接的默认配置:

      // 数据库连接配置信息
      "connections"     => [
          "mysql" => [
              // 数据库类型
              "type"            => env("DB_TYPE", "mysql"),
              // 服务器地址
              "hostname"        => env("DB_HOST", "127.0.0.1"),
              // 数据库名
              "database"        => env("DB_NAME", "demo"),
              // 用户名
              "username"        => env("DB_USER", "root"),
              // 密码
              "password"        => env("DB_PASS", "123456"),
              // 端口
              "hostport"        => env("DB_PORT", "3306"),
      

    2. PHP获取数据

  • 我们暂时没有详细学习此类语法,可以简单用一些了解一下即可:

    // 引入Db数据库类
    use think\facade\Db;  class User extends BaseController
    {
        public function get()
        {
            // 连接user表,查询
            $user = Db::table("user")->select();
            // 输出数据
            return json($user);
        }
    }
    

    10. 构造器之数据查询

1. table方法

  • Db类旗下有一个 table 静态调用的方法,参数为完整的表名(前缀都不能省略);

  • 如果希望只查询一条数据,可以使用 find() 方法,需指定 where 条件:

    // 通过ID查询指定的数据
    // find 方法查询结果不存在,返回 null,否则返回结果数组
    $user = Db::table("user")->where("id", 1)->find();
    
  • 想要了解执行的原生SQL是什么,可以注释掉 return 直接通过 trace 查看;

  • 使用 findOrEmpty() 方法也可以查询一条数据,但在没有数据时返回一个空数组:

    // 没有数据返回空数组
    $user = Db::table("user")->where("id", 11)->findOrEmpty();
    
  • 使用 findOrFail() 方法同样可以查询一条数据,在没有数据时抛出一个异常:

    // 没有数据抛出异常
    $user = Db::table("user")->where("id", 11)->findOrFail();
    
  • 想要获取多列数据,可以使用 select() 方法:

    // 查询所有数据
    $user = Db::table("user")->select();
    
  • select() 方法默认返回 Collection 对象的数据集,可以通过 toArray() 方法转换成数组:

    // 用中断函数,来检测返回值
    $user = Db::table("user")->select();
    halt($user);  // 转换成数组
    $user = Db::table("user")->select()->toArray();
    halt($user);
    
  • 多列数据也可以参与 where() 方法的筛选:

    // 多列筛选
    $user = Db::table("user")->where("age", 14)->select();
    

2. 链式查询

  • 我们发现通过指向符号 “->” 多次连续调用方法称为:链式查询;
  • 当 Db::table(“user”) 时,返回查询对象(Query),即可连缀数据库对应的方法;
  • 当返回查询对象(Query)时,就可以继续调用链式方法,where() 也是链式方法;
  • 而 where() 被调用后,依旧返回(Query),可以再次链式调用;
  • 在手册 数据库 -> 查询构造器 -> 链式操作 可以了解所有可链式的方法:table、where等;
  • 直到遇到 find() 或 select() 返回数组或数据集时,结束查询;# 11. 表前缀之扩展查询

1. 表前缀

  • 一般来说,为了保持表名统一性和防止冲突,都会给表加上一个前缀,以下划线结束;

    • 比如:tp_user,这里的 tp_ 就是表前缀,所有;

    • 我们修改MySQL中表名,然后刷新程序,报错;

    • 当然,你可以传递 Db::table(“tp_user”),但没必要;

  • 首先,我们可以来配置统一前缀:

    • 在 .env 文件中 添加:DBPREFIX = tp

    • 如果部署环境 database.php 中 设置

      "prefix" => env("DB_PREFIX", "tp_"),
      
  • 然后,使用 Db::name(“user”) 方法即可:

    // 此时,tp_ 表名的前缀可以省略
    $user = Db::name("user")->select();
    

2. 扩展查询

  • 通过 value() 方法,可以查询指定字段的值(单个),没有数据返回 null

    // value() 方法查询单个列值
    $user = Db::name("user")->where("id", 3)->value("name");
    
  • 通过 colunm() 方法,可以查询指定列的值(多个),没有数据返回空数组;

    // colunm() 方法查询多个列值
    $user = Db::name("user")->column("name");
    // 通过id 作为索引
    $user = Db::name("user")->column("name,age", "id");
    
  • 当大量数据需要 批处理 时,比如给所有用户更新数据,就不能一次性全取出来,一批一批的来;

    // 批量处理
    Db::name("user")->chunk(2, function ($users) {
        foreach ($users as $user) {
            dump($user);
        }
        echo 1;
    });  // 通过获取最后的SQL语句,发现用的是LIMIT 2
    return Db::getLastSql();
    
  • 另一种处理大量数据:游标查询,为了解决内存开销,每次读取一行,并返回到下一行再读取;

    // 批量处理2
    $users = Db::name("user")->cursor();
    // PHP生成器
    // halt($user);
    foreach ($users as $user) {
        dump($user);
    }
    

12. 数据的新增方式

1. 单条新增

  • 使用 insert() 方法可以向数据表添加一条数据,更多的字段采用默认;

    // 数据
    $data = [
        "name"    => "张麻子",
        "age"     => 28,
        "gender"  => "男",
        "details" => "我脸上没有麻子!"
    ];  // 单条新增,成功返回1
    return Db::name("user")->insert($data);
    
  • 如果想强行新增抛弃不存在的字段数据,则使用 strick(false) 方法,忽略异常;

    // 数据
    $data = [
        "name"    => "马邦德",
        "age"     => 30,
        "gender"  => "男",
        "deta" => "我脸上没有麻子!"
    ];  // 单条新增,成功返回1
    return Db::name("user")->strict(false)->insert($data);
    
  • 如果我们采用的数据库是 mysql,可以支持 replace 写入;

  • insert 和 replace insert 写入的区别,前者表示表中存在主键相同则报错,后者则修改;

    // 新增数据时,主键冲突时,直接修改这条记录
    Db::name("user")->replace()->insert($data);
    
  • 使用 insertGetId() 方法,可以在新增成功后返回当前数据 ID;

    // 返回自增ID
    return Db::name("user")->replace()->insertGetId($data);
    

2. 多条新增

  • 使用 insertAll() 方法,可以批量新增数据,但要保持数组结构一致;

    // 数据
    $data = [[
        "name"    => "林克",
        "age"     => 19,
        "gender"  => "男",
        "details" => "先收集999个呀哈哈!"
    ],[
        "name"    => "普尔亚",
        "age"     => 100,
        "gender"  => "女",
        "details" => "我先来个返老还童,再快速长大!"
    ]];  return Db::name("user")->insertAll($data);
    
  • insertAll() 方法 也支持 replace 写入,如果添加数据量大,可以通过 -> limit() 方法限制添加数量;

    Db::name("user")->replace()->limit(100)->insertAll($data);
    

    13. 更新删除和save方法

1. 数据修改

  • 使用 update() 方法来修改数据,修改成功返回影响行数,没有修改返回 0

    // 修改的数据
    $data = [
        "name" => "王三狗",
        "age"  => "13",
    ];  // 执行修改并返回
    return Db::name("user")->where("id", 4)->update($data);
    
  • 如果修改数据包含了主键信息,比如 id,那么可以省略掉 where 条件;

    // 修改的数据
    $data = [
        "id"   => 4,
        "name" => "王三狗",
        "age"  => "13",
    ];  // 执行修改并返回
    return Db::name("user")->update($data);
    
  • 如果想让一些字段修改时执行 SQL 函数操作,可以使用 exp() 方法实现;

    // 让details字段内的英文大写
    return Db::name("user")->exp("details", "UPPER(details)")->update($data);
    
  • 如果要自增/自减某个字段,可以使用 inc/dec 方法,并支持自定义步长;

    // 修改时,让age自增和自减,默认1,要去掉$data里面age字段的修改,不然冲突
    return Db::name("user")->inc("age")->dec("age", 2)->update($data);  // 派生自字段,延迟执行,毫秒
    setInc("age", 1, 600)
    setDec("age", 2, 600)
    
  • 使用 Db::raw() 来设置每个字段的特殊需求,灵活且清晰:

    // 使用Db::raw 更加清晰灵活
    Db::name("user")->where("id", 4)->update([
        "details"   =>  Db::raw("UPPER(details)"),
        "age"       =>  Db::raw("age-2")
    ]);
    return Db::getLastSql();
    
  • save() 方法是一个通用方法,可以自行判断是新增还是修改(更新)数据;

    // 包含主键,即修改;否则,新增
    return Db::name("user")->save($data);
    

2. 数据删除

  • 极简删除可以根据主键直接删除,删除成功返回影响行数,否则 0;

    // 根据主键删除
    Db::name("user")->delete(8);
    
  • 根据主键,还可以删除多条记录;

    // 根据主键删除多条
    Db::name("user")->delete([48,49,50]);
    
  • 正常情况下,通过 where()方法来删除;

    // 条件删除
    Db::name("user")->where("id", 47)->delete();
    
  • 清空表以及逻辑软删除,参考手册即可;逻辑软删除,在模型篇单独讲解,这里略过。

14. 查询表达式规则

1. 表达式查询

  • 查询表达式支持大部分常用的 SQL 语句,语法格式如下:

    where("字段名","查询表达式","查询条件");
    
  • 所有的表达式,查阅手册 -> 查询表达式 中的表格即可;这里列出几个意思一下:

    | 表达式 | 含义 | 快捷方式 |
    | :————: | :———————: | :———-: |
    | = | 等于 | |
    | <= time | 小于等于某个时间 | whereTime |
    | EXP | SQL表达式查询 | whereExp |
    | [NOT] LIKE | 模糊查询 | whereLike |
    | [NOT] IN | [非] IN 查询 | whereIN |

2. 查询示例

  • 条件判断类的,id大于4的;

    // 查询id大于4的数据
    $user = Db::name("user")->where("id", ">", 4)->select();
    return json($user);
    
  • Like模糊查询,姓王的;

    // 查询姓王的用户
    $user = Db::name("user")->where("name", "like", "王%")->select();
    // like快捷方式
    $user = Db::name("user")->whereLike("name", "王%")->select();
    
  • IN区间查询,根据id;

    // 区间查询,支持not in
    $user = Db::name("user")->where("id", "in", "1, 3, 5")->select();
    // 语义更好一点
    $user = Db::name("user")->where("id", "in", [1,3,5])->select();
    // IN快捷查询,两种均可,支持whereNotIn
    $user = Db::name("user")->whereIn("id", [1, 2, 3])->select();  // Between,和IN一样 支持 not between
    $user = Db::name("user")->where("id", "between", [2,5])->select();
    // 快捷方式和IN一样:whereBetween和whereNotBetween
    
  • NULL查询;

    // NULL,  null 或 not null:
    $user = Db::name("user")->where("details", "not null")->select();
    // 快捷方式:whereNull和whereNotNull
    
  • EXP查询,自定义SQL片段;

    // EXP查询,自定义SQL
    $user = Db::name("user")->where("id", "EXP", "<> 8 and id >5")->select();
    // 快捷查询
    $user = Db::name("user")->whereExp("id","<> 8 and id >5")->select();
    
  • 这里推荐:有快捷方式的用快捷方式,通过Ctrl+方法名得知,快捷方式绕过了很多拼装流程,速度更快;

15. 超多查询都不讲- 警告:这里罗列了大量的快捷查询的示例、链式查询以及其它非常用的查询方法;

  • 介于TP6课程大家的反馈,我这里不再详细讲解每个方法的用法;
  • 但我会录入在讲义里,方便后续项目课程时候回头查阅;后续类似的知识点也这么砍;

1. 字符串条件(不讲)

  • whereRaw 可以直接写入多条件:

    // 多条件字符串
    $user = Db::name("user")->whereRaw("age > 15 AND gender="女"")->select();
    
  • 包含变量的多条件查询:

    // 变量
    $age = 15;
    $gender = "女";  // 预处理机制
    $user = Db::name("user")->whereRaw("age>:age AND gender=:gender", [
        "age"       => $age,
        "gender"    => $gender
    ])->select();
    

    2. field()字段筛选(不讲)

  • 使用 field() 方法,可以指定要查询的字段;

    // 字段筛选
    $user = Db::name("user")->field("id, age, gender")->select();
    $user = Db::name("user")->field(["id, age, gender"])->select();
    
  • 使用 field() 方法,给指定的字段设置别名;

    // 字段别名
    $user = Db::name("user")->field("id, gender as sex")->select();
    $user = Db::name("user")->field(["id", "gender"=>"sex"])->select();
    
  • fieldRaw() 方法里,可以直接给字段设置 MySQL 函数;

    // 直接SQL函数
    $user = Db::name("user")->fieldRaw("id, UPPER(details)")->select();
    $user = Db::name("user")->field(true)->select();   // 推荐
    return Db::getLastSql();
    
  • 使用 withoutField() 方法中字段排除,可以屏蔽掉想要不显示的字段;

    // 排除字段
    $user = Db::name("user")->withoutField("details")->select();
    
  • 使用 field() 方法在新增时,验证字段的合法性;

    // 排除新增字段
    Db::name("user")->field("name,age,gender")->insert($data);
    

3. 常用链式方法(不讲)

  • 使用 alias() 方法,给数据库起一个别名;

    // 给数据库起个别名
    Db::name("user")->alias("a")->select();
    return Db::getLastSql();  // 起别名最主要是和另一张表进行关联,这里看手册好了,没表测试
    alias("a")->join()
    
  • 使用 limit() 方法,限制获取输出数据的个数;

    // 显示前5条
    $user = Db::name("user")->limit(5)->select();
    
  • 分页模式,即传递两个参数,比如从第 3 条开始显示 5 条 limit(2,5);

    // 从第2个位置,也就是第3条开始,显示5条
    $user = Db::name("user")->limit(2,5)->select();
    // 查询第一页数据,1至10条
    $user = Db::name("user")->page(1,10)->select();
    
  • 使用 order() 方法,可以指定排序方式,没有指定第二参数,默认 asc;

    // 按id倒序排列
    $user = Db::name("user")->order("id", "desc")->select();
    
  • 支持数组的方式,对多个字段进行排序;

    // 按多个字段规则排序
    $user = Db::name("user")->order(["age"=>"asc", "id"=>"desc"])->select();
    //支持 orderRaw() 方法,可以传入SQL函数,和前面各类Raw一样,不再赘述
    
  • 使用 group() 方法,给性别不同的人进行 age 字段的总和统计;

    // 统计性别的年龄总和
    $user = Db::name("user")->fieldRaw("gender, SUM(age)")
                            ->group("gender")->select();
    
  • 使用 group() 分组之后,再使用 having() 进行筛选;

    // 统计性别的年龄总和,筛选大于100的
    $user = Db::name("user")->fieldRaw("gender, SUM(age)")
                            ->group("gender")
                            ->having("SUM(age) > 100")->select();
    

4. 时间查询(不讲)

  • 可以使用 >、<、>=、<= 来筛选匹配时间的数据;

    // 传统时间筛选
    $user = Db::name("user")->where("create_time", ">", "2022-1-1")->select();
    $user = Db::name("user")->where("create_time", "between", ["2020-1-1", "2023-1-1"])->select();
    
  • 快捷方式 whereTime

    // 使用快捷方式查询
    $user = Db::name("user")->whereTime("create_time", ">=", "2022-1-1")->select();  // 默认是 > 可以省略
    $user = Db::name("user")->whereTime("create_time", "2022-1-1")->select();
    
  • 区间查询快捷方式 whereBetweenTime

    // 区间查询,包含 whereNotBetweenTime
    $user = Db::name("user")->whereBetweenTime("create_time", "2020-1-1", "2023-1-1")->select();
    
  • 使用 whereYear 查询今年的数据、去年的数据和某一年的数据;

    // 查询今年
    $user = Db::name("user")->whereYear("create_time")->select();
    // 查询去年
    $user = Db::name("user")->whereYear("create_time", "last year")->select();
    // 查询某一年
    $user = Db::name("user")->whereYear("create_time", "2019")->select();
    
  • 使用 whereMonth 查询当月的数据、上月的数据和某一个月的数据;

    Db::name("user")->whereMonth("create_time")->select();
    Db::name("user")->whereMonth("create_time", "last month")->select();
    Db::name("user")->whereMonth("create_time", "2020-6")->select();
    
  • 使用 whereDay 查询今天的数据、昨天的数据和某一个天的数据;

    Db::name("user")->whereDay("create_time")->select();
    Db::name("user")->whereDay("create_time", "last day")->select();
    Db::name("user")->whereDay("create_time", "2020-6-27")->select();
    
  • 查询指定时间的数据,比如两小时内的;

    // 两小时内的
    $user = Db::name("user")->whereTime("create_time", "-2 hours")->select();
    
  • 查询两个时间字段时间有效期的数据,比如活动开始到结束的期间;

  • 比如创建两个字段:start_time,end_time,注册后,分别写入对应时间表明它的有效期;

    php // 直接这么写,不太好理解,看手册的另一种普通写法很容易理解 // 实战中,字段丰富的时候再演示 $user = Db::name("user")->whereBetweenTimeField("start_time", "end_time")->select();### 5. 聚合查询(不讲)

  • 使用 count() 方法,可以求出所查询数据的数量;

    // 获取记录数
    $user = Db::name("user")->count();
    
  • count() 可设置指定 id,比如有空值(Null)的 details,不会计算数量;

    // 值NULL不计数
    $user = Db::name("user")->count("details");
    
  • 使用 max() 方法,求出所查询数据字段的最大值;

    // 求最大年龄
    $user = Db::name("user")->max("age");
    
  • 如果 max() 方法,求出的值不是数值,则通过第二参数强制转换;

    // 如果最大值不是数值,false关闭强制转换
    $user = Db::name("user")->max("name", false);
    
  • 使用 min() 方法,求出所查询数据字段的最小值,也可以强制转换;

    // 求最小值
    $user = Db::name("user")->min("age");
    
  • 使用 avg() 方法,求出所查询数据字段的平均值;

    // 求平均值
    $user = Db::name("user")->avg("age");
    
  • 使用 sum() 方法,求出所查询数据字段的总和;

    // 求总和
    $user = Db::name("user")->sum("age");
    

    6. 子查询(不讲)

  • 使用 fetchSql() 方法,传递参数true时,可以设置不执行 SQL,直接返回SQL语句;

    // 子查询语句
    $user = Db::name("user")->fetchSql(true)->select();
    
  • 使用 buildSql() 方法,也是返回 SQL 语句,不需要再执行 select(),且有括号;

    // 第二种子查询
    $subQuery = Db::name("user")->buildSql(true);
    
  • 结合以上方法,我们实现一个子查询;

    // 子查询样式
    $subQuery = Db::name("user")->field("id")->where("age",">", 18)->buildSql();
    $user = Db::name("user")->whereExp("id", "IN ".$subQuery)->select();
    
  • 使用闭包的方式执行子查询;

    // 采用闭包构建子查询
    $user = Db::name("user")->where("id", "IN", function ($query) {
        $query->name("user")->field("id")->where("age",">", 18);
    })->select();
    

7. 原生查询

  • 使用 query() 方法,进行原生 SQL 查询,适用于读取操作,SQL 错误返回 false;

    // 原生SQL
    $user = Db::query("SELECT * FROM tp_user");
    
  • 使用 execute 方法,进行原生 SQL 更新写入等,SQL 错误返回 false;

    // 原生更新写入
    $user = Db::execute("update tp_user set details="快快快来救我!" where id=5");
    

    8. 列字段快捷查询(不讲)

  • 之前用过诸如:whereIn、whereExp、whereLike等等快捷查询;

  • 所有快捷查询列表的手册位置:数据库 -> 查询构造器 -> 高级查询中,找到快捷查询表格;

  • whereColumn() 方法,比较两个字段的值,符合的就筛选出来;

    // 字段比较,id大于age
    $user = Db::name("user")->whereColumn("id", ">", "age")->select();  // 如果是 等于判断 可以简化
    ->whereColumn("id", "age")
    
  • whereFieldName() 方法,查询某个字段的值,注意 FileName 是字段名;

    // 获取所有性别为:男
    $user = Db::name("user")->whereGender("男")->select();  // 获取名字叫王二狗的信息
    $user = Db::name("user")->whereName("王二狗")->find();
    
  • getByFieldName() 方法,查询某个字段的值,注意只能查询一条,不需要 find()

    // 单条数据
    $user = Db::name("user")->getByName("王二狗");
    
  • getFieldByFieldName() 方法,通过查询得到某个指定字段的单一值;

    // 查询单条并返回单列,找出王二狗的年龄
    $user = Db::name("user")->getFieldByName("王二狗", "age");
    

9. 条件查询(不讲)

  • when() 可以通过条件判断,执行闭包里的分支查询;

    ```php
    // 条件判断
    $user = Db::name(“user”)->when(false, function ($query) {

    // 满足条件执行这段SQL
    $query->where("id", ">", 5);
    

    }, function ($query) {

    // 不满足条件执行这段SQL
    $query->where("id", "<=", 5);
    

    })->select();
    ```### 10. 事务(不讲)

  • 数据库的表引擎需要是 InnoDB 才可以使用,如果不是调整即可;

  • 事务处理,需要执行多个 SQL 查询,数据是关联恒定的;

  • 如果成功一条查询,改变了数据,而后一条失败,则前面的数据回滚;

  • 比如:银行取钱,银行ATM扣了1000,但入口被卡住,你没拿到,这时需要事务处理;

  • 系统提供了两种事务处理的方式,第一种是自动处理,出错自动回滚;

    // 出现异常回滚
    Db::transaction(function () {
        Db::name("user")->delete(12);
        Db::name("user")->findOrFail(13);
    });
    
  • 手动处理,基本和原生处理类似,可以自行输出错误信息;

    // 启动事务
    Db::startTrans();
    try {
        Db::name("user")->delete(12);
        Db::name("user")->findOrFail(13);
        //提交事务
        Db::commit();
    } catch (\Exception $e) {
        echo "执行SQL失败!";
        // 回滚
        Db::rollback();
    }
    

11. 获取器(不讲)

  • 获取器的意思就是:将数据的字段进行转换处理再进行操作;

  • 比如在获取数据列表的时候,将获取到的详情字段全部大写;

    // 获取器改变字段值
    $user = Db::name("user")->withAttr("details", function ($value, $data) {
        // NULL 不处理
        if ($value != null) {
            return strtoupper($value);
        }
    })->select();
    
  • withAttr也是支持JSON字段的,具体参考手册 查询构造器 -> 获取器;

16. 关联索引查询

1. 索引关联

  • where 方法的数组查询:

    // 性别男,年龄大于15岁,常规做法
    $user = Db::name("user")->where("age", ">", 15)
                            ->where("gender", "男")->select();  // 索引数组方式,二维数组,返回的SQL 是一条 AND 并列关系
    $user = Db::name("user")->where([
        ["age", ">", "15"],
        ["gender","=", "男"]
    ])->select();  // 如果是等于,可以直接用关联数组,一维
    $user = Db::name("user")->where([
        "age"     =>  15,
        "gender"  =>  "男"
    ])->select();  // 两种模式结合起来,
    $user = Db::name("user")->where([
        ["age", ">", "15"],
        "gender"  =>  "男"
    ])->select();  // 搜索条件独立管理,这里=号写全
    $map[] = ["age", ">", "15"];
    $map[] = ["gender","=", "男"];  $user = Db::name("user")->where($map)->select();
    

    17. 拼装高级查询

1. 拼装查询

  • 使用 |(OR)&(AND) 来实现 where 条件的高级查询,where 支持多个连缀;

    // or和and 拼装查询
    $user = Db::name("user")->where("name|details", "like", "%王%")
                            ->where("id&create_time", ">", 0)
                            ->select();  // 拼装返回的SQL
    SELECT * FROM `tp_user` WHERE ( `name` LIKE "%王%" OR `details` LIKE "%王%" ) AND ( `id` > 0 AND `create_time` > "0" )
    
  • 索引数组方式,可以在 where 进行多个字段进行查询;

    // 索引数组拼装
    $user = Db::name("user")->where([
        ["id", ">", "5"],
        ["gender", "=", "女"],
        ["age", "<=", 15],
        ["details", "like", "%我%"]
    ])->select();  // 拼装返回的SQL
    SELECT * FROM `tp_user` WHERE `id` > 5 AND `gender` = "女" AND `age` <= 15 AND `details` LIKE "%我%"
    
  • 根据之前的课程中,条件字符串复杂组装,比如使用 exp 了,就使用 raw() 方法;

    // exp 拼装
    $user = Db::name("user")->where([
        ["gender", "=", "男"],
        ["age", "exp", Db::raw(">=10 AND id<5")]
    ])->select();  // 拼装返回的SQL
    SELECT * FROM `tp_user` WHERE `gender` = "男" AND ( `age` >=10 AND id<5 )
    
  • 如果有多个where,并需要控制优先级,那么在可以在需要的部分加上中括号;

    // 下面的代码无法控制优先级
    $user = Db::name("user")->where([
        ["gender", "=", "男"],
        ["age", "exp", Db::raw(">=10 AND id<5")]
    ])->where("details", "like", "%我%")->select();  // 外加一个中括号
    ->where([[
        ...
    ]])
    
    // 拼装返回的SQL
    SELECT * FROM `tp_user` WHERE ( `gender` = "男" AND ( `age` >=10 AND id<5 ) ) AND `details` LIKE "%我%"
    
    // 推荐用变量代替
    $map =[
        ["gender", "=", "男"],
        ["age", "exp", Db::raw(">=10 AND id<5")]
    ];
    ->where([$map])
    
  • 如果,条件中有多次出现一个字段,并且需要 OR 来左右筛选,可以用 whereOr

    // 多条件重复字段 OR 选项
    $map1 = [
        ["name", "like", "%王%"],
        ["details", "=", null]
    ];
    $map2 = [
        ["gender", "=", "女"],
        ["details", "exp", Db::raw("IS NOT NULL")]
    ];  $user = Db::name("user")->whereOr([$map1, $map2])->select();  // 拼装返回的SQL
    SELECT * FROM `tp_user` WHERE ( `name` LIKE "%王%" AND `details` IS NULL ) OR ( `gender` = "女" AND ( `details` IS NOT NULL ) )
    

18. 模型的定义方式

1. 定义模型

  • 为了避免被前面课程中控制器的类名干扰,删除或改名都行:

    // UserBak.php,目前不存在任何地方的User.php了
    class UserBak extends BaseController
    
  • 定义一个和数据库表相匹配的模型,可在app应用目录下创建model文件夹;

    namespace app\model;
    use think\Model;  class User extends Model
    {
    
    }
    
  • 模型会自动对应数据表,并且有一套自己的命名规则;

  • 模型类需要去除表前缀(tp_),采用驼峰式命名,并且首字母大写;

    tp_user(表名) => User
    tp_user_type(表名) => UserType
    
  • 在控制器段创建一个任意名称的类,当然有语义更好,但为了教学理解起名为:TestUser.php;

    namespace app\controller;
    use app\model\User;
    
    // 注意:类名不限制
    class TestUser
    {
        public function index()
        {
            return json(User::select());
        }
    }
    

2. 模型设置

  • 系统会自动识别 模型类名 对应 表名,User.php 对应 user 表(不含前缀);

  • 但如果你的模型类名不是按照规则对应表名,则需要通过成员字段去设置;

    class Abc extends Model
    {
        // 设置表名
        protected $name = "user";
    }  // 使用$table时,指定表时需要完整的表名:tp_user
    
  • 系统也会默认id为你的主键名,如果不是id,则需要设置;

    // 设置主键
    protected $pk = "uid";
    
  • 模型支持初始化功能,需要设置静态方法,并只在第一次实例化的时候执行,且只执行一次;

    protected static function init()
    {
        echo "初始化";
    }