模型定义

一.定义模型

定义一个和数据库表向匹配的模型; class User extends Model
模型会自动对应数据表,并且有一套自己的命名规则;
模型类需要去除表前缀(tp_),采用驼峰式命名,并且首字母大写;
tp_user(表名) => User
tp_user_type(表名) => UserType
如果担心设置的模型类名和 PHP 关键字冲突,可以开启应用类后缀;
在 app.php 中,设置 class_suffix 属性为 true 即可;
// 应用类库后缀
‘class_suffix’ => true,
设置完毕后,所有的控制器类名和模型类名需要加上 Controller 和 Model; class UserModel

二.设置模型

默认主键为 id,你可以设置其它主键,比如 uid; protected $pk = ‘uid’;
从控制器端调用模型操作,如果和控制器类名重复,可以设置别名; use app\model\User as UserModel;
在模型定义中,可以设置其它的数据表; protected $table = ‘tp_one’;
模型和控制器一样,也有初始化,在这里必须设置 static 静态方法;

  1. //模型初始化
  2. protected static function init()
  3. {
  4. //第一次实例化的时候执行 init
  5. echo '初始化 User 模型'; }

三.模型操作

模型操作数据和数据库操作一样,只不过不需要指定表了; UserModel::select();
数据库操作返回的列表是一个二维数组,而模型操作返回的是一个结果集; [[]] 和 [{}]

模型的添加与删除

一.数据添加

使用实例化的方式添加一条数据,首先实例化方式如下,两种均可:

$user = new UserModel();
$user = new \app\model\User();
设置要新增的数据,然后用 save()方法写入到数据库中,save()返回布尔值;

  1. $user->username = '李白';
  2. $user->password = '123';
  3. $user->gender = '男';
  4. $user->email = 'libai@163.com';
  5. $user->price = 100;
  6. $user->details = '123';
  7. $user->uid = 1011;
  8. $user->create_time = date('Y-m-d H:i:s');
  9. $user->save();

也可以通过 save()传递数据数组的方式,来新增数据;

  1. $user = new UserModel();
  2. $user->save([
  3. 'username' => '李白',
  4. 'password' => '123',
  5. 'gender' => '男',
  6. 'email' => 'libai@163.com',
  7. 'price' => 100,
  8. 'details' => '123',
  9. 'uid' => 1011,
  10. 'create_time' => date('Y-m-d H:i:s')
  11. ]);

模型新增也提供了 replace()方法来实现 REPLACE into 新增; $user->replace()->save();
当新增成功后,使用$user->id,可以获得自增 ID(主键需是 id); echo $user->id;
使用 saveAll()方法,可以批量新增数据,返回批量新增的数组;

  1. $dataAll = [
  2. [
  3. 'username' => '李白 1',
  4. 'password' => '123',
  5. 'gender' => '男',
  6. 'email' => 'libai@163.com',
  7. 'price' => 100,
  8. 'details' => '123',
  9. 'uid' => 1011,
  10. 'create_time' => date('Y-m-d H:i:s')
  11. ],
  12. [
  13. 'username' => '李白 2',
  14. 'password' => '123',
  15. 'gender' => '男',
  16. 'email' => 'libai@163.com',
  17. 'price' => 100,
  18. 'details' => '123',
  19. 'uid' => 1011,
  20. 'create_time' => date('Y-m-d H:i:s')
  21. ]
  22. ];
  23. $user = new UserModel();
  24. print_r($user->saveAll($dataAll));

二.数据删除

使用 get()方法,通过主键(id)查询到想要删除的数据; $user = UserModel::get(93);

然后再通过 delete()方法,将数据删除,返回布尔值; $user->delete();
可以使用静态方法调用 destroy()方法,通过主键(id)删除数据; UserModel::destroy(92)
静态方法 destroy()方法,也可以批量删除数据;
UserModel::destroy(‘80, 90, 91’);
UserModel::destroy([80, 90, 91]);
通过数据库类的查询条件删除; UserModel::where(‘id’, ‘>’, 80)->delete();
使用闭包的方式进行删除;

  1. UserModel::destroy(function ($query) {
  2. $query->where('id', '>', 80);
  3. });

模型修改与查询

一.数据修改

使用 get()方法通过主键获取数据,然后通过 save()方法保存修改,返回布尔值;

  1. $user = UserModel::get(118);
  2. $user->username = '李黑';
  3. $user->email = 'lihei@163.com';
  4. $user->save();

通过 where()方法结合 find()方法的查询条件获取的数据,进行修改;

  1. $user = UserModel::where('username', '李黑')->find();
  2. $user->username = '李白';
  3. $user->email = 'libai@163.com';
  4. $user->save();

save()方法只会更新变化的数据,如果提交的修改数据没有变化,则不更新;
但如果你想强制更新数据,即使数据一样,那么可以使用 force()方法; $user->force()->save();
Db::raw()执行 SQL 函数的方式,同样在这里有效; $user->price = Db::raw(‘price+1’);
如果只是单纯的增减数据修改,可以使用 inc/dec; $user->price = [‘inc’, 1];
直接通过 save([],[])两个数组参数的方式更新数据;

  1. $user->save([
  2. 'username' => '李黑',
  3. 'email' => 'lihei@163.com'
  4. ],['id'=>118]);

通过 saveAll()方法,可以批量修改数据,返回被修改的数据集合;

  1. $list = [
  2. ['id'=>118, 'username'=>'李白', 'email'=>'libai@163.com'],
  3. ['id'=>128, 'username'=>'李白', 'email'=>'libai@163.com'],
  4. ['id'=>129, 'username'=>'李白', 'email'=>'libai@163.com']
  5. ];
  6. $user->saveAll($list);

批量更新 saveAll()只能通过主键 id 进行更新;
使用静态方法结合 update()方法来更新数据,这里返回的是影响行数;

  1. UserModel::where('id', 118)->update([
  2. 'username' => '李黑',
  3. 'email' => 'lihei@163.com'
  4. ]);

另外一种静态方法 update(),返回的是对象实例;

  1. UserModel::update([
  2. 'id' => 118,
  3. 'username' => '李黑',
  4. 'email' => 'lihei@163.com'
  5. ]);

模型的新增和修改都是 save()进行执行的,它采用了自动识别体系来完成;
实例化模型后调用 save()方法表示新增,查询数据后调用 save()表示修改;
当然,如果在 save()传入更新修改条件后也表示修改;
再当然,如果编写的代码比较复杂的话,可以用 isUpdate()方法显示操作;

  1. //显示更新
  2. $user->isUpdate(true)->save();
  3. //显示新增
  4. $user->isUpdate(false)->save();

二.数据查询

使用 get()方法,通过主键(id)查询到想要的数据;
$user = UserModel::get(129);
return json($user);
也可以使用 where()方法进行条件筛选查询数据;
$user = UserModel::where(‘username’, ‘辉夜’)->find();
return json($user);
不管是 get()方法还是 find()方法,如果数据不存在则返回 Null;
和数据库查询一样,模型也有 getOrFail()方法,数据不存在抛出异常;
同上,还有 findOrEmpty()方法,数据不存在返回空模型;
通过模型->符号,可以得到单独的字段数据; return $user->username;
如果在模型内部获取数据,请不要用$this->username,而用如下方法;

  1. public function getUserName()
  2. {
  3. return self::where('username', '辉夜')->find()->getAttr('username');
  4. }

通过 all()方法,实现 IN 模式的多数据获取;
$user = UserModel::all(‘79, 118, 128’);
$user = UserModel::all([79, 118, 128]);
使用链式查询得到想要的数据;
UserModel::where(‘gender’, ‘男’)->order(‘id’, ‘asc’) ->limit(2)->select();
获取某个字段或者某个列的值;
UserModel::where(‘id’, 79)->value(‘username’);
UserModel::whereIn(‘id’,[79,118,128])->column(‘username’,’id’);
模型支持动态查询:getBy表示字段名;
UserModel::getByUsername(‘辉夜’);
UserModel::getByEmail(‘huiye@163.com’);
模型支持聚合查询;
UserModel::max(‘price’);

模型获取器与修改器

一.模型获取器

获取器的作用是对模型实例的数据做出自动处理;
一个获取器对应模型的一个特殊方法,该方法为 public;
方法名的命名规范为:getFieldAttr();
举个例子,数据库表示状态 status 字段采用的是数值;
而页面上,我们需要输出 status 字段希望是中文,就可以使用获取器;
在 User 模型端,我创建一个对外的方法,如下:

  1. public function getStatusAttr($value)
  2. {
  3. $status = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核'];
  4. return $status[$value];
  5. }

然后,在控制器端,直接输出数据库字段的值即可得到获取器转换的对应值;

  1. $user = UserModel::get(21);
  2. return $user->status;
  3. 8. 除了 getFieldAttr Field 可以是字段值,也可以是自定义的虚拟字段;
  4. public function getNothingAttr($value, $data)
  5. {
  6. $myGet = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核'];
  7. return $myGet[$data['status']];
  8. }
  9. return $user->nothing;

Nothing 这个字段不存在,而此时参数$value 只是为了占位,并未使用;
第二个参数$data 得到的是筛选到的数据,然后得到最终值;
如果你定义了获取器,并且想获取原始值,可以使用 getData()方法; return $user->getData(‘status’);
1直接输出无参数的 getData(),可以得到原始值,而$user 输出是改变后的;
dump($user->getData());
dump($user);
使用 WithAttr 在控制器端实现动态获取器,比如设置所有 email 为大写;

  1. $result = UserModel::WithAttr('email', function ($value) {
  2. return strtoupper($value);
  3. })->select();
  4. return json($result);

使用 WithAttr 在控制器端实现动态获取器,比如设置 status 翻译为中文;

  1. $result = UserModel::WithAttr('status', function ($value) {
  2. $status = [-1=>'删除', 0=>'禁用', 1=>'正常', 2=>'待审核'];
  3. return $status[$value];
  4. })->select();
  5. return json($result);

同时定义了模型获取器和动态获取器,那么模型修改器优先级更高;

二.模型修改器

模型修改器的作用,就是对模型设置对象的值进行处理;
比如,我们要新增数据的时候,对数据就行格式化、过滤、转换等处理;
模型修改器的命名规则为:setFieldAttr;
我们要设置一个新增,规定邮箱的英文都必须大写,修改器如下:

  1. public function setEmailAttr($value)
  2. {
  3. return strtoupper($value);
  4. }

除了新增,会调用修改器,修改更新也会触发修改器;
模型修改器只对模型方法有效,调用数据库的方法是无效的,比如->insert();

模型搜索器和数据集

一.模型搜索器

搜索器是用于封装字段(或搜索标识)的查询表达式;
一个搜索器对应模型的一个特殊方法,该方法为 public;
方法名的命名规范为:searchFieldNameAttr();
举个例子,我们要封装一个邮箱字符模糊查询,然后封装一个时间限定查询;
在 User 模型端,我创建两个对外的方法,如下:

  1. public function searchEmailAttr($query, $value)
  2. {
  3. $query->where('email', 'like', $value.'%');
  4. }
  5. public function searchCreateTimeAttr($query, $value)
  6. {
  7. $query->whereBetweenTime('create_time', $value[0], $value[1]);
  8. }

然后,在控制器端,通过 withSearch()静态方法实现模型搜索器的调用;

  1. $result = UserModel::withSearch(['email', 'create_time'],[
  2. 'email' => 'xiao',
  3. 'create_time' => ['2014-1-1', '2017-1-1']
  4. ])->select();

withSearch()中第一个数组参数,限定搜索器的字段,第二个则是表达式值;
如果想在搜索器查询的基础上再增加查询条件,直接使用链式查询即可; UserModel::withSearch(…)->where(‘gender’, ‘女’)->select()
如果你想在搜索器添加一个可以排序的功能,具体如下:

  1. public function searchEmailAttr($query, $value, $data)
  2. {
  3. $query->where('email', 'like', $value.'%');
  4. if (isset($data['sort'])) {
  5. $query->order($data['sort']);
  6. }
  7. }
  8. $result = UserModel::withSearch(['email', 'create_time'],[
  9. 'email' => 'xiao',
  10. 'create_time' => ['2014-1-1', '2017-1-1'],
  11. 'sort' => ['price'=>'desc']
  12. ])->select();

搜索器的第三个参数$data,可以得到 withSearch()方法第二参数的值;
字段也可以设置别名:’create_time’=>’ctime’

二.模型数据集

数据集由 all()和 select()方法返回数据集对象;
数据集对象和数组操作方法一样,循环遍历、删除元素等;
判断数据集是否为空,我们需要采用 isEmpty()方法;

  1. $resut = UserModel::where('id', 111)->select();
  2. if ($resut->isEmpty()) {
  3. return '没有数据!';
  4. }

使用模型方法 hidden()可以隐藏某个字段,使用 visible()显示只某个字段;
使用 append()可以添加某个获取器字段,使用 withAttr()对字段进行函数处理;

  1. $result = UserModel::select();
  2. $result->hidden(['password'])->append(['nothing'])->withAttr('em
  3. ail', function ($value) {
  4. return strtoupper($value);
  5. });
  6. return json($result);
  7. 6. 使用模型方法 filter()对筛选的数据进行过滤;
  8. $result = UserModel::select()->filter(function ($data) {
  9. return $data['price'] > 100;
  10. });
  11. return json($result);

也可以使用数据集之后链接 where()方法来代替 filter()方法; $result = UserModel::select()->where(‘price’, ‘>’, ‘100’);
数据集甚至还可以使用 order()方法进行排序; $result = UserModel::select()->order(‘price’, ‘desc’);
使用 diff()和 intersect()方法可以计算两个数据集的差集和交集;

  1. $result1 = UserModel::where('price', '>', '80')->select();
  2. $result2 = UserModel::where('price', '<', '100')->select();
  3. return json($result1->diff($result2));
  4. return json($result2->intersect($result1));