## TP5实战开发---模型技巧 在MVC模式下 model 的灵活应用可以减少代码量,逻辑处理也更加清晰明确 下面 我拿一个商城的订单Model实例来简单介绍TP5的模型 (model)的用法 ~~~ <?php /** * Created by PhpStorm. * User: Mikkle * Email:776329498@qq.com * Date: 2017/1/4 * Time: 17:00 */ namespace app\base\model; use think\Db; use think\Model; class Orders extends Base { protected $table = "my_orders"; protected $name = "orders"; protected $pk = "id"; protected $insert = ['status'=>1,'guid','order_no','order_state'=>0,'pay_type'=>0,'send_state'=>0,'is_comment'=>0,'factory_state'=>0]; protected $autoWriteTimestamp = true; } ~~~ 先看一下前一部分 >[info] protected $table = "my_orders"; //表名 > protected $name = "orders"; > protected $pk = "id"; > protected $insert = ['status'=>1,'guid','order_no','order_state'=>0,'pay_type'=>0,'send_state'=>0,'is_comment'=>0,'factory_state'=>0]; > protected $autoWriteTimestamp = true; //开启时间戳 其中这一部分主要说的是 自动完成 protected $insert 在这部分中后面定义了一个数组,其中有一部分已经定义值 而未赋值将自动调用修改器完成。 ### Model中的获取器和修改器 >[info] 详情参见 我这里只讲实例 > 获取器 http://www.kancloud.cn/manual/thinkphp5/135192 > 修改器 http://www.kancloud.cn/manual/thinkphp5/135193 在这个订单表中 使用获取器 ~~~ /** * 获取器 * Power by Mikkle * QQ:776329498 * @param $value * @param $data * @return mixed */ public function getDistributeAttr($value, $data){ $get_data = ['SF'=>'顺丰快递','ZT'=>'中通快递']; return $get_data[$value]; } public function getPayTimeAttr($value, $data){ return date('Y-m-d h:i:s', $value); } 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']]; } ~~~ 这几个获取器都比较简单,都是常用数据转换。 * * * * * 下面的源码是修改器 ~~~ 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 ; } ~~~ 其中 setGuidAttr 使用model基类的create_uuid方法创造guid,而setOrderNoAttr是生产不重复的订单号,生成方法依然使用了基类的方法。这里使用 do while循环进行了一次唯一性过滤(当数值存在,重新获取) >[danger] 需要注意的是,为了防止订单号的重复,这里使用一次查库过滤,虽然重复的几率低,但是这种类型的值进行一次查库还是有必要的。 * * * * * 下面这个例子是是分页搜索的list列表,这里附加了字段不存在的cover_info的获取器, ~~~ /** * 获取订单列表 含append用法 * Power by Mikkle * QQ:776329498 * @param array $map * @param string $order * @param int $limit * @param int $page * @return array */ public function getOrderList($map=[],$order = 'id desc',$limit=8,$page=1){ $field='order_no,order_num,amount,distribute,create_time,is_pay,send_state,order_state'; $map['status']=1; $data=$this->where($map)->field($field) ->limit($limit) ->page($page) ->order($order)->select(); $re=[]; foreach($data as $order){ $re[]= $order->append(['cover_info'])->toArray(); } return $re; } ~~~ >[danger] 注意:模型中使用select返回的是多个对象的数组,对象中的获取器只有在单个对象toArray才会全部生效, $re=[]; foreach($data as $order){ $re[]= $order->append(['cover_info'])->toArray(); } return $re; 所以在这个获取器最后加入foreach循环 * * * * * 下面这个例子是订单详情 ~~~ /** * 订单详情 * Power by Mikkle * QQ:776329498 * @param array $map * @return array|bool|false|\PDOStatement|string|Model */ public function getOrderInfo($map=[]){ if (!$map) return false; $field = 'order_no,amount,distribute,order_desc,consignee_name,consignee_mobile,consignee_address,send_state,is_pay,is_comment,order_state,create_time'; $data=$this->where($map)->field($field)->find(); if (!$data) return false; //$data['cart_list']=$data->hasManyThrough('VGuidAll','OrdersAccess','order_no','my_guid','order_no')->select(); $data['cart_list']=$this->getOrderAccessList($data['order_no']); return $data; } /** * 订单简要信息 * Power by Mikkle * QQ:776329498 * @param $order_no * @return array|bool|false|\PDOStatement|string|Model */ public function getOrderSimpleInfo($order_no){ if (!$order_no) return false; $map['order_no']=$order_no; $field = 'order_no,amount,distribute,order_desc,consignee_name,consignee_mobile,consignee_address,create_time'; $data=$this->where($map)->field($field)->find(); if (!$data) return false; return $data; } /* * 关联 */ public function orderAccess(){ $this->hasMany('OrdersAccess','order_no','order_no'); } /** * 视图查询 * Power by Mikkle * QQ:776329498 * @param $order_no * @return false|\PDOStatement|string|\think\Collection */ public function getOrderAccessList($order_no){ return Db::view('my_orders_access','id,order_no,my_guid,my_num,my_price,is_comment') ->view('my_guid_all','my_name,my_type,my_price,my_pic','my_orders_access.my_guid=my_guid_all.my_guid') ->view('my_common_picture','path','my_common_picture.id=my_guid_all.my_pic') ->where('order_no',$order_no) ->cache('OrderList_'.$order_no) ->select(); } ~~~ >[danger] 在getOrderInfo方法中,比较复杂在初期写的时候使用了关联,后期修改会使用单独的方法getOrderAccessList > $data['cart_list']=$this->getOrderAccessList($data['order_no']); > 在方法getOrderAccessList中使用了视图view的方法,还使用了缓存(订单商品列表是禁止修改的,所以这里为了加快查询速度使用了缓存) > PS:其实实现的方法很多,商品详情列表使用获取器也是可以完成的,大家也可以想一下。 * * * * * 下面这个实例是Model的数据库的关联和事务操作 ~~~ try{ $this->startTrans(); $this->data($order_data)->isUpdate(false)->save(); $new_order = $this->order_no; if (!is_numeric($new_order)) throw new \Exception("商品订单添加失败"); $this->hasMany('OrdersAccess', 'order_no', 'order_no')->saveAll($data_order); $this->commit(); return ['code' => '1001', 'msg' => '商品订单添加成功', 'data' => ['order_no' => $new_order, 'cart_list' => $data_order]]; }catch (\Exception $e){ $this->rollback(); return ['code'=>'1008','msg'=>'商品订单添加失败','data']; } ~~~ 注意:数据只要涉及多表一致性操作,必须要开启数据库事务操作 * 更多model示例请见附件4