模型

定义

一、模型定义

<?php
namespace app\index\model;

use think\Model;

class User extends Model
{
}

模型会自动对应数据表,模型类的命名规则是除去表前缀的数据表名称,采用驼峰法命名,并且首字母大写

模型自动对应的数据表名称都是遵循小写+下划线规范,如果你的表名有大写的情况,必须通过设置模型的table属性。

// 开启应用类库后缀
    'class_suffix'           => true,

 开启后,所有的应用类库定义的时候都需要加上对应后缀,包括控制器类。

<?php
namespace app\index\model;

use think\Model;

class UserModel extends Model
{
}

二、模型设置

默认主键为id,如果你没有使用id作为主键名,需要在模型中设置属性

5.1中模型不会自动获取主键名称,必须设置pk属性。

<?php
namespace app\index\model;

use think\Model;

class User extends Model
{
    // 设置当前模型对应的完整数据表名称
    protected $table = 'think_user';
    
    // 设置当前模型的数据库连接
    protected $connection = 'db_config';

    // 设置当前模型的主键
    protected $pk = 'uid';
}

 

属性描述
name模型名(默认为当前不含后缀的模型类名)
table数据表名(默认自动获取)
pk主键名(默认为id
connection数据库连接(默认读取数据库配置)
query模型使用的查询类名称
field模型对应数据表的字段列表(数组)

三、模型初始化

<?php
namespace app\index\model;

use think\Model;

class User extends Model
{

    // 模型初始化
    protected static function init()
    {
        //TODO:初始化内容
    }
}

模型初始化方法通常用于注册模型的事件操作。

init必须是静态方法,并且只在第一次实例化的时候执行

四、模型操作

数据库查询

Db::name('user')->where('id','>',10)->select();

模型操作

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

虽然看起来是相同的查询条件,但一个最明显的区别是查询结果的类型不同。第一种方式的查询结果是一个(二维)数组,而第二种方式的查询结果是包含了模型(集合)的数据集。不过,在大多数情况下,这二种返回类型的使用方式并无明显区别。

模型操作和数据库操作的另外一个显著区别是模型支持包括获取器、修改器、自动完成在内的一系列自动化操作和事件,简化了数据的存取操作,但随之而来的是性能有所下降(其实并没下降,而是自动帮你处理了一些原本需要手动处理的操作)。

新增

一、添加一条数据

1. 实例化模型对象后赋值

$user           = new User;
$user->name     = 'thinkphp';
$user->email    = 'thinkphp@qq.com';
$user->save();

save方法返回影响的记录数

2. 直接传入数据到save方法批量赋值

$user = new User;
$user->save([
    'name'  =>  'thinkphp',
    'email' =>  'thinkphp@qq.com'
]);

3.直接在实例化的时候传入数据

$user = new User([
    'name'  =>  'thinkphp',
    'email' =>  'thinkphp@qq.com'
]);
$user->save();

实例化传入的模型数据也不会经过修改器处理。

4.过滤非数据表字段的数据

$user = new User;
// 过滤post数组中的非数据表字段数据
$user->allowField(true)->save($_POST);

5. 通过外部赋值给模型,直接写入某些字段

$user = new User;
// post数组中只有name和email字段会写入
$user->allowField(['name','email'])->save($_POST);

6. 数据过滤后赋值(建议)

$user = new User;
// 过滤post数组中的非数据表字段数据
$data = Request::only(['name','email']);
$user->save($data);

二、Replace 

$user           = new User;
$user->name     = 'thinkphp';
$user->email    = 'thinkphp@qq.com';
$user->replace()->save();

三、获取自增ID

$user           = new User;
$user->name     = 'thinkphp';
$user->email    = 'thinkphp@qq.com';
$user->save();
// 获取自增ID
echo $user->user_id;

不要在同一个实例里面多次新增数据,如果确实需要多次新增,可以使用后面的静态方法处理。

四、添加多条数据

$user = new User;
$list = [
    ['name'=>'thinkphp','email'=>'thinkphp@qq.com'],
    ['name'=>'onethink','email'=>'onethink@qq.com']
];
$user->saveAll($list);

saveAll方法新增数据返回的是包含新增模型(带自增ID)的数据集对象。

saveAll方法新增数据默认会自动识别数据是需要新增还是更新操作,当数据中存在主键的时候会认为是更新操作,如果你需要带主键数据批量新增,可以使用下面的方式:

五、静态方法

$user = User::create([
    'name'  =>  'thinkphp',
    'email' =>  'thinkphp@qq.com'
]);
echo $user->name;
echo $user->email;
echo $user->id; // 获取自增ID

save方法不同的是,create方法返回的是当前模型的对象实例。

最佳实践

新增数据的最佳实践原则:使用create方法新增数据,使用saveAll批量新增数据

更新

一、查找并更新

$user = User::where('status',1)
	->where('name','liuchen')
	->find();
$user->name     = 'thinkphp';
$user->email    = 'thinkphp@qq.com';
$user->save();
//如果只是字段的增加/减少,也可以直接用inc/dec方式
$user = User::get(1);
$user->name     = 'thinkphp';
$user->email    = 'thinkphp@qq.com';
$user->score	= ['inc', 1];
$user->save();

二、直接更新

$user = new User;
// 过滤post数组中的非数据表字段数据
$user->allowField(true)->save($_POST,['id' => 1]);

最佳建议是在传入模型数据之前就进行过滤

$user = new User();
// post数组中只有name和email字段会写入
$data = Request::only(['name','email']);
$user->save($data, ['id' => 1]);

三、批量更新

最佳建议是在传入模型数据之前就进行过滤

批量更新仅能根据主键值进行更新,其它情况请自行处理。

$user = new User();
// post数组中只有name和email字段会写入
$data = Request::only(['name','email']);
$user->save($data, ['id' => 1]);

四、静态方法

模型支持调用数据库的方法直接更新数据

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

五、自动识别

  • 实例化模型后调用save方法表示新增;
  • 查询数据后调用save方法表示更新;
  • save方法传入更新条件后表示更新;

显式更新数据:

// 实例化模型
$user = new User;
// 显式指定更新数据操作
$user->isUpdate(true)
    ->save(['id' => 1, 'name' => 'thinkphp']);

显式新增数据:

$user = User::get(1);
$user->name = 'thinkphp';
// 显式指定当前操作为新增操作
$user->isUpdate(false)->save();

不要在一个模型实例里面做多次更新,会导致部分重复数据不再更新,正确的方式应该是先查询后更新或者使用模型类的update方法更新。

如果你调用save方法进行多次数据写入的时候,需要注意,第二次save方法的时候必须使用isUpdate(false),否则会视为更新数据。

最佳实践

更新的最佳实践原则是:如果需要使用模型事件,那么就先查询后更新,如果不需要使用事件,直接使用静态的Update方法进行条件更新,如非必要,尽量不要使用批量更新。

删除

一、删除当前模型

$user = User::get(1);
$user->delete();

delete方法返回影响的记录数,V5.1.6+版本开始返回布尔值

二、根据主键删除

User::destroy(1);
// 支持批量删除多个数据
User::destroy('1,2,3');
// 或者
User::destroy([1,2,3]);

destroy方法传入空值(包括空字符串和空数组)的时候不会做任何的数据删除操作,但传入0则是有效的

三、条件删除

还支持使用闭包删除,例如:

User::destroy(function($query){
    $query->where('id','>',10);
});

或者通过数据库类的查询条件删除

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

直接调用数据库的delete方法的话无法调用模型事件。

最佳实践

删除的最佳实践原则是:如果删除当前模型数据,用delete方法,如果需要直接删除数据,使用destroy静态方法。

查询

模型查询和数据库查询方法的区别主要在于,模型中的查询的数据在获取的时候会经过获取器的处理,以及更加对象化的获取方式。

一、获取单个数据

// 取出主键为1的数据
$user = User::get(1);
echo $user->name;

// 使用查询构造器查询满足条件的数据
$user = User::where('name', 'thinkphp')->find();
echo $user->name;

模型无论使用get还是find方法查询,返回的是都当前模型的对象实例,如果查询数据不存在,则返回Null,除了获取模型数据外,还可以使用模型的方法。

模型无论使用get还是find方法查询,返回的是都当前模型的对象实例,如果查询数据不存在,则返回Null,除了获取模型数据外,还可以使用模型的方法。

如果你是在模型内部获取模型数据,请不要使用$this->name的方式来获取数据,请使用$this->getAttr('name') 替代。

二、获取多个数据

// 根据主键获取多个数据
$list = User::all('1,2,3');
// 或者使用数组
$list = User::all([1,2,3]);
// 对数据集进行遍历操作
foreach($list as $key=>$user){
    echo $user->name;
}

//V5.1.21+版本开始,可以在all方法之前使用Db类的查询链式操作,

// 使用查询构造器查询
$list = User::where('status', 1)->limit(3)->order('id', 'asc')->all();
foreach($list as $key=>$user){
    echo $user->name;
}

要更多的查询支持,一样可以使用查询构造器:

// 使用查询构造器查询
$list = User::where('status', 1)->limit(3)->order('id', 'asc')->select();
foreach($list as $key=>$user){
    echo $user->name;
}

三、使用查询构造器

1.获取某个字段或者某个列的值

// 获取某个用户的积分
User::where('id',10)->value('score');
// 获取某个列的所有值
User::where('status',1)->column('name');
// 以id为索引
User::where('status',1)->column('name','id');

valuecolumn方法返回的不再是一个模型对象实例,而是纯粹的值或者某个列的数组。

2.动态查询

支持数据库的动态查询方法,例如:

// 根据name字段查询用户
$user = User::getByName('thinkphp');

// 根据email字段查询用户
$user = User::getByEmail('thinkphp@qq.com');

四、查询缓存

get方法和all方法的支持使用查询缓存,可以直接在第二个参数传入true表示开启查询缓存。

$user = User::get(1,true);
$list  = User::all('1,2,3',true);

如果要设置缓存标识,则必须在第三个参数传入缓存标识。

$user = User::get(1,'','user');
$list  = User::all('1,2,3','','user_list');

最佳实践

模型查询的最佳实践原则是:在模型外部使用静态方法进行查询,内部使用动态方法查询,包括使用数据库的查询构造器。模型的查询始终返回对象实例,但可以和数组一样使用。

 数据库模型
查询

find()--null,findOrFail()--异常,findOrEmpty()--空数组

select()--空数组,selectOrFail()--异常

value()--null

column()--空数组

getAttr('name')【内部】

get()

find()

all()

select()

value()

column()

新增

insert($data)

data($data)->insert()

strict(false)->insert($data)

insert($data,true)

insertGetId($data)

insertAll($data)

saveAll()

create()

save()

allowField()->save()

replace()->save()

更新

updata($data)

data($data)->updata()

setField()

setInc()/setDec()

先查询,save()【使用模型事件】

静态update()

allowField(true)->save()

isUpdate(true)->save()

删除delete()

delete()

destroy()

获取器

一、获取器

getFieldNameAttr

FieldName为数据表字段的驼峰转换,定义了获取器之后会在下列情况自动触发: 

  • 模型的数据对象取值操作($model->field_name);
  • 模型的序列化输出操作($model->toArray()toJson());
  • 显式调用getAttr方法($this->getAttr('field_name'));

获取器的场景包括:

  • 时间日期字段的格式化输出;
  • 集合或枚举类型的输出;
  • 数字状态字段的输出;
  • 组合字段的输出;

 获取器还可以定义数据表中不存在的字段

获取器方法的第二个参数传入的是当前的所有数据数组。

<?php
class User extends Model 
{
    public function getStatusTextAttr($value,$data)
    {
        $status = [-1=>'删除',0=>'禁用',1=>'正常',2=>'待审核'];
        return $status[$data['status']];
    }
}

二、获取原始数据

$user = User::get(1);
// 通过获取器获取字段
echo $user->status;
// 获取原始字段数据
echo $user->getData('status');
// 获取全部原始数据
dump($user->getData());

三、动态获取器

V5.1.20+版本开始,可以支持对模型使用动态获取器,无需在模型类中定义获取器方法。

User::withAttr('name', function($value, $data) {
	return strtolower($value);
})->select();

withAttr方法支持多次调用,定义多个字段的获取器。另外注意,withAttr方法之后不能再使用模型的查询方法,必须使用Db类的查询方法。

如果同时还在模型里面定义了相同字段的获取器,则动态获取器优先,也就是可以临时覆盖定义某个字段的获取器。

支持对关联模型的字段使用动态获取器,例如:

User::with('profile')->withAttr('profile.name', function($value, $data) {
	return strtolower($value);
})->select();

修改器

一、修改器

setFieldNameAttr

修改器的使用场景和读取器类似:

  • 时间日期字段的转换写入;
  • 集合或枚举类型的写入;
  • 数字状态字段的写入;
  • 某个字段涉及其它字段的条件或者组合写入;

定义了修改器之后会在下列情况下触发:

  • 模型对象赋值;
  • 调用模型的data方法,并且第二个参数传入true
  • 调用模型的save方法,并且传入数据;
  • 显式调用模型的setAttr方法;
  • 定义了该字段的自动完成;
<?php
class User extends Model 
{
    public function setNameAttr($value)
    {
        return strtolower($value);
    }
}

二、批量修改

除了赋值的方式可以触发修改器外,还可以用下面的方法批量触发修改器:

$user = new User();
$data['name'] = 'THINKPHP';
$data['email'] = 'thinkphp@qq.com';
$user->data($data, true);
$user->save();
echo $user->name; // thinkphp

如果为nameemail字段都定义了修改器的话,都会进行处理。

或者直接使用save方法触发,例如:

$user = new User();
$data['name'] = 'THINKPHP';
$data['email'] = 'thinkphp@qq.com';
$user->save($data);
echo $user->name; // thinkphp

修改器方法仅对模型的写入方法有效,调用数据库的写入方法写入无效,例如下面的方式修改器无效。

$user = new User();
$data['name'] = 'THINKPHP';
$data['email'] = 'thinkphp@qq.com';
$user->insert($data);

搜索器

searchFieldNameAttr

FieldName为数据表字段的驼峰转换,搜索器仅在调用withSearch方法的时候触发。

搜索器的场景包括:

  • 限制和规范表单的搜索条件;
  • 预定义查询条件简化查询;
<?php
namespace app\index\model;

use think\Model;

class User extends Model 
{
    public function searchNameAttr($query, $value, $data)
    {
        $query->where('name','like', $value . '%');
    }
    
    public function searchCreateTimeAttr($query, $value, $data)
    {
        $query->whereBetweenTime('create_time', $value[0], $value[1]);
    }    
}

然后,我们可以使用下面的查询

User::withSearch(['name','create_time'], [
		'name'			=>	'think',
    	'create_time'	=>	['2018-8-1','2018-8-5'],
        'status'		=>	1
    ])
	->select();

搜索器通常会和查询范围进行比较,搜索器无论定义了多少,只需要一次调用,查询范围如果需要组合查询的时候就需要多次调用。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值