定义
定义一个和数据库表相匹配的模型;
<?php
namespace app\model;
use think\Model;
class User extends Model{
}
模型会自动对应数据表,并且有一套自己的命名规则;模型类需要去除表前缀(tp_),采用驼峰式命名,并且首字母大写,对应规则如下:
tp_user(表名) => User
tp_user_type(表名) => UserType
创建空模型后,我们可以在控制器调用,创建控制器 DataModel.php。可以直接使用模型的名称 User::*调用查询方法,比如 select()等;如果没有代码提示,请参照【ThinkPHP6.x框架】(6)数据库进阶4(事务与结果集处理)。
<?php
namespace app\controller;
use app\model\User;
class DataModel{
public function index(){
return(User::select());
}
}
设置模型
如果担心设置的模型类名和 PHP关键字冲突,可以开启应用类后缀;比如设置:Class UserModel这种,需要更改文件名为 UserModel.php;然后设置一下$name属性为指定 user(表名)即可实现;
class UserModel extends Model
{
protected $name = 'user';
}
默认主键为 id,你可以设置其它主键,比如 uid;
protected $pk = 'uid';
从控制器端调用模型操作,如果和控制器类名重复,可以设置别名;
use app\model\User as UserModel;
在模型定义中,可以设置其它的数据表(即使);
protected $table = 'tp_one';
模型和控制器一样,也有初始化,在这里必须设置static静态方法;
//模型初始化
protected static function init() {
//第一次实例化的时候执行
init echo '初始化User模型';
}
Create
使用实例化的方式添加一条数据,首先实例化方式如下,两种均可:
$user = new UserModel();
$user = new \app\model\User();
设置要新增的数据,然后用 save()方法写入到数据库中,save()返回布尔值;
$user->username = '李白';
$user->password = '123';
$user->gender = '男';
$user->email = 'libai@163.com';
$user->price = 100;
$user->details = '123';
$user->uid = 1011;
$user->save();
// save可以传入数组
$user = new UserModel();
$user->save([
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => 'libai@163.com',
'price' => 100,
'details' => '123',
'uid' => 1011
]);
使用 saveAll()方法,可以批量新增数据,返回批量新增的数组;
$dataAll = [
[
'username' => '李白1',
'password' => '123',
'gender' => '男',
'email' => 'libai@163.com',
'price' => 100,
'details' => '123',
'uid' => 1011
],
[
'username' => '李白2',
'password' => '123',
'gender' => '男',
'email' => 'libai@163.com',
'price' => 100,
'details' => '123',
'uid' => 1011
]
];
$user = new UserModel();
dump($user->saveAll($dataAll));
使用 allowField()方法,允许要写入的字段,其它字段就无法写入了;
$user->allowField(['username','email', 'password','details'])->save(...)
模型新增也提供了 replace()方法来实现 REPLACE into新增;
$user->replace()->save();
使用::create()静态方法,来创建要新增的数据;
$user = UserModel::create([
'username' => '李白',
'password' => '123',
'gender' => '男',
'email' => 'libai@163.com',
'price' => 100,
'details' => '123',
'uid' => 1011
], ['username', 'password', 'details'], false);
//参数 1是新增数据数组,必选
//参数 2是允许写入的字段,可选
//参数 3为是否 replace写入,默认 false为 Insert写入
Delete
使用 find()方法,通过主键(id)查询到想要删除的数据;然后再通过delete()方法,将数据删除,返回布尔值;
$user = UserModel::find(93);
$user->delete();
也可以使用静态方法调用 destroy()方法,通过主键(id)删除数据;同时,静态方法destroy()方法,也可以批量删除数据;
UserModel::destroy(92);
UserModel::destroy([80, 90, 91]);
通过数据库类的查询条件删除;或者使用闭包的方式进行删除;
UserModel::destroy(function ($query) {
$query->where('id', '>', 80);
});
Update
使用 find()方法获取数据,然后通过 save()方法保存修改,返回布尔值;
$user = UserModel::find(118);
$user->username = '李黑';
$user->email = 'lihei@163.com';
$user->save();
通过 where()方法结合 find()方法的查询条件获取的数据,进行修改;
$user = UserModel::where('username', '李黑')->find();
$user->username = '李白';
$user->email = 'libai@163.com';
$user->save();
通过 saveAll()方法,可以批量修改数据,返回被修改的数据集合,只能通过主键id进行更新。
$list = [
['id'=>118, 'username'=>'李白', 'email'=>'libai@163.com'],
['id'=>128, 'username'=>'李白', 'email'=>'libai@163.com'],
['id'=>129, 'username'=>'李白', 'email'=>'libai@163.com']
];
$user->saveAll($list);
如果你想强制更新数据,即使数据一样,那么可以使用 force()方法;
$user->force()->save();
Db::raw()执行 SQL函数的方式,同样在这里有效;
$user->price = Db::raw('price+1');
使用 allowField()方法,允许要更新的字段,其它字段就无法写入了;
$user->allowField(['username','email'])->save(...)
使用静态方法::update()更新,返回的是对象实例;
UserModel::update([
'id' => 118,
'username' => '李黑',
'email' => 'lihei@163.com'
]);
UserModel::update([
'username' => '李黑',
'email' => 'lihei@163.com'
],['id'=>118]);
UserModel::update([
'username' => '李黑',
'email' => 'lihei@163.com'
], ['id'=>118], ['username']);
//只更新 username
注意:
模型的新增和修改都是save()进行执行的,它采用了自动识别体系来完成;
实例化模型后调用save()方法表示新增,查询数据后调用 save()表示修改;
当然,如果在save()传入更新修改条件后也表示修改;
Retrieve
使用 where()方法进行条件筛选查询数据;
$user = UserModel::where('username', '辉夜')->find();
return json($user);
注意:
调用 find()方法时,如果数据不存在则返回 Null;同上,还有 findOrEmpty()方法,数据不存在返回空模型;此时,可以后使用 isEmpty()方法来判断,是否为空模型;
$user = UserModel::findOrEmpty(1111);
if ($user->isEmpty()) {
echo '空模型,无数据!';
}
使用 select([])方式,查询多条指定 id的字段,不指定就是所有字段;
$user = UserModel::select([19,20,21]);
foreach ($user as $key=>$obj) {
echo $obj->username;
}
模型方法也可以使用 where等连缀查询,和数据库查询方式一样;
$user = UserModel::where('status', 1)
->limit(5)
->order('id', 'desc')
->select();
获取某个字段 value()或者某个列 column()的值;
UserModel::where('id', 79)->value('username');
UserModel::whereIn('id',[79,118,128])->column('username','id');
模型支持动态查询:getBy*,*表示字段名;
UserModel::getByUsername('辉夜');
UserModel::getByEmail('huiye@163.com');
模型支持聚合查询:max、min、sum、count、avg等;
UserModel::max('price');
使用 chunk()方法可以分批处理数据,数据库查询时讲过,防止一次性开销过大;
UserModel::chunk(5, function ($users) {
foreach($users as $user) {
echo $user->username;
}
echo '<br>------<br>';
});
可以利用游标查询功能,可以大幅度减少海量数据的内存开销,它利用了 PHP 生 成器特性。每次查询只读一行,然后再读取时,自动定位到下一行继续读取;
foreach (UserModel::where('status', 1)->cursor() as $user)
{
echo $user->username;
echo '<br>------<br>';
}
模型的字段
模型的数据字段和表字段是对应关系,默认会自动获取,包括字段的类型。自动获取会导致增加一次查询,如果在模型中配置字段信息,会减少内存开销。可以在模型设置$schema字段,明确定义字段信息,字段需要对应表写完整。
//设置字段信息,需要写完整的数据表字段
protected $schema = [
'id' => 'int',
'username' => 'string',
'status' => 'int',
'create_time'=> 'datetime',
'...' => '...'
];
系统提供了一条命令,生成一个字段信息缓存,可以自动生成;
php think optimize:schema
生成后的字段缓存文件在 runtime下 schema文件加下。我们可以先把这里的键值对复制到$schema属性上,开启 trace测试效果。这时,在控制器执行查询,会发现减少了一次 SQL查询,只不过,大可不必设置$schema属性,因为它只对模型有效。如果想模型和数据库 Db类同时有效,直接运用字段缓存文件即可。默认情况下字段缓存文件是关闭状态,需要在 config/database.php开启;
// 开启字段缓存
'fields_cache' => true,
当数据获取到后,想要单独获取数据可以用->和数组方式来获取;
$user = UserModel::find(19);
echo $user->username;
echo $user['email'];
如果我们在模型端把数据整理好,交给控制器直接调用,如下方式:
//模型端
public function getUsername($id) {
$obj = $this->find($id);
return $obj->getAttr('username');
}
//控制器端调用
$user = new UserModel();
return $user->getUsername(19);
字段的赋值操作,也可以是->和数组方式,作用就是提交给模型处理。
$user = new UserModel();
$user->username = 'Mr.Lee';
$user['email'] = 'lee@163.com';
默认情况下,字段是严格区分大小写的,也就是需要和数据表字段保持一致。
echo $user->create_time;
我们可以在模型属性$strict设置为 false即可实现非严格字段;
echo $user->createTime; //并非肆无忌惮的不严格,只能首字母大写