数据集
模型的
all
和select
查询方法返回数据集对象think\model\Collection
,该对象继承自think\Collection
,因此具有数据库的数据集类的所有方法,而且还提供了额外的模型操作方法。基本用法和数组一样,需要注意的是,如果要判断数据集是否为空,不能直接使用
empty
判断,而必须使用数据集对象的isEmpty
方法判断可以使用模型的
hidden
/visible
/append
/withAttr
方法进行数据集的输出处理
$users = User::select();
if($users->isEmpty()){
echo '数据集为空';
}
V5.1.23+
版本开始,支持数据集的diff/intersect
操作。
// 模型查询返回数据集对象
$list1 = User::where('status', 1)->field('id,name')->select();
$list2 = User::where('name', 'like', 'think')->field('id,name')->select();
// 计算差集
dump($list1->diff($list2));
// 计算交集
dump($list1->intersect($list2));
自动时间戳
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 开启自动写入时间戳字段
protected $autoWriteTimestamp = true/false;
// 字段类型设置
protected $autoWriteTimestamp = 'timestamp/datetime/int';
// 定义时间戳字段名
protected $createTime = 'create_at';
protected $updateTime = 'update_at';
// 关闭自动写入update_time字段
protected $updateTime = false;
}
一、全局开启
// 开启自动写入时间戳字段
'auto_timestamp' => true,
二、单独开启
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
protected $autoWriteTimestamp = true;
}
三、全局开启,单独关闭
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
protected $autoWriteTimestamp = false;
}
一旦配置开启的话,会自动写入
create_time
和update_time
两个字段的值,默认为整型(int
),如果你的时间字段不是int
类型的话,可以直接使用:
// 开启自动写入时间戳字段
'auto_timestamp' => 'datetime',
或者
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
protected $autoWriteTimestamp = 'datetime';
}
默认的创建时间字段为
create_time
,更新时间字段为update_time
,支持的字段类型包括timestamp/datetime/int
。写入数据的时候,系统会自动写入
create_time
和update_time
字段,而不需要定义修改器
时间字段的自动写入仅针对模型的写入方法,如果使用数据库的更新或者写入方法则无效。
时间字段输出的时候会自动进行格式转换,如果不希望自动格式化输出,可以把数据库配置文件的
datetime_format
参数值改为false
如果你的数据表字段不是默认值的话,可以按照下面的方式定义:
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 定义时间戳字段名
protected $createTime = 'create_at';
protected $updateTime = 'update_at';
}
如果你只需要使用create_time
字段而不需要自动写入update_time
,则可以单独关闭某个字段,例如:
class User extends Model
{
// 关闭自动写入update_time字段
protected $updateTime = false;
}
支持动态关闭时间戳写入功能,例如你希望更新阅读数的时候不修改更新时间,可以使用isAutoWriteTimestamp
方法:
$user = User::get(1);
$user->read +=1;
$user->isAutoWriteTimestamp(false)->save();
只读字段
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
protected $readonly = ['name', 'email'];
}
5.1版本支持动态设置只读字段,例如:
$user = User::get(5);
// 更改某些字段的值
$user->name = 'TOPThink';
$user->email = 'Topthink@gmail.com';
$user->address = '上海静安区';
// 保存更改后的用户数据
$user->readonly(['name','email'])->save();
只读字段仅针对模型的更新方法,如果使用数据库的更新方法则无效,例如下面的方式无效。
类型转换
支持给字段设置类型自动转换,会在写入和读取的时候自动进行类型转换处理,例如:
<?php
class User extends Model
{
protected $type = [
'status' => 'integer',
'score' => 'float',
'birthday' => 'datetime',
'info' => 'array',
];
}
数据库查询默认取出来的数据都是字符串类型,如果需要转换为其他的类型,需要设置
自动完成
系统支持
auto
、insert
和update
三个属性,可以分别在写入、新增和更新的时候进行字段的自动完成机制,auto
属性自动完成包含新增和更新操作
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
protected $auto = ['name', 'ip'];
protected $insert = ['status' => 1];
protected $update = [];
protected function setNameAttr($value)
{
return strtolower($value);
}
protected function setIpAttr()
{
return request()->ip();
}
}
数据自动完成如果需要写入固定的值,可以直接指定(例如上面的status字段固定写入了1),类似于数据表字段的默认值功能。
数据自动完成仍然还是调用的修改器,要注意避免数据被两次处理的可能,自动完成定义的属性不要和表单提交的冲突。
查询范围
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
public function scopeThinkphp($query)
{
$query->where('name','thinkphp')->field('id,name');
}
public function scopeAge($query)
{
$query->where('age','>',20)->limit(10);
}
}
使用:
// 查找name为thinkphp的用户
User::scope('thinkphp')->find();
// 查找年龄大于20的10个用户
User::scope('age')->select();
// 查找name为thinkphp的用户并且年龄大于20的10个用户
User::scope('thinkphp,age')->select();
查询范围的方法可以定义额外的参数,例如User模型类定义如下:
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
public function scopeEmail($query, $email)
{
$query->where('email', 'like', '%' . $email . '%');
}
public function scopeScore($query, $score)
{
$query->where('score', '>', $score);
}
}
在查询的时候可以如下使用:
// 查询email包含thinkphp和分数大于80的用户
User::email('thinkphp')->score(80)->select();
使用查询范围后,只能使用
find
或者select
查询。
全局查询
如果你的所有查询都需要一个基础的查询范围,那么可以在模型类里面定义一个静态的base
方法,例如:
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 定义全局的查询范围
protected function base($query)
{
$query->where('status',1);
}
}
然后,执行下面的代码:
$user = User::get(1);
//即
status = 1 AND id = 1
如果需要动态关闭/开启全局查询访问,可以使用:
// 关闭全局查询范围
User::useGlobalScope(false)->select();
// 开启全局查询范围
User::useGlobalScope(true)->select();
V5.1.26+
版本开始,支持在模型里面设置globalScope
属性,定义全局的查询范围
<?php
namespace app\index\model;
use think\Model;
class User extends Model
{
// 定义全局的查询范围
protected $globalScope = ['status'];
public function scopeStatus($query)
{
$query->where('status',1);
}
}
或者使用useGlobalScope
方法动态指定当前查询的全局查询范围。
User::useGlobalScope(['status'])->select();
模型输出
一、数组转换
可以使用toArray
方法将当前的模型实例输出为数组,例如:
$user = User::find(1);
dump($user->toArray());
对于数据集结果一样可以直接使用(包括
append
、visible
和hidden
方法)注意,必须要首先调用一次Db类的方法后才能调用
hidden
/visible
/append
方法。
$user = User::find(1);
dump($user->visible(['id','name','email'])->toArray());
$user = User::find(1);
dump($user->hidden(['create_time','update_time'])->toArray());
$user = User::find(1);
dump($user->append(['status_text'])->toArray());
二、追加关联属性
支持追加一对一关联模型的属性到当前模型,例如:
$user = User::find(1);
dump($user->append(['profile' => ['email', 'nickname']])->toArray());
profile
是关联定义方法名,email
和nickname
是Profile
模型的属性。
三、JSON序列化
可以调用模型的toJson
方法进行JSON
序列化,toJson
方法的使用和toArray
一样。
$user = User::get(1);
echo $user->toJson();