Model 模型

模型定义

class User extends Model{
    // 完整数据表名称
    protected $table = 'user';

    // 主键
    protected $pk = 'id';
}

新增数据

$user = User::create([
    'name'  =>  'thinkphp',
    'email' =>  'thinkphp@qq.com'
]);

删除数据

User::where('id','>',10)->delete();

更新数据

UserModel::where('id', '=', 12)
    ->update([
        'name' => 'thinkphp'
    ]);

数据查询

// 单条 不存在返回null
UserModel::find($id);

UserModel::where('id', '=', $id)->find();

// 不存在返回空模型
UserModel::findOrEmpty($id);

// 多条
UserModel::select();

模型字段

模型的数据字段和数据表的字段对应,
默认会自动获取, 会导致增加一次查询,
在模型中明确定义字段信息避免多一次查询的开销。

class UserModel extends Model
{
    protected $name = 'tb_user';

    // 设置字段信息
    protected $schema = [
        'id'       => 'int',
        'username' => 'string',
    ];

执行 SQL

// 没有$schema查询两次
SHOW FULL COLUMNS FROM `tb_user`
SELECT * FROM `tb_user`

// 设置$schema查询一次
SELECT * FROM `tb_user`

缓存字段(多应用模式下不起作用)

php think optimize:schema

字段缓存默认是关闭状态,需要在 config/database.php 开启

// 开启字段缓存, 线上环境可开启
'fields_cache'    => true,

模型字段 2 种获取方式

// 模型外部
$user = UserModel::find(1);
$username = $user->username;
$username = $user['username'];

// 模型内部
$user = $this->find(1);
$username = $user->getAttr('username');

获取器和设置器

定义方式

public function  getFieldNameAttr($value, $data){
    return $value
}

public function  setFieldNameAttr($value){
    return $value
}

查询范围

// 定义全局的查询范围
protected $globalScope = ['status'];

public function scopeStatus($query, $value=1) {
    $query->where('status', '=', $value);
}

// 未定义全局
User::status()->select();

// 定义全局后
User::select();

搜索器

public function searchFieldNameAttr($query, $value, $data){

}

数据集 Collection

hidden   隐藏字段
visible  只显示字段
append   添加获取器字段
withAttr 对字段进行函数处理

自动时间戳

// 全局开启
'auto_timestamp' => true,
// 默认为整型(int)
'auto_timestamp' => 'datetime',

// 模型类单独开启
protected $autoWriteTimestamp = true;
// 定义时间戳字段名
protected $createTime = 'create_at';
protected $updateTime = 'update_at';

// 动态修改
$user->isAutoWriteTimestamp(false)->save();

只读字段

// 模型中定义
protected $readonly = ['name', 'email'];

// 动态设置 仅针对模型的更新方法
$user->readonly(['name','email'])->save();

类型转换

class User extends Model
{
    protected $type = [
        'status'    =>  'bool',
        'score'     =>  'float',
        'birthday'  =>  'datetime',
        'info'      =>  'array',
    ];
}

废弃字段

class User extends Model
{
    protected $disuse = [ 'status', 'type' ];
}

json 类型字段

class User extends Model
{
    // 设置json类型字段
    protected $json = ['tags'];
}

软删除

use think\model\concern\SoftDelete;

class User extends Model
{
    use SoftDelete;

    // 默认字段
    protected $deleteTime = 'delete_time';

    // 定义软删除字段的默认值
    protected $defaultSoftDelete = 0;
}
// 软删除
User::destroy(1);
// 真实删除
User::destroy(1, true);

$user = User::find(1);
// 软删除
$user->delete();
// 真实删除
$user->force()->delete();

// 不包含软删除的数据
User::find();
User::select();

// 包含软删除的数据
User::withTrashed()->find();
User::withTrashed()->select();

// 仅需要查询软删除的数据
User::onlyTrashed()->find();
User::onlyTrashed()->select();

// 恢复被软删除的数据
$user = User::onlyTrashed()->find(1);
$user->restore();

// 真实删除:先还原、再删除

模型和数据库事件

事件 描述 事件方法名
after_read 查询后 onAfterRead
before_insert 新增前 onBeforeInsert
after_insert 新增后 onAfterInsert
before_update 更新前 onBeforeUpdate
after_update 更新后 onAfterUpdate
before_write 写入前 onBeforeWrite
after_write 写入后 onAfterWrite
before_delete 删除前 onBeforeDelete
after_delete 删除后 onAfterDelete
before_restore 恢复前 onBeforeRestore
after_restore 恢复后 onAfterRestore

关联模型

类型 关联关系 相对的关联关系
一对一 hasOne belongsTo
一对多 hasMany belongsTo
多对多 belongsToMany belongsToMany
远程一对多 hasManyThrough 不支持
多态一对一 morphOne morphTo
多态一对多 morphMany morphTo

表结构

主表
user id name 

副表
profile id age sex user_id
class UserModel extends Model
{
    public function profile()
    {
        return $this->hasOne(ProfileModel::class);
    }
}

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

关联预载入

UserModel::with(['profile'])->select([1, 2, 3]);

关联统计

UserModel::withCount('cards')->select([1,2,3]);

多对多关联

表结构

CREATE TABLE `tb_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50)  NOT NULL,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
);

CREATE TABLE `tb_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(50) DEFAULT NULL,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
)

CREATE TABLE `tb_access` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `role_id` int(11) DEFAULT NULL,
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP,
  `update_time` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uk_user_id_role_id` (`user_id`,`role_id`)
)

模型类

/**
 * 用户表
 *
 * @mixin \think\Model
 */
class UserModel extends Model
{
    protected $table = 'tb_user';

    public function roles()
    {
        return $this->belongsToMany(RoleModel::class, AccessModel::class, 'role_id', 'user_id');
    }
}



/**
 * 角色表
 *
 * @mixin \think\Model
 */
class RoleModel extends Model
{
    //
    protected $table = 'tb_role';

    public function users()
    {
        return $this->belongsToMany(UserModel::class, AccessModel::class);
    }
}

use think\model\Pivot;

/**
 * 权限中间表
 *
 * @mixin \think\Model
 */
class AccessModel extends Pivot
{
    //
    protected $table = 'tb_access';
}

查询示例

<?php

namespace app\admin\controller;

use app\BaseController;
use app\model\UserModel;

class UserController extends BaseController
{

    // 查询列表数据
    public function getUserList()
    {
        return UserModel::with(['roles'])->select();
    }

    // 查询一条数据
    public function getUserById()
    {
        $user_id = input('id');
        return UserModel::with(['roles'])->find($user_id);
    }

    //添加关联
    public function addUserRole()
    {
        $user_id = input('user_id');
        $role_id = input('role_id');

        $user   = UserModel::find($user_id);
        $result = $user->roles()->attach([$role_id, $role_id]);

        return $result;
    }

    //移除关联
    public function removeUserRole()
    {
        $user_id = input('user_id');
        $role_id = input('role_id');

        $user   = UserModel::find($user_id);
        $result = $user->roles()->detach([$role_id, 2]);

        return $result;
    }

}

路由

路由配置 config/route.php
路由定义 route/app.php
// 定义路径参数
Route::get('test/:name', 'Index/test');
Route::get('test/<name>', 'Index/test');
// /index/test/Tom

// 定义别名
Route::get('hello', 'Index/hello')->name('hello');
// /index/index/test?name=Tom
public function test($name)
{
    return $name;
}

public function hello()
{
    // return url('hello');
    // /index/Index/hello.html

    return url('Index/test', ['name'=> 'Tom']);
    // /index/test/Tom.html

}

多级控制器访问

<?php
namespace app\index\controller\v1;

class BlogController
{
    //多级控制器 /index/v1.blog/index
    public function index()
    {
        return 'v1.Blog';
    }

    // 静态方法 /index/v1.blog/detail
    public static function detail()
    {
        return 'v1.static.detail';
    }
}

跨域请求

Route::get('new/:id', 'News/read')
    ->allowCrossDomain();

p40
https://www.bilibili.com/video/BV12E411y7u8?p=40&spm_id_from=pageDriver