模型&&验证器
定义一个User模型类:
namespace app\index\model;
use think\Model;
class User extends Model
{
// 设置当前模型对应的完整数据表名称
protected $table = 'think_user';
}
模型调用
模型类可以使用静态调用或者实例化调用两种方式,例如:
// 静态调用
$user = User::get(1);
$user->name = 'thinkphp';
$user->save();
// 实例化模型
$user = new User;
$user->name= 'thinkphp';
$user->save();
// 使用 Loader 类实例化(单例)
$user = Loader::model('User');
// 或者使用助手函数`model`
$user = model('User');
$user->name= 'thinkphp';
$user->save();
模型初始化
模型同样支持初始化,与控制器的初始化不同的是,模型的初始化是重写Model
的initialize
,具体如下
namespace app\index\model;
use think\Model;
class Index extends Model
{
//自定义初始化
protected function initialize()
{
//需要调用`Model`的`initialize`方法
parent::initialize();
//TODO:自定义的初始化
}
}
同样也可以使用静态init
方法,需要注意的是init
只在第一次实例化的时候执行,并且方法内需要注意静态调用的规范,具体如下:
namespace app\index\model;
use think\Model;
class Index extends Model
{
//自定义初始化
protected static function init()
{
//TODO:自定义的初始化
}
}
新增
添加一条数据
$user = new User;
$user->name = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();
也可以使用data方法批量赋值:
$user = new User;
$user->data([
'name' => 'thinkphp',
'email' => 'thinkphp@qq.com'
]);
$user->save();
或者直接在实例化的时候传入数据
$user = new User([
'name' => 'thinkphp',
'email' => 'thinkphp@qq.com'
]);
$user->save();
如果需要过滤非数据表字段的数据,可以使用:
$user = new User($_POST);
// 过滤post数组中的非数据表字段数据
$user->allowField(true)->save();
如果你通过外部提交赋值给模型,并且希望指定某些字段写入,可以使用:
$user = new User($_POST);
// post数组中只有name和email字段会写入
$user->allowField(['name','email'])->save();
获取自增ID
如果要获取新增数据的自增ID,可以使用下面的方式:
$user = new User;
$user->name = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();
// 获取自增ID
echo $user->id;
注意这里其实是获取模型的主键,如果你的主键不是id,而是user_id的话,其实获取自增ID就变成这样:
$user = new User;
$user->name = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();
// 获取自增ID
echo $user->user_id;
注意不要在同一个实例里面多次新增数据,如果确实需要多次新增,那么可以用下面的方式:
$user = new User;
$user->name = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();
$user->name = 'onethink';
$user->email = 'onethink@qq.com';
// 第二次开始必须使用下面的方式新增
$user->isUpdate(false)->save();
添加多条数据
支持批量新增,可以使用:
$user = new User;
$list = [
['name'=>'thinkphp','email'=>'thinkphp@qq.com'],
['name'=>'onethink','email'=>'onethink@qq.com']
];
$user->saveAll($list);
更新
在取出数据后,更改字段内容后更新数据。
$user = User::get(1);
$user->name = 'thinkphp';
$user->email = 'thinkphp@qq.com';
$user->save();
也可以直接带更新条件来更新数据
$user = new User;
// save方法第二个参数为更新条件
$user->save([
'name' => 'thinkphp',
'email' => 'thinkphp@qq.com'
],['id' => 1]);
上面两种方式更新数据,如果需要过滤非数据表字段的数据,可以使用:
$user = new User();
// 过滤post数组中的非数据表字段数据
$user->allowField(true)->save($_POST,['id' => 1]);
如果你通过外部提交赋值给模型,并且希望指定某些字段写入,可以使用:
$user = new User();
// post数组中只有name和email字段会写入
$user->allowField(['name','email'])->save($_POST, ['id' => 1]);
可以使用saveAll方法批量更新数据,例如:
$user = new User;
$list = [
['id'=>1, 'name'=>'thinkphp', 'email'=>'thinkphp@qq.com'],
['id'=>2, 'name'=>'onethink', 'email'=>'onethink@qq.com']
];
$user->saveAll($list);
删除
删除模型数据,可以在实例化后调用delete方法。
$user = User::get(1);
$user->delete();
根据主键删除
User::destroy(1);
// 支持批量删除多个数据
User::destroy('1,2,3');
// 或者
User::destroy([1,2,3]);
条件删除
// 删除状态为0的数据
User::destroy(['status' => 0]);
还支持使用闭包删除,例如:
User::destroy(function($query){
$query->where('id','>',10);
});
或者通过数据库类的查询条件删除
User::where('id','>',10)->delete();
查询
获取单个数据的方法包括:
取出主键为1的数据
$user = User::get(1);
echo $user->name;
// 使用数组查询
$user = User::get(['name' => 'thinkphp']);
// 使用闭包查询
$user = User::get(function($query){
$query->where('name', 'thinkphp');
});
echo $user->name;
获取多个数据
取出多个数据:
// 根据主键获取多个数据
$list = User::all('1,2,3');
// 或者使用数组
$list = User::all([1,2,3]);
foreach($list as $key=>$user){
echo $user->name;
}
// 使用数组查询
$list = User::all(['status'=>1]);
// 使用闭包查询
$list = User::all(function($query){
$query->where('status', 1)->limit(3)->order('id', 'asc');
});
foreach($list as $key=>$user){
echo $user->name;
}
获取某个字段或者某个列的值
// 获取某个用户的积分
User::where('id',10)->value('score');
// 获取某个列的所有值
User::where('status',1)->column('name');
// 以id为索引
User::where('status',1)->column('name','id');
User::where('status',1)->column('id,name'); // 同tp3的getField
简单方法查询
User::where('id','>',10)->select();
User::where('name','thinkphp')->find();
聚合
在模型中也可以调用数据库的聚合方法进行查询,例如:
方法 | 说明 |
---|---|
count | 统计数量,参数是要统计的字段名(可选) |
max | 获取最大值,参数是要统计的字段名(必须) |
min | 获取最小值,参数是要统计的字段名(必须) |
avg | 获取平均值,参数是要统计的字段名(必须) |
sum | 获取总分,参数是要统计的字段名(必须) |
静态调用:
User::count();
User::where('status','>',0)->count();
User::where('status',1)->avg('score');
User::max('score');
动态调用:
$user = new User;
$user->count();
$user->where('status','>',0)->count();
$user->where('status',1)->avg('score');
$user->max('score');
获取器
获取器的作用是在获取数据的字段值后自动进行处理,例如,我们需要对状态值进行转换,可以使用:
class User extends Model
{
public function getStatusAttr($value)
{
$status = [-1=>'删除',0=>'禁用',1=>'正常',2=>'待审核'];
return $status[$value];
}
}
数据表的字段会自动转换为驼峰法,一般status字段的值采用数值类型,我们可以通过获取器定义,自动转换为字符串描述。
$user = User::get(1);
echo $user->status; // 例如输出“正常”
获取器还可以定义数据表中不存在的字段,例如:
class User extends Model
{
public function getStatusTextAttr($value,$data)
{
$status = [-1=>'删除',0=>'禁用',1=>'正常',2=>'待审核'];
return $status[$data['status']];
}
}
我们就可以直接使用status_text字段的值了,例如:
$user = User::get(1);
echo $user->status_text; // 例如输出“正常”
获取器只有当获取某个数据属性的时候自动触发,如果你要获取包含获取器处理的全部数据属性的话,可以使用下面的方法:
$user = User::get(1);
// 获取全部获取器数据
dump($user->toArray());
修改器
修改器的作用是可以在数据赋值的时候自动进行转换处理,例如:
class User extends Model
{
public function setNameAttr($value)
{
return strtolower($value);
}
}
如下代码实际保存到数据库中的时候会转为小写
$user = new User();
$user->name = 'THINKPHP';
$user->save();
echo $user->name; // thinkphp
也可以进行序列化字段的组装:
class User extends Model
{
public function setNameAttr($value,$data)
{
return serialize($data);
}
}
批量修改
除了赋值的方式可以触发修改器外,还可以用下面的方法批量触发修改器
$user = new User();
$data['name'] = 'THINKPHP';
$data['email'] = 'thinkphp@qq.com';
$user->data($data, true);
$user->save();
echo $user->name; // thinkphp
或者直接使用save方法触发,例如:
$user = new User();
$data['name'] = 'THINKPHP';
$data['email'] = 'thinkphp@qq.com';
$user->save($data);
echo $user->name; // thinkphp
时间戳
系统支持自动写入创建和更新的时间戳字段,有两种方式配置支持。
第一种方式,是在数据库配置文件中添加全局设置:
// 开启自动写入时间戳字段
'auto_timestamp' => true,
第二种是直接在单独的模型类里面设置:
protected $autoWriteTimestamp = true;
如果这两个地方设置为true,默认识别为整型int类型,如果你的时间字段不是int类型的话,
例如使用datetime类型的话,可以这样设置:
// 开启自动写入时间戳字段
'auto_timestamp' => 'datetime',
或者
protected $autoWriteTimestamp = 'datetime';
如果是关闭全局的自动时间写入,则可以使用:
// 关闭全局自动写入时间字段
'auto_timestamp' => false,
验证器
ThinkPHP5.0验证使用独立的\think\Validate
类或者验证器进行验证。
独立验证
任何时候,都可以使用Validate
类进行独立的验证操作,例如:
$validate = new Validate([
'name' => 'require|max:25',
'email' => 'email'
]);
$data = [
'name' => 'thinkphp',
'email' => 'thinkphp@qq.com'
];
if (!$validate->check($data)) {
dump($validate->getError());
}
这是5.0推荐的验证方式,为具体的验证场景或者数据表定义好验证器类,直接调用验证类的check
方法即可完成验证,下面是一个例子:
我们定义一个\app\index\validate\User
验证器类用于User
的验证。
namespace app\index\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'email' => 'email',
];
}
在需要进行User
验证的地方,添加如下代码即可:
$data = [
'name'=>'thinkphp',
'email'=>'thinkphp@qq.com'
];
$validate = Loader::validate('User');
if(!$validate->check($data)){
dump($validate->getError());
}
使用助手函数实例化验证器
$validate = validate('User');
验证规则
$rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email',
];
$msg = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误',
];
$data = [
'name' => 'thinkphp',
'age' => 10,
'email' => 'thinkphp@qq.com',
];
$validate = new Validate($rule, $msg);
$result = $validate->check($data);
使用默认的错误提示信息
$rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email',
];
$data = [
'name' => 'thinkphp',
'age' => 121,
'email' => 'thinkphp@qq.com',
];
$validate = new Validate($rule);
$result = $validate->check($data);
if(!$result){
echo $validate->getError();
}
验证场景
$rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email',
];
$msg = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误',
];
$data = [
'name' => 'thinkphp',
'age' => 10,
'email' => 'thinkphp@qq.com',
];
$validate = new Validate($rule);
$validate->scene('edit', ['name', 'age']);
$result = $validate->scene('edit')->check($data);
表示验证edit场景(该场景定义只需要验证name和age字段)。
如果使用了验证器,可以直接在类里面定义场景,例如:
namespace app\index\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'age' => 'number|between:1,120',
'email' => 'email',
];
protected $message = [
'name.require' => '名称必须',
'name.max' => '名称最多不能超过25个字符',
'age.number' => '年龄必须是数字',
'age.between' => '年龄只能在1-120之间',
'email' => '邮箱格式错误',
];
protected $scene = [
'edit' => ['name','age'],
];
}
然后再需要验证的地方直接使用 scene 方法验证
$data = [
'name' => 'thinkphp',
'age' => 10,
'email' => 'thinkphp@qq.com',
];
$validate = new \app\index\validate\User($rule);
$result = $validate->scene('edit')->check($data);
控制器验证
如果你需要在控制器中进行验证,并且继承了\think\Controller
的话,可以调用控制器类提供的validate
方法进行验证,如下:
$result = $this->validate(
[
'name' => 'thinkphp',
'email' => 'thinkphp@qq.com',
],
[
'name' => 'require|max:25',
'email' => 'email',
]);
if(true !== $result){
// 验证失败 输出错误信息
dump($result);
}
如果定义了验证器类的话,例如:
namespace app\index\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'email' => 'email',
];
protected $message = [
'name.require' => '用户名必须',
'email' => '邮箱格式错误',
];
protected $scene = [
'add' => ['name','email'],
'edit' => ['email'],
];
}
控制器中的验证代码可以简化为:
$result = $this->validate($data,'User');
if(true !== $result){
// 验证失败 输出错误信息
dump($result);
}
如果要使用场景,可以使用:
$result = $this->validate($data,'User.edit');
if(true !== $result){
// 验证失败 输出错误信息
dump($result);
}
模型验证
如果使用下面的验证器类的话:
namespace app\index\validate;
use think\Validate;
class User extends Validate
{
protected $rule = [
'name' => 'require|max:25',
'email' => 'email',
];
protected $message = [
'name.require' => '用户名必须',
'email' => '邮箱格式错误',
];
protected $scene = [
'add' => ['name','email'],
'edit' => ['email'],
];
}
模型验证代码可以简化为:
$User = new User;
// 调用当前模型对应的User验证器类进行数据验证
$result = $User->validate(true)->save($data);
if(false === $result){
// 验证失败 输出错误信息
dump($User->getError());
}
如果需要调用的验证器类和当前的模型名称不一致,则可以使用:
$User = new User;
// 调用Member验证器类进行数据验证
$result = $User->validate('Member')->save($data);
if(false === $result){
// 验证失败 输出错误信息
dump($User->getError());
}
同样也可以支持场景验证:
$User = new User;
// 调用Member验证器类进行数据验证
$result = $User->validate('User.edit')->save($data);
if(false === $result){
// 验证失败 输出错误信息
dump($User->getError());
}
内置规则
验证某个字段必须,例如:
'name'=>'require'
验证某个字段的值是否为数字(采用filter_var验证),例如:
'num'=>'number'
验证某个字段的值是否为浮点数字(采用filter_var验证),例如:
'num'=>'float'
验证某个字段的值是否为布尔值(采用filter_var验证),例如:
'num'=>'boolean'
验证某个字段的值是否为email地址(采用filter_var验证),例如:
'email'=>'email'
验证某个字段的值是否为数组,例如:
'info'=>'array'
验证某个字段是否为为 yes, on, 或是 1。这在确认"服务条款"是否同意时很有用,例如:
'accept'=>'accepted'
验证值是否为有效的日期,例如:
'date'=>'date'
验证某个字段的值是否为字母,例如:
'name'=>'alpha'
验证某个字段的值是否为字母和数字,例如:
'name'=>'alphaNum'
验证某个字段的值是否为字母和数字,下划线_及破折号-,例如:
'name'=>'alphaDash'
验证某个字段的值只能是汉字,例如:
'name'=>'chs'
验证某个字段的值只能是汉字、字母,例如:
'name'=>'chsAlpha'
验证某个字段的值只能是汉字、字母和数字,例如:
'name'=>'chsAlphaNum'
验证某个字段的值只能是汉字、字母、数字和下划线_及破折号-,例如:
'name'=>'chsDash'
验证某个字段的值是否为有效的域名或者IP,例如:
'host'=>'activeUrl'
验证某个字段的值是否为有效的URL地址(采用filter_var验证),例如:
'url'=>'url'
验证某个字段的值是否为有效的IP地址(采用filter_var验证),例如:
'ip'=>'ip'
验证某个字段的值是否为指定格式的日期,例如:
'create_time'=>'dateFormat:y-m-d'
验证某个字段的值是否在某个范围,例如:
'num'=>'in:1,2,3'
验证某个字段的值不在某个范围,例如:
'num'=>'notIn:1,2,3'
验证某个字段的值是否在某个区间,例如:
'num'=>'between:1,10'
验证某个字段的值不在某个范围,例如:
'num'=>'notBetween:1,10'
验证某个字段的值的长度是否在某个范围,例如:
'name'=>'length:4,25'
验证某个字段的值的最大长度,例如:
'name'=>'max:25'
验证某个字段的值的最小长度,例如:
'name'=>'min:5'
验证某个字段的值是否在某个日期之后,例如:
'begin_time' => 'after:2016-3-18',
验证某个字段的值是否在某个日期之前,例如:
'end_time' => 'before:2016-10-01',