TP5 Model 功能总结

简介

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

功能清单

数据自动完成
自动写入时间戳
时间字段自动格式化输出字段
字段验证器
自动关联写入
只读字段
隐藏字段
事件回调
软删除
类型转换

功能详情

  1. 数据自动完成
//设置自动完成的字段,支持键值对数组和索引数组
//新增和更新时都会使用
//如:['name'=>'zhangsan','sex'=>'男']
// ['name','sex']
protected $auto = [];

//新增 自动完成列表
//只在新增数据的时候使用
protected $insert = [];

//更新 自动完成列表
//只在更新数据的时候使用
protected $update = [];

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

//依赖方法,model类会自动调用解析auto数组
//我们只需配置auto数组即可
protected function autoCompleteData($auto = []){}

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

  1. 自动写入时间戳
//是否需要自动写入时间戳
//可以是字符串类型和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';

配置方式

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

'auto_timestamp' => true
//或者设置时间格式
// 'auto_timestamp' => 'datatime'

在单独的模型类里设置

protected $autoWriteTimestamp = true;
//或者设置时间格式
// protected $autoWriteTimestamp = 'datatime';

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

//如:
protected $createTime = 'my_create_time_filed';
protected $updateTime = 'my_careate_time_field';

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

//如
protected $updateTime = false;

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

  1. 时间字段自动格式化输出
//输出格式
protected $dateFormat;

配置方式

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

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

也可以在model中设置

protected $dateFormat = 'Y/m/d H:i';
  1. 字段验证器
//字段验证规则
protected $validate = [];
//是否采用批量验证
protected $batchValidate = false;

/**
 * 设置字段验证
 * @access public
 * @param array|string|bool $rule  验证规则 true表示自动读取验证器类
 * @param array             $msg   提示信息
 * @param bool              $batch 批量验证
 * @return $this
 */
public function validate($rule = ture,$msg=[],$bath=false){}


/**
 * 自动验证数据
 * @access protected
 * @param array $data  验证数据
 * @param mixed $rule  验证规则
 * @param bool  $batch 批量验证
 * @return bool
 */
public function validateData($data,$rule=null,$batch=null){}

使用方式

在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之间'
]
];

在具体操作时调用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($data)){

    echo '数据格式符合要求';
}else{

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

对比

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

  1. 自动关联写入
// 关联对象
protected $relation;

// 关联自动写入(关联的属性名)
protectd $relationWrite = [];

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

  1. 只读字段
//用来保护那些不许要被更新的字段。
//比如,创建时间
//设置后再更新数据时,会字段过滤掉create_time字段
//避免更新到数据库。
protected $readonly = ['create_time'];
  1. 隐藏字段
//设置要隐藏的字段,
//该设置只在toArray(),和subToArray()方法中起作用
protected $hidden = [];

//相关方法
public function hidden($hidden=[],$override=false){

}

当使用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. 事件回调

支持的回调事件

before_insert 新增前
after_insert 新增后
before_update 更新前
after_update 更新后
before_write 写入前(新增和更新都会调用)
after_write 写入后(新增和更新都会调用)
before_delete 删除前
after_delete 删除后
注册的回调方法支持传入一个参数,当前示例模型对象,并且before_write,before_insert,before_update,before_delete返回false会结束执行。
使用方法

控制器里使用

//支持给一个位置注册多个事件
User::event('before_insert',function($user){

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

        return false;
    }
});

//这个也会生效,回到函数为beforeInsert
User::event('before_insert','beforeInsert');

模型里使用

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

class User extends Model{

    protected static function init(){

        User::event('before_insert',function($user){
            if($user->status != 1){
                return false;
            }
        }

        //注册第二个事件
        User::event('before_insert','beforeInsert');
    }
}

原理

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

$event = [
    //模型名称
    'user' => [
        //事件名称
        'before_insert' => [
            'callback_funciton','beforeInsert'
        ],
        'after_insert' => [
            'callback_function','afterInsert'
        ],
        'before_delete' => [
            'beforeDelete'
        ]
    ]
]

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

  1. 软删除

简介

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

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

namespace app\index\model;

use think\Model;
use think\model\SoftDelete;

class User extends Model{

    // 使用SoftDelete
    // trait 的使用方式
    // 使用trait跟类的继承相似
    use SoftDelete;


    //软删除标记的字段名
    protected $deleteTime = 'delete_time';
}

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);

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

User::withTrashed()->find();
User::withTrashed()->select();

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

User::onlyTranshed()->find();
User::onlyTranshed()->select();
  1. 类型转换

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

class User extends Model{

    protected $type = [
        'status' => 'integer',
        'score' => 'float',
        'login_timme' => 'datetime',
        'info' => 'array'
    ];
}

使用示例

//
$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

注意: 如果制定为时间戳类型(timestamp)的话,该字段会在写入的时候自动调用strtotime函数生成对应的时间戳,输出是自动使用dateFormat格式化时间戳,默认格式为Y:m:d H:i:s,如果想要改变输出格式,可以如下:

class User extends Model{

    protected $dataFormat = 'Y/m/d';
    protected $type = [
        'status' => 'integer',
        'score' => 'float',
        'birthday' => 'timestemp'//时间戳格式
    ];
}

或者如下:

class User extends Model{

    protected $type = [
        'status' => 'integer',
        'socre' => 'float',
        'birthday' => 'timestemp:Y/m/d'//写入时间戳,读取按照Y/m/d的格式来格式化输出。
    ];
}

原稿:http://blog.csdn.net/qq_20678155/article/details/68926487
作者:CSDN博主:輘酆

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容