# 模型实战开发之模型使用技巧 > 本节课讲的模型实际上是就是常说的物理模型 (数据模型) [TOC] ## 模型的建立 建立一个新模型很简单 详情参见 https://www.kancloud.cn/mikkle/thinkphp5_study/268682 ~~~ namespace app\base\model; use think\Model; /** * Created by PhpStorm. * User: Mikkle * Q Q:776329498 * Date: 2017/2/8 * Time: 1:01 */ class AdminUser extends Base { protected $table = "my_admin_user"; } ~~~ >[info] 模型中使用中,我们根据自身情况继承Base基类或者子基类,在模型中 > 模型中,只要定义好$table即可正常使用了. ## TP5模型最常用且实用的方法(写入部分) ### 模型的自动完成功能 >[success] 支持auto、insert和update三个属性,可以分别在写入、新增和更新的时候进行字段的自动完成机制,auto属性自动完成包含新增和更新操作 > 模型自动完成 只需要在model中定义三种对应的数组即可,注意未赋值的数组需要定义修改器 我们现在拿那个model实例说明一下:这个是半年前写的代码 点开下面链接查看全部代码 https://www.kancloud.cn/mikkle/thinkphp5_study/329928 ~~~ protected $insert = ['status'=>1,'guid','order_no','order_state'=>0,'pay_type'=>0,'send_state'=>0,'is_comment'=>0,'factory_state'=>0]; ~~~ 大家看一下这段代码,我使用了 对象中$insert这个属性赋值,负责方式是数组. >[danger] 当定义 $insert字段时,在写入时候模型会自动处理这些字段 > 当定义 $update字段时,在更新时候模型会自动处理这些字段 > 当定义 $auto字段时,在写入和更新时候模型都会自动处理这些字段 其中 guid 字段和order_no字段我并没有给出指定的值,那这时候会调用对应的修改器对该字段进行赋值 这个自动完成非常实用 特别是写入时候的自动完成($insert). ### 模型的修改器 >[danger] 模型的修改器作用是可以在数据赋值的时候自动进行转换处理 #### 修改器的实例 我们看一下自动完成中提到的 guid 字段和order_no字段的修改器 ~~~ protected function setGuidAttr($value, $data) { return $this->create_uuid() ; } /** * 订单类获取器 含防重复筛查 * Power by Mikkle * QQ:776329498 * @param $value * @param $data * @return string */ protected function setOrderNoAttr($value, $data) { do { $order_no= date('Ymd').$this->builderRand(); } while ($this->where('order_no',$order_no)->count()==1); return $order_no ; } ~~~ #### 模型修改器的建立方式 >[info] 修改器方法的命名规范为:setFieldNameAttr 我们只要在将字段转换成 大写驼峰 拼接在set. 和 Attr之间即可 | 字段名称 | 字段大写驼峰名称 |拼接后修改器对应方法名称 | | --- | --- |--- | | guid | Guid |setGuidAttr | | order_no | OrderNo |setOrderNoAttr | #### 修改器参数说明 $value, $data | 值名称 | 参数说明 |值类型| | --- | --- |--- | | $value | 当前模型中对应字段传入的值 |--- | | $data | 当前模型中对应字段传入的所有值 |数组 | #### 修改器实例讲解 在订单模型创建新数据时候,我需要在给新数据赋值一个新的GUID以及唯一的数字型订单号, 这两个实例都未用到$value, $data两个参数,而使用到基类中的create_uuid builderRand ~~~ /** * 创建个性GUID * Power by Mikkle * QQ:776329498 * @param string $base_code * @return string */ public function create_uuid($base_code = '') { if (empty($base_code)) { $base_name = basename(str_replace('\\', '/', get_called_class()), '.php'); $uuid_list = ModelCode::$uuid_list; $base_code = isset($uuid_list[$base_name]) ? $uuid_list[$base_name] : 'QT'; } $uuid = $base_code . strtoupper(uniqid()) . $this->builderRand(6); return $uuid; } /** * 创建随机数 * Power by Mikkle * QQ:776329498 * @param int $num 随机数位数 * @return string */ public function builderRand($num=8){ return substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, $num); } ~~~ >[info] 其中 create_uuid这个方法名不规范啊,现在要想改一下啊,不知道要动多少文件. > (还有项目git中) 忍了吧 !大家千万别学我 > 另外 setOrderNoAttr 方法中,通过while方法进行查库比对 确保唯一 其实以前写个的这个方法也不严谨,存在可能发生的bug ~~~ do { $order_no= date('Ymd').$this->builderRand(); } while ($this->where('order_no',$order_no)->count()==1); //bug 应该 count()>0; return $order_no ; ~~~ 如果数据库中如果已经出现重复,那查库验证就失效了! 好吧!我承认,我是专职写bug的! #### 修改器的触发方法 修改器会在使用save方法触发 官方文档中也介绍了另一种触发方法 ~~~ $user = new User(); $data['name'] = 'THINKPHP'; $data['email'] = 'thinkphp@qq.com'; $user->data($data, true); $user->save(); echo $user->name; // thinkphp ~~~ >[info] 换句话说就是使用model新增和修改都会调用和使用的修改器 ### 修改器使用注意事项即只读属性字段的应用 那么新的问题来了,当修改数据时候,如果传值有这两个字段数据时候,我们发现guid和order_no字段的全部变了.而且是修改一次变更一次.这两个字段可以说是重要索引字段 那么所有关联数据你猜会咋样 TP5的model方法 自读字段的设置 就最便捷的解决方法 > 不要问我 我是如何知道这个问题的,伤疤都快没有了,大家不要再揭了 #### 只读字段的定义 > 只读字段用来保护某些特殊的字段值不被更改,这个字段的值一旦写入,就无法更改。 要使用只读字段的功能,我们只需要在模型中定义readonly属性: ~~~ protected $readonly = ['guid','order_no']; ~~~ #### 只读字段放的位置 我的基类中有下面一行代码,一般人我不告诉他 嘿嘿 ~~~ protected $readonly = ['guid']; ~~~ ### 自动时间戳 >[info] **protected $autoWriteTimestamp = true;** 一句话的事情 ,我每个表基本都有 ### 类型转换 这个我一直没有怎么用到 想了解的 请查看官方手册吧 https://www.kancloud.cn/manual/thinkphp5/138669 >[info] 模型中写入部分的常用的方法大体上 就这么多 再重申一下 一个是自动完成 一个修改器 还有一个只读字段 这三个方法是配合使用来完成数据的数据写入工作, ## TP5模型最常用且实用的方法(读取部分) ### 获取器的使用 >[info] 获取器的作用是在获取数据的字段值后按照我们定义的方法进行自动处理 #### 模型获取器的建立方式 >[info] 修改器方法的命名规范为:**getFieldNameAttr** 还是看order例子中的一段代码 ~~~ public function getPayTypeAttr($value, $data){ if ($value){ $get_data = ['WxPay'=>'微信支付','AliPay'=>'支付宝支付']; return isset($get_data[$value]) ? $get_data[$value] : '其他方式'; }else{ return $value; } } public function getIsPayTextAttr($value, $data){ $get_data = ['0'=>'未付款','1'=>'已付款']; return $get_data[$data['is_pay']]; } ~~~ 我们只要在将字段转换成 大写驼峰 拼接在get. 和 Attr之间即可 | 字段名称 | 字段大写驼峰名称 |拼接后获取器对应方法名称 | | --- | --- |--- | | pay_type | PayType |getPayTypeAttr | | is_pay_text | IsPayText |getIsPayTextAttr | 当字段中不存在的时候,我们随意append一个新字段,如果想获取is_pay的中文说明,就append写一个is_pay_text字段,并用$data中的值进行处理返回想要的值. #### 获取器参数说明 $value, $data | 值名称 | 参数说明 |值类型| | --- | --- |--- | | $value | 当前模型中对应字段读取的值 |--- | | $data | 当前模型中读取的所有值 |数组 | #### 获取器的触发方式 获取器只有当获取某个数据属性的时候自动触发,如果你要获取包含修改器处理的全部数据属性的话,可以使用下面的方法: | 触发方法 | 触发方法实例 | | --- | --- | | 模型的数据对象取值操作 | $model->field_name | | 模型的序列化输出操作 | $model->toArray() ;$model->toJson() | | 显式调用getAttr方法 | $this->getAttr('field_name') | | 附加字段要append | `$model->append(['field_name'])->toArray()` | 备注:定义修改器的字段 如果要获取原始数据的时候 使用下面官方文档中的方法 ~~~ $user = User::get(1); // 通过获取器获取字段 echo $user->status; // 获取原始字段数据 echo $user->getData('status'); // 获取全部原始数据 dump($user->getData()); ~~~ #### 获取器小结 >[danger] 获取器在项目中使用率比较高,我个人不建设使用和字段同名的获取器,而使用别名的获取器. > 特别是项目进行中时候,你添加的同名获取器,可能会引发老代码bug