ThinkPHP6 学习笔记

3,255 阅读8分钟

写在最前面

差不都10年前就接触过 ThinkPHP,后来再接触 ThinkPHP 已经是到5了。借这次新版本的更新,系统重新再学习下。

如有错误,还请大佬们支出,中国加油!武汉加油!

官方手册

www.kancloud.cn/manual/thin…

版本要求

PHP7.1+ 官方推荐7.3 MySQL5.7+ 数据库可默认支持JSON数据格式处理

安装

  1. composer改国内镜像composer config -g repo.packagist composer https://mirrors.aliyun.com/composer/
  2. composer create-project topthink/think tp6
  3. cd tp6
  4. composer require topthink/think-view
  5. php think run

开发规范

  1. 文件夹名:小写和下划线(例:index)
  2. 类名:首字母大写驼峰式(例:User UserType)
  3. 函数:小写和下划线(什么是函数?不是方法吗?)
  4. 方法:首字母小写驼峰式(例:getUserName)
  5. 属性:首字母小写驼峰式(例:tableName)
  6. 魔术方法:__全部小写(例:构造方法)
  7. 常量:全大写加下划线(例:DIRECTORY_SEPARATOR)
  8. 配置参数:小写加下划线(例:config/app.php)
  9. 环境变量:全大写加下划线(例:APP_DEBUG)
  10. 数据表和字段:小写和下划线(例:tp_user user_name)

目录结构

  1. 默认单应用模式
  2. 多应用在app下建立(app/index app/admin)
  3. 默认只有public对外可访问,生产环境部署到服务器,推荐使用宝塔设置访问[运行目录]到public

服务器二级目录配置

这里以宝塔的IIS为例

  1. 在域名设置伪静态规则
<?xml version="1.0" ?>
<rules>
	<rule name="OrgPage_tp6_rewrite_test1" stopProcessing="true">
		<match url="^tp6_test1(.*)$"/>
		<conditions logicalGrouping="MatchAll">
			<add input="{HTTP_HOST}" pattern="^(.*)$"/>
			<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
			<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true"/>
		</conditions>
		<action type="Rewrite" url="tp6_test1/index.php/{R:1}"/>
	</rule>
	<rule name="OrgPage_tp6_rewrite_test2" stopProcessing="true">
		<match url="^tp6_test2(.*)$"/>
		<conditions logicalGrouping="MatchAll">
			<add input="{HTTP_HOST}" pattern="^(.*)$"/>
			<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true"/>
			<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true"/>
		</conditions>
		<action type="Rewrite" url="tp6_test2/index.php/{R:1}"/>
	</rule>
</rules>
  1. 删除 tp 目录下的 web.config
  2. 在 tp 根目录新建 index.php
<?php
require 'public/index.php';

多应用模式

  1. composer require topthink/think-multi-app
  2. RESTFul 资源控制器 php think make:controller api@Index --api
  3. app.php 配置默认访问入口 'default_app' => 'api',

跳转操作

TP6 默认不在提供 success、error、redirect和result,需要自行安装

composer require liliuwei/thinkphp-jump

开启调试

  1. TP6默认未开启调试模式
  2. 根目录 .example.env 重命名成 .env 就开启调试了(APP_DEBUG = true)
  3. .env 仅用于本地开发测试,生产环境会被忽略(我试过一次,放在服务器上貌似还是有效的。。。)
  4. 本地测试 .env 优先级高于 config

获取 .env 配置信息

use think\facade\Env;
Env::get('DATABASE.HOSTNAME');

获取 config 配置信息

use think\facade\Config;
Config::get('app.default_timezone');
Config::get('database.connections.mysql.hostname');

判断配置存在并返回布尔值

Env::has('DATABASE.HOSTNAME');
Config::has('app.default_timezone');

URL 访问模式

网址/控制器/方法/参数名/参数


控制器新建

新建继承基础控制器(BaseController)的 HelloWorld.php 控制器

<?php
namespace app\controller;

use app\BaseController;

class HelloWorld extends BaseController
{
    public function index()
    {
        return 'HelloWorld';
    }
}

initialize() 控制器初始化方法,必须继承 BaseController 才能使用

class HelloWorld extends BaseController
{
    public function initialize(){
        echo 'initialize';
    }
}

控制器渲染输出

  1. 使用方法内的 return
  2. return json($data)
  3. 中断代码实行不推荐使用die或者exit,推荐助手函数halt()

基础控制器

  1. 基础控制器提供控制器验证,并注入了 think\Appthink\Request
  2. 获取控制器方法名 $this->request->action()
  3. 获取当前实际路径 $this->app->getBasePath()

空控制器

仅用于控制器不存在的错误提示页面 新建 Error.php 控制器

<?php
namespace app\controller;
class Error
{
    public function index()
    {
        return '控制器不存在';
    }
}

多级控制器

  1. 新建多级控制器 app\controller\group\Blog.php
  2. namespace app\controller\group
  3. 访问 http://127.0.0.1/group.blog/
  4. 更多方法 http://127.0.0.1/group.blog/read

数据库连接

  1. .env 优先于 config/database.php 的配置
  2. 服务器会忽略 .env 直接读取 config/database.php 的配置

门面方式连接数据库

use think\facade\Db;
Db::table('tp6_user')->select();

使用 name 可以省略前缀

use think\facade\Db;
Db::name('user')->select();

使用 connect() 可以切换 database.php 内配置的多个数据库

Db::connect('mysql')->table('tp6_user')->select();

模型连接据库

创建 app/model/User.php

<?php
namespace app\model;
use think\Model;
class User extends Model
{
    
}

在控制器中使用

use app\model\User as UserModel;
UserModel::select();

门面方式单数据查询

find() 只返回1条数据,没有则返回 null,返回的是数组(Array)

Db::name('user')->where('id',1)->find();

value() 获取单数据具体值

Db::name('user')->where('id',1)->value('username');

getBy**() 只查询返回1条,不需要find()

Db::name('user')->getByEmail('oy@qq.com');

getFieldBy**() 只查询返回1条,不需要find(),并且只返回制定的字段

Db::name('user')->getFieldByEmail('oy@qq.com','email');

门面方式多数据查询

select() 返回数据集,没有则返回空数组,返回的是数据集对象(Colletion)

Db::name('user')->select();

field() 指定显示数据列,find同样可用,性能更好

Db::name('user')->field('username,email')->select();

withoutField() 排除指定显示数据列

Db::name('user')->withoutField('username,email')->select();

field() 设置别名

Db::name('user')->field('username as user,gender as sax')->select();

group() 搭配 field() 获取某字段所有不通数值,等于去重

Db::name('user')->field('username')->group('username')->select();

limit() 限制显示条数

Db::name('user')->limit(3)->select();

page() 页数显示 第一个参数是第几页,第二个参数是显示几个

Db::name('user')->page(1,5)->select();

order() 排序顺序 asc正序(默认) desc倒序

Db::name('user')->order('id','asc')->select();

直接转换成数组

Db::name('user')->select()->toArray();

column() 获取具体值的指定列多数据,第二个参数可设置为索引一般用id

Db::name('user')->column('username');
Db::name('user')->column('username','id');

whereColumn() 两个数据对比查询

Db::name('user')->whereColumn('update_time','>','create_time')->select();

where**() 查找某个字段的值 **部分是数据表中字段的名称

Db::name('user')->whereUsername('oy')->select();
Db::name('user')->whereEmail('oy@qq.com')->select();

优化门面方式多数据查询

chunk() 每次读取指定数量数据,大数据量效果明显,节约内存开销

Db::name('user')->chunk(3,function($users){
    foreach ($users as $user) {
        dump($user);
    }
});

cursor() 每次只读取一条,大数据量效果明显,节约内存开销

$cursor = Db::name('user')->cursor();
foreach ($cursor as $user) {
    dump($user);
}

链式查询

www.kancloud.cn/manual/thin…

优化查询

每次使用 Db 都会创建一个实例,如果多次使用,可以把对象保存下来。 此外,同一个对象实例第二次查询会保留第一次的数值,如要清空第一次的值,请使用 removeOption('where')

$userQuery = Db::name('user');
$userFind = $userQuery->where('id',1)->find();
$userSelect = $userQuery->removeOption('where')->select();

门面方式数据库新增

insert() 添加一条数据,返回值是添加的数据数量

$data = [
    'username'=>'OY',
    'email'=>'oy@qq.com',
    'gender'=>'男',
    'price'=>'100',
    'details'=>'123',
];
Db::name('user')->insert($data);

field() 限制可新增的字段,不在范围内的字段添加会报错并添加失败

Db::name('user')->field('username,email,gender,price,details')->insert($data);

如果添加不存在字段,无视报错强制插入,使用 strict(false)

Db::name('user')->strict(false)->insert($data);

replace() insert表中存在相同主键会报错,replace则会修改

Db::name('user')->replace()->insert($data);

insertGetId() 新增数据后返回新增数据的主键id值

Db::name('user')->insertGetId($data);

insertAll() 批量添加多条数据,返回值是添加的数据数量

$data = [
    [...],
    [...],
    [...],
];
Db::name('user')->insertAll($data);

save()通用方法

  1. 不存在主键则新增
  2. 存在主键则修改
  3. 门面方式没有saveAll(),只有模型才有saveAll()
Db::name('user')->save($data);

修改数据

update() 需要指向主键,成功返回修改的行数,数据相同则返回0

$data = [
    'id'=>1,
    'username'=>'OY',
];
return Db::name('user')->update($data);

或者使用 where()

$data = [
    'username'=>'OY',
];
return Db::name('user')->where('id',1)->update($data);

如果要更新的数据需要使用SQL函数,使用exp()

$data = [
    'username'=>'OY923',
];
return Db::name('user')->where('id',1)
                        ->exp('email','UPPER(email)')
                        ->update($data);

自增和自减

return Db::name('user')->where('id',1)
                        ->inc('price')
                        ->dec('details')
                        ->update($data);

raw 兼容以上2种方法,可读性更高

$data = [
    'id'=>1,
    'email'=>Db::raw('UPPER(email)'),
    'price'=>Db::raw('price+1'),
    'details'=>Db::raw('details-1'),
];

门面方式删除数据

delete() 通过主键删除数据,成功返回删除的行数,没有找到删除的数据则返回0

Db::name('user')->delete(1);
Db::name('user')->where('id',1)->delete();

删除多条数据

Db::name('user')->delete([1,2,3]);

门面方式数据库查询

比较查询,where 如果是 = 可以省略,<> 是不等于

Db::name('user')->where('id','=',6)->find();
Db::name('user')->where('id',6)->find();
Db::name('user')->where('id','>',6)->select();
Db::name('user')->where('id','<>',6)->select();

区间查询,like 模糊查询,link 多条件下默认是 and

Db::name('user')->where('email','like','oy%')->select();
Db::name('user')->where('email','like',['oy%','tb%'])->select();
Db::name('user')->where('email','like',['oy%','tb%'],'or')->select();
Db::name('user')->whereLike('email','oy%')->select();
Db::name('user')->whereNotLike('email','oy%')->select();
Db::name('user')->whereOr([
    ['email','like','oy%'],
    ['email','like','oldyellow%']
])->select();

区间查询,between 字符串和数组模式都可以

Db::name('user')->where('id','between','2,10')->select();
Db::name('user')->where('id','between',[2,10])->select();
Db::name('user')->whereBetween('id',[2,10])->select();
Db::name('user')->whereNotBetween('id',[2,10])->select();

区间查询,in 指定数据,字符串和数组模式都可以

Db::name('user')->where('id','in','5,10,12')->select();
Db::name('user')->where('id','in',[5,10,12])->select();
Db::name('user')->whereIn('id',[5,10,12])->select();
Db::name('user')->whereNotIn('id',[5,10,12])->select();

区间查询,null

Db::name('user')->where('uid','null')->select();
Db::name('user')->where('uid','not null')->select();
Db::name('user')->whereNull('uid')->select();
Db::name('user')->whereNotNull('uid')->select();

EXP查询 SQL语法自定义查询

Db::name('user')->where('id','exp','IN(5,10,12)')->select();

whereRaw 条件部分直接使用 SQL 语句查询

Db::name('user')
    ->whereRaw('SQL语句')
    ->select();

门面方式数据库时间查询

比较查询,where 如果是 = 可以省略

Db::name('user')->where('create_time','=','2020-1-20')->select();
Db::name('user')->where('create_time','2020-1-20')->select();

多条件查询

Db::name('user')->where([
    ['username','=','OY9'],
    ['price','>','100'],
])->select();

区间查询,between 其中 whereTime 可省略 > , whereBetweenTime 是数组变字符串方式

Db::name('user')->where('create_time','>','2020-1-20')->select();
Db::name('user')->whereTime('create_time','>','2020-1-20')->select();
Db::name('user')->where('create_time','between',['2020-1-20','2020-1-21'])->select();
Db::name('user')->whereBetween('create_time',['2020-1-20','2020-1-21'])->select();
Db::name('user')->whereNotBetween('create_time',['2020-1-20','2020-1-21'])->select();
Db::name('user')->whereBetweenTime('create_time','2020-1-20','2020-1-21')->select();

固定查询 whereYear whereMonth whereDay

Db::name('user')->whereYear('create_time')->select();
Db::name('user')->whereYear('create_time','last year')->select();
Db::name('user')->whereYear('create_time','2016')->select();

Db::name('user')->whereMonth('create_time')->select();
Db::name('user')->whereMonth('create_time','last month')->select();
Db::name('user')->whereMonth('create_time','2016-6')->select();

Db::name('user')->whereDay('create_time')->select();
Db::name('user')->whereDay('create_time','last day')->select();
Db::name('user')->whereDay('create_time','2016-6-6')->select();

有效期查询 whereBetweenTimeField()

Db::name('user')->whereBetweenTimeField('start_time','end_time')->select();

门面方式数据库聚合查询

count 数据总条数

$data = Db::name('user')->count();

max 最大值

$data = Db::name('user')->max('price');

min 最小值

$data = Db::name('user')->min('price');

avg 平均值

$data = Db::name('user')->avg('price');

sum 总和

$data = Db::name('user')->sum('price');

门面方式数据库子查询

数据分成多个表存放,子表通过 uid 和主表 id 连接 buildSql() 返回的是SQL子查询语句

$subQuery = Db::name('marry')->field('uid')->where('marry',1)->buildSql();
$result = Db::name('user')->where('id','exp','IN '.$subQuery)->select();

也可以用闭包,这里不需要再写 buildSql()

$result = Db::name('user')->where('id','in',function($query){
    $query->name('marry')->field('uid')->where('marry',1);
})->select();

门面方式数据库原生SQL语句查询

query() 适合读取 Db::query();

execute() 适合更新和写入 Db::execute();

门面方式判断运行数据库语句

when() 通过第一个参数判断,类似if条件语句

Db::name('user')->when(true,function($query){
    $query->where('username',1);
},function($query){
    $query->where('username',2);
})->select();

事务处理

数据库表的存储引擎,必须是 InnoDB。 简单理解就是,2件事情,前者失败,后者即使成功也回滚。 或者前者成功,后者失败,前者也回滚。 只能对错误表或者字段实现。

自动

Db::transaction(function () {
    Db::name('user1')->where('id',1)->save(['price'=>Db::raw('price+1')]);
    Db::name('user')->where('id',7)->save(['price'=>Db::raw('price+1')]);
});

手动,可自定义报错后的处理

Db::startTrans();
try {
    Db::name('user1')->where('id',1)->save(['price'=>Db::raw('price+1')]);
    Db::name('user')->where('id',7)->save(['price'=>Db::raw('price+1')]);
    // 提交事务
    Db::commit();
} catch (\Exception $e) {
    echo '失败';
    // 回滚事务
    Db::rollback();
}

门面方式获取器

withAttr() 对获取的数据2次处理,然后return再输出。

$data = Db::name('user')->withAttr('email',function($value,$data){
    return strtoupper($value);
})->select();

dump($data);

门面方式数据集

www.kancloud.cn/manual/thin…

$data = Db::name('user')->select();
dump($data->toArray());
$data = Db::name('user')->select();
dump($data->shuffle());
$data = Db::name('user')->select();
dump($data->whereIn('id',[5,8,10]));

模型连接据库

创建 app/model/User.php

<?php
namespace app\model;
use think\Model;
class User extends Model
{
    
}

模型在控制器中使用

use app\model\User as UserModel;
UserModel::select();

模型初始化

class User extends Model
{
    protected static function init()
    {
        echo '初始化';
    }
}

模型新增

save() 模型新增必须要实例化,门面方式不需要。返回添加数量。

$data = [
    'username'=>'OY5',
    'email'=>'oy@qq.com',
    'gender'=>'男',
    'price'=>'100',
    'details'=>'123',
];
$user = new UserModel();
$result = $user->save($data);

获取插入数据的id,只有save方法有。

$user->id;

此外发现,模型的insert()新增,无需实例化,为啥这就可以不需要实例化?

UserModel::insert($data);

allowField() 允许写入字段,参数为数组格式。

$user->allowField(['username'])->save($data);

saveAll() 批量新增数据,同样需要实例化,返回的是添加数据的数组。

$data = [
    [...],
    [...],
    [...],
];
$user = new UserModel();
result = $user->saveAll($data);

create() 静态方法,无需实例化,TP6新增的官方推荐使用。

$data = [
    'username'=>'OY5',
    'email'=>'oy@qq.com',
    'gender'=>'男',
    'price'=>'100',
    'details'=>'123',
];
$result = UserModel::create($data,['username','email','gender'],false);
echo $result->id;

模型删除

delelt() 返回布尔值,不存在返回会报错?

UserModel::find(50)->delete();
UserModel::find([47,48,49])->delete();

destroy() 支持单个和批量删除,无论成功与否返回的都是 true,不存在返回会报错?

UserModel::destroy(1);
UserModel::destroy([2,5,6]);

模型修改数据

通过 find() 找到需要删除的对象

$data = [
    'username'=>'OY'
];
$user = UserModel::find(6)->save($data);

通过 where() 找到需要删除的对象

$data = [
    'username'=>'OY'
];
$user = UserModel::where('id',6)->save($data);

allowField() 允许更新数据。

UserModel::find(6)->allowField(['username'])->save($data);

saveAll() 批量性修改,必须有id,必须实例化。 save系列的貌似都需要实例化。

$user = new UserModel();
$list = [
    [
        'id'=>'6',
        'username'=>'OY5abcd'
    ],
    [
        'id'=>'7',
        'username'=>'OY5abcd'
    ]
];
$result = $user->saveAll($list);

update() 静态方法更新,必须要有id

$data = [
    'id'=>'6',
    'username'=>'OY5abc'
];
$result = UserModel::update($data);

第二个参数是id,第三个参数是允许修改字段。

$data = [
    'username'=>'OY5aa',
    'email'=>'OY5@qq.com'
];
$user = UserModel::update($data,['id'=>6],['username']);

模型数据查询

几乎和门面方式数据查询一模一样,不全部举例了。 find()

$user = UserModel::find(6);
echo $user->username;
echo $user->create_time;

findOrEmpty()

$user = UserModel::findOrEmpty(1);
if($user->isEmpty()){
    echo '空';
}else{
    echo $user;
}

select()

UserModel::select([6,9,12]);

模型端处理好,交给控制器直接调用 官方建议使用 getAttr()

class User extends Model
{
    public function getUsername()
    {
        $obj = $this->find(6);
        // return $obj->username;
        return $obj->getAttr('username');
    }

}

控制器端调用

$user = new UserModel();
echo $user->getUsername();

模型获取器

get**Attr() 在模型中输出处理后的数据。

public function getStatusAttr($value)
{
    $status = [
        0=>'零',
        1=>'一',
        2=>'二',
        3=>'三',
    ];
    return $status[$value];
}

控制器直接输出的是处理过的数据。

$user = UserModel::find(6);
echo $user->status;

getData() 获取指定原始数据

$user = UserModel::find(6);
echo $user->getData('status');

不填参数,就是获取全部原始数据数据

$user->getData();

模型修改器

用于新增、修改数据

public function setEmailAttr($value)
{
    return strtoupper($value);
}

模型查询范围

scope**() 在模型中封装好最最常用的SQL语句在控制器中直接使用,可叠加使用

public function scopeGender($query)
{
    $query->where('gender','男')
            ->limit(5);
}

scope() 在控制器中使用,参数是模型里命名函数scope之后部分的名字

UserModel::scope('gender')->select();

带参数查询

public function scopeEmail($query,$value)
{
    $query->where('email','like','%'.$value.'%');
}

在控制器中使用

UserModel::scope('email','lihei@qq.com')->select();

强制全局查询条件,可多个

protected $globalScope =['status'];
public function scopeStatus($query)
{
    $query->where('status',1);
}

在控制器里解除强制

UserModel::withoutGlobalScope()->select();

search**Attr() 搜索器,参数必须是数组格式。基本和 scope() 用法一致,当然也可以叠加使用。

$result = UserModel::withSearch(['email'],[
    'email' => 'oy'
])->select();

模型数据集

基本和门面方式一样,都是对已近取得的结果集进行处理。 www.kancloud.cn/manual/thin…

hidden() 模型独有

$data = UserModel::select();
dump($data->hidden(['username','email']));

visible() 模型独有

$data = UserModel::select();
dump($data->visible(['username','email']));

自动时间戳

database.php 默认开启,新增数据 create_time update_time 自动添加时间。

模型只读字段

修改时无法修改数据库字段,只对 save() 方法有效,update() 无效。 在模型中设置

protected $readonly =['email'];

在控制器中设置

$data = [
    'username'=>'OY',
    'email'=>'OY@qq.com'
];
UserModel::find(6)->readonly(['email'])->save($data);

模型数据类型转换

在模型中对数据类型进行转换 www.kancloud.cn/manual/thin…

protected $type = [
    'price'    =>  'float',
    'create_time'    =>  'datetime:Y-m-d',
];

var_dump() 可现实数据类型

模型废弃字段

在模型中设置后将不能使用这些字段

protected $disuse = [’status‘,’uid‘];

门面方式JSON

mysql5.7+的版本已经内部支持json格式 save() insert() 新增

$data = [
    'username'=>'OY',
    'email'=>'oy@qq.com',
    'gender'=>'男',
    'price'=>'100',
    'details'=>'123',
    'list'=>['username'=>'OY','email'=>'oy@qq.com'],
];
Db::name('user')->json(['list'])->save($data);

find() select() 查询

Db::name('user')->json(['list'])->find(6);

条件查询(必须mysql5.7)

Db::name('user')->json(['list'])->where('list->username','oy')->select();

update() save() 更新(必须mysql5.7)

$data['list->username'] = 'OY';
Db::name('user')->json(['list'])->where('id',58)->update($data);

模型JSON

在模型中设置好就可以了

protected $json = ['list'];

新增

$data = [
    'username'=>'OY',
    'email'=>'oy@qq.com',
    'gender'=>'男',
    'price'=>'100',
    'details'=>'123',
    'list'=>['username'=>'OY','email'=>'oy@qq.com'],
];
$user = new UserModel();
$result = $user->save($data);

查询

UserModel::find(58);
UserModel::select();

条件查询(必须mysql5.7)

UserModel::where('list->username','OY')->select();

更新(必须mysql5.7)

$data['list->username'] = 'OY';
UserModel::where('id',58)->update($data);

模型软删除

模型开启软删除,数据库有 delete_time 字段,必须默认为 NULL

use think\model\concern\SoftDelete;
user SoftDelete;

显示包含软删除数据

UserModel::withTrashed()->select();

只显示包含软删除数据

UserModel::OnlyTrashed()->select();

恢复软删除数据

$result = UserModel::onlyTrashed()->find(58);
$result->restore();

destroy() 硬删除,需要先还原再删除

$result = UserModel::onlyTrashed()->find(58);
$result->restore();
UserModel::destroy(58,true);

delete() 硬删除

UserModel::onlyTrashed()->find(58)->force()->delete();

门面方式查询事件

www.kancloud.cn/manual/thin…

public function initialize(){
    Db::event('before_select', function ($query) {
        echo 'before_select';
    });
}

模型查询事件

写在模型里 www.kancloud.cn/manual/thin… onBeforeInsert() 和 onAfterInsert 只有使用 save() 才有效,insert() 无效。

public static function onAfterRead($query)
{
    echo 'after_read';
}

public static function onBeforeInsert($query)
{
    echo 'before_insert';
}

public static function onAfterInsert($query)
{
    echo 'after_insert';
}

关联模型

表与表之间实现关联 www.kancloud.cn/manual/thin…

关联模型一对一

hasOne() 主 user 表和被关联 profile 数据表一对一

class User extends Model
{
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
}

控制器

$result = UserModel::find(1);
$result->profile;

belongsTo() 反向一对一

class Profile extends Model
{
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

修改关联表数据

$user = UserModel::find(2);
$data = [
    'love'=>'gaming',
];
$result = $user->profile->save($data);

新增关联表数据 profile 改成 profile() 即是新增

$result = $user->profile()->save($data);

关联模型一对多

hasMany() 主 user 表和被关联 profile 数据表一对多

class User extends Model
{
    public function profile()
    {
        return $this->hasMany(Profile::class);
    }
}

控制器 2种方法

$result = UserModel::find(1);
$result->profile;
$result->profile()->select();

saveAll() 添加多条关联数据

$user = UserModel::find(1);
$data = [
    ['love'=>'gaming1',],
    ['love'=>'gaming2',]
];
$user->profile()->saveAll($data);

删除主表的同时删除附表数据,支持软删除

$user = UserModel::with('profile')->find(4);
$user->together(['profile'])->delete();

with() 多数据获取

$result = UserModel::with(['profile'])->select([1,2,3]);
return json($result);

读取

$result = UserModel::with(['profile'])->select([1,2,3]);
foreach($result as $user){
    echo $user->profile;
}

一对多表数据

$result = UserModel::with(['profile','book'])->select([1,2,3]);
foreach($result as $user){
    echo $user->profile.$user->book;
}

withCount() 关联统计,获取字表关联的数量 获取方法是 表名_count

$result = UserModel::withCount(['book'])->select([1,2,3]);
foreach($result as $user){
    echo $user->book_count;
    echo '<br>';
}

关联模型多对多

一般用于用户多权限

表user:用户
表role:权限
表access:真正存储用户和权限管理的数据

Access表设置关联

use think\model\Pivot;
class Access extends Pivot
{
    
}

查询用户id=1的role数据

$user = UserModel::find(1);
eturn $user->roles;

为id=1的用户,添加role的3权限数据

$user = UserModel::find(1);
$user->roles()->save(Role::find(3));

删除id=1的用户,删除role的3权限数据

$user = UserModel::find(1);
$user->roles()->detach(Role::find(3));

路由

控制器

class Address
{
    public function details($id = null)
    {
        return $id;
    }
}

路由

Route::rule('ad/:id', 'Address/details');

原生访问地址

127.0.0.1:8000/address/details/id/1

路由访问地址

127.0.0.1:8000/ad/1

强制参数只能是数字

Route::rule('ad/:id', 'Address/details')->pattern(['id'=>'\d+']);

多参数

Route::rule('ad/:id/:uid', 'Address/details')->pattern(['id'=>'\d+','uid'=>'\d+']);

原生访问地址

127.0.0.1:8000/address/details/id/1/uid/2

路由访问地址

127.0.0.1:8000/ad/1/2

全局 id 和 uid 强制数字

Route::pattern(['id'=>'\d+','uid'=>'\d+']);

路由闭包

Route::get('think/:name', function ($name=null) {
    return 'hello,'.$name;
});

未完待续