简介

  1. tp5的model只做业务层操作,不做具体的链接数据库sql操作。
  2. think\db\Connection.php做链接数据库操作
  3. think\db\Builder.php做创建sql操作
  4. think\db\Query.php做数据CURD操作

功能清单



  1. 数据自动完成
  2. 自动写入时间戳
  3. 时间字段自动格式化输出字段
  4. 字段验证器
  5. 自动关联写入
  6. 只读字段
  7. 隐藏字段
  8. 事件回调
  9. 软删除
  10. 类型转换



功能详情

1. 数据自动完成



									
						

//设置自动完成的字段,支持键值对数组和索引数组

//新增和更新时都会使用

//如:['name'=>'zhangsan','sex'=>'男']// ['name','sex']

protected$auto= [];

//只在新增数据的时候使用

protected $insert = [];

//更新 自动完成列表 //只在更新数据的时候使用

protected$update= [];

//用来标记当前操作被修改的字段 //如 ['name','sex']

protected$change= [];

//依赖方法,model类会自动调用解析auto数组 //我们只需配置auto数组即可

protectedfunctionautoCompleteData($auto= []){}

  1. 在model中设置完auto字段后在更新或新增的时候首先会判断auto中设置的字段是否存在于被更新的字段($this->change)中
  2. 如果存在则不用auto里设置的字段和值
  3. 如果不存在则将auto里设置的字段和值添加到this>datathis->change中。
  4. 如果auto是索引数组,也就是只设置了字段名,没有设置子字段值,这是就会根据字段名去$this->data中查询该字段值,并添加的到要更新的属性数组中去。
  5. 新增数据的方法是create, 修改数据的方法是update,批量新增和修改的方法是saveAll,这几个方法的最终实现都是调用的save方法
  6. saveAll方法批量新增和修改,并不是组合sql语句,而是开启事务,然后调用save方法,一条一条添加和修改,最后提交事务。
  7. 在更新操作中,model会自动检查data的所有字段的值是否被更改,只会跟新被更改过得字段的值。没被更改的则被忽略。
  8. insert、update的功能和auto的功能类似,只不过auto是不管是新增数据和是更新数据都会使用,而insert值针对新增,update只针对更新。如果设置了相同的属性,insert和update的则会覆盖auto中的字段。

2. 自动写入时间戳



											
								

//是否需要自动写入时间戳

//可以是字符串类型和boolean类型

//字符串类型代表要写入的时间格式

//如: 'Y-m-d H:i:s'

//boolean类型就是true和false,代表是否开启

//默认时间格式为int类型

protected $autoWriteTimestamp;

//默认自动写入的字段有

//创建时间和更新时间,他们对应的字段名分别是

//create_time,和update_time

//也可以在model里自己设置。

protected $createTime = 'create_time';

protected $updateTime = 'update_time';

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15



配置方式
  1. 该配置TP5默认为false,需要手动开启
  2. 在数据库配置(database.php)中添加全局配置。



 'auto_timestamp' => true //或者设置时间格式 // 'auto_timestamp' => 'datatime' 
										
  • 1
  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4



  1. 在单独的模型类里设置



												
									

protected $autoWriteTimestamp = true;

//或者设置时间格式

// protected $autoWriteTimestamp = 'datatime';

  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4



  1. 知识的字段类型 timestamp/datetime/int
  2. 如果自己的数据字段不是默认值得话,可以在自己的model里修改。



													
										

//如:

protected $createTime = 'my_create_time_filed';

protected$updateTime='my_careate_time_field';

  • 2
  • 3
  • 4
  • 1
  • 2
  • 3
  • 4



  1. 如果只需要createTime而不需要updateTIme,则可以在model中关闭updateTIme



 //如 protected $updateTime = false; 
									
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3



  1. 在model中开启和关闭只针对单独的model起作用,想要全局起作用还是要在配置文件里配置。

3. 时间字段自动格式化输出



 //输出格式 protected $dateFormat; 
											
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3



配置方式
  1. 该配置TP5模式输出格式为 ‘Y-m-d H:i:s’
  2. 可以自己在数据库配置文件(database.php)中配置。如



 'datetime_format' => 'Y/m/d H:i', 
													
  • 1
  • 2
  • 1
  • 2



  1. 也可以在model中设置



 protected $dateFormat = 'Y/m/d H:i'; 
												
  • 1
  • 2
  • 1
  • 2



4. 字段验证器



 //字段验证规则 protected $validate = []; //是否采用批量验证 protected $batchValidate = false; /**
* 设置字段验证
*
@accesspublic
*
@paramarray|string|bool $rule 验证规则 true表示自动读取验证器类
*
@paramarray $msg 提示信息
*
@parambool $batch 批量验证
*
@return$this
*/
public functionvalidate($rule = ture,"hljs-variable">$msg=[],$bath=false){} /**
* 自动验证数据
*
@accessprotected
*
@paramarray $data 验证数据
*
@parammixed $rule 验证规则
*
@parambool $batch 批量验证
*
@returnbool
*/
public functionvalidateData($data,"hljs-variable">$rule=null,$batch=null){}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26



使用方式

  1. 在model中配置字段验证规则,在整个model中新增和更新操作都通用。



																
													

// 优点:只需要设置一次,即可通用

// 缺点:无法针对化设置

//比如:新增用户和编辑用户功能,

//新增是密码为必填项,编辑时密码就是选填项了

//所以就不能再model里设置密码的验证规则了, 这个时候就只能在新增的action里为密码做验证了。

protected $validate = [

'rule' => [

'name' => 'require',

//多个规则可以是用字符串用|分隔

//也可以使用数组['require','number','min'=>10,'max'=>80]

//使用字符串配置要被使用explode('|',$rule)转化成数组,所以使用数组配置效率更高

'age'=>'require|number|min:10|max:80',

'height'=>'between:100,200'],

'msg'=> [

'name'=>'name不能为空',

'age.require'=>'age不能没空',

'age.number'=>'age必须是一个数字',

'age.min'=>'age最小为10',

'age.max'=>'age最大为80',

'height'=>'height只能在100到200之间'

]

];

1

  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24



  1. 在具体操作时调用think\Validate类来实现



															
												

//在类的头部,因为Validate文件。

use think\Validate;

$validate = new Validate(

     ['name'=>'require','age'=>'require|number|min:10|max:80'],

     ['name'=>'name不能为空',

         'age.require'=>'age不能没空',

         'age.number'=>'age必须是一个数字',

        'age.min'=>'age最小为10',

        'age.max'=>'age最大为80']

     );

//使用check检查数据

if($validate->check(class="hljs-variable">$data)){

    echo '数据格式符合要求';

}else{//比如:name不能为空echo$validate->getError();

    }

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25



对比
  1. 使用第一种方法在model里设置验证规则,虽然说结构看着比较合理,但是这种方法灵活性比较低,
  2. 因为他是在save的时候去判断的,如果save失败,你不清楚是数据验证失败,还是说插入到数据失败。
  3. 所以对于做提示验证很麻烦(因为数据验证的提示我们是直接返回给用户的,而数据库操作的提示一般我们是不返回给用户的,
  4. 所以得到结果后还要做判断,先对比较麻烦)。
  5. 使用第二种方法在action里定义一个_validate的函数,专门用来做数据校验,这中方法比较灵活,
  6. 而且他是在在保存数据之前做的校验,所以返回结果分的比较清楚,对用户的提示也比较清晰,代码可读性也比较好。

5. 自动关联写入



 // 关联对象 protected $relation; // 关联自动写入(关联的属性名) protectd $relationWrite = []; 
													
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6



暂时没有使用,后续再继续不补充。

6. 只读字段



 //用来保护那些不许要被更新的字段。 //比如,创建时间 //设置后再更新数据时,会字段过滤掉create_time字段 //避免更新到数据库。 protected $readonly = ['create_time']; 
															
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6



7. 隐藏字段



																	
														

//设置要隐藏的字段,

//该设置只在toArray(),和subToArray()方法中起作用

protected$hidden= [];

//相关方法

publicfunctionhidden($hidden=[],"hljs-variable">$override=false){

}

  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9



当使用toArray和subToArray获得数组数据时,使用hidden字段和hidden函数可以隐藏数组中的元素。如:



																
													

//user表的属性字段(模拟操作) user_field = ['name','sex','age','height'];在User模型中设置$hidden字段

protected $hidden = ['age','height'];

dump($User->toArray());

//只有name和sex字段。

//也可以调用hidden方法隐藏字段

//会有 name,age,height 三个字段

dump($User->hidde(['sex'])->toArray());

//只有name字段了

//第二个参数标识是否合并

$this->hidden

dump($user->hidden(['sex'],true)->toArray());

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16



8. 事件回调

支持的回调事件
  1. before_insert 新增前
  2. after_insert 新增后
  3. before_update 更新前
  4. after_update 更新后
  5. before_write 写入前(新增和更新都会调用)
  6. after_write 写入后(新增和更新都会调用)
  7. before_delete 删除前
  8. after_delete 删除后

注册的回调方法支持传入一个参数,当前示例模型对象,并且before_write,before_insert,before_update,before_delete返回false会结束执行。

使用方法
  1. 控制器里使用



																

//支持给一个位置注册多个事件

User::event('before_insert',function($user){

    if($user->status != 1){

        return false;

    }

}); //这个也会生效,回到函数为beforeInsert User::event('before_insert','beforeInsert');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12



  1. 模型里使用



															

//使用init方法统一注册模型事件

classUserextendsModel{

    protected static functioninit(){

        User::event('before_insert',function($user){

            if($user->status != 1){

                return false;

            }

       }

    //注册第二个事件

    User::event('before_insert','beforeInsert');

}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17



原理

model类里有一个protected static $event = [];属性,注册的时间都存放在这个属性中。比如:



													

$event = [  //模型名称

    'user'=> [

        //事件名称

        'before_insert' => [

              'callback_funciton',

              'beforeInsert'

        ],

        'after_insert'=> [

            'callback_function',

            'afterInsert'

        ],

        'before_delete'=> [

            'beforeDelete'

        ]

] ]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17



注册事件时,把所有的事件都保存在$event中了,然后在insert,update,delete等相应的位置调用即可。

9. 软删除

简介

在实际项目中,对数据频繁的使用删除操作可能会导致性能问题,软删除的作用就是给数据加上删除标记,而不是真正的删除,同时也便于需要的时候恢复数据。

设置方式

使用软删除功能需要引用SoftDelete trait;如:



																			

namespace app\index\model;

use think\Model;

use think\model\SoftDelete;

classUserextendsModel{

    // 使用SoftDelete

    // trait 的使用方式

    // 使用trait跟类的继承相似

    use SoftDelete;

    //软删除标记的字段名

    protected $deleteTime = 'delete_time';

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17



dateteTIme属性用于标记数据表里的软删除字段,TP5里的软删除使用的是int类型,默认值为null(这个很重要,因为查询的时候是用delete_time is not null 来查询的),用于记录删除时间。

可以用类型转换指定软删除的字段类型,建议数据表里的所有时间字段使用同一种数据类型。

使用方式

在model中设置好后,就可以直接使用了



																

//软删除 User::destory(1);

//真删除 User::destory(1,true);

//软删除 $user = User::get(1); $user->delete();

//真删除 $user->delete(true);

  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14



默认情况下,查询出来的数据是不包括软删除的数据的,如果想要查询包括软删除的数据,可以使用下面的方式。



 User::withTrashed()->find();
 User::withTrashed()->select(); 
																	
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3



如果仅需要查询软删除的数据,可以这样:



 User::onlyTranshed()->find();
 User::onlyTranshed()->select(); 
																
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3



10. 类型转换

TP5支持给数据表中的字段设置类型,并会在读取和写入的时候自动转换。如:



																		

classUserextendsModel{

    protected $type = [

        'status' => 'integer',

        'score' => 'float',

        'login_timme' => 'datetime',

        'info' => 'array'

    ];

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10



使用示例



																	

//

$user = new User;

$user->status ='1';

$user->score ='90.50';

$user->birthday ='2015/5/1';

$user->info = ['a'=>1,'b'=>2];

$user->save();

var_dump($user->status);      // int 1

var_dump($user->score);     // float 90.5;

var_dump($user->birthday);     // string '2015-05-01 00:00:00'

var_dump($user->info);         // array (size=2) 'a' => int 1 'b' => int 2

  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12



注意: 如果制定为时间戳类型(timestamp)的话,该字段会在写入的时候自动调用strtotime函数生成对应的时间戳,

输出是自动使用dateFormat格式化时间戳,默认格式为Y:m:d H:i:s,如果想要改变输出格式,可以如下:



																		

classUserextendsModel{

protected $dataFormat = 'Y/m/d';

protected $type = [

        'status'=>'integer',

       'score'=>'float',

        'birthday'=>'timestemp'        //时间戳格式

];

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10



或者如下:



																	

classUserextendsModel{

    protected$type= [

         'status'=>'integer',

        'socre'=>'float',

         'birthday'=>'timestemp:Y/m/d'

        //写入时间戳,读取按照Y/m/d的格式来格式化输出。

  ];

}