[TOC] ## 数据表关联,可以查询范围连用 ### 一对一关联 ```php class MediaPublicModel extends RelationModel{ protected $_link=[ 'read_adv_media'=>[ 'mapping_type'=>self::HAS_ONE, 'foreign_key'=>'mid', 'mapping_fields'=>'id,name,wechat', 'as_fields'=>'wechat:wechat_username', //把关联的字段值映射成数据对象中的某个字段 //'class_name'=>'read_adv_media', //驼峰或者下滑线都可以都可以 //'condition'=>"name = cpj'", //复杂查询条件,用string ] ]; } //1. 直接关联查选 $res = D("MediaPublic")->relation('read_adv_media')->where(['id'=>12306])->find(); //2. 选查询在关联 $mp = D("MediaPublic")->where(['id'=>12306]); var_dump($mp->find()); var_dump($mp->relationGet('read_adv_media')); // 使用relationGet 在find后输出关联的read_adv_media中的字段 ``` ### 一对多关联 ``` class BookModel extends RelationModel{ protected $_link=[ 'book_episodes'=>[ //关联表名 'mapping_type'=>self::HAS_MANY, 'foreign_key'=>'bid', 'mapping_fields'=>'ji_no,title', 'mapping_limit'=>'20', 'mapping_order'=>'ji_no asc' //'parent_key'=>'id', 主表id, //'condition'=>'', 复杂查询条件 ] } ``` ### 关联添加 ``` $mp = D("MediaPublic"); $data['fans']='130001'; $data['name']='cpj130001'; $data['read_adv_media']=[ 'pv'=>'1000', ]; $mp->relation("read_adv_media")->add($data); //relation 的name只能是对应的link的值 ``` ### 关联更新 > **关联更新必须是主表的主键id 为子表的关联id,否则更新无效** ``` $mp = D("MediaPublic")->where(['id'=>'28805']); $data['licai']='0'; $data['read_adv_media']=[ 'pv'=>'1002', 'url'=>'http://www.baiducki.com', ]; $mp->relation("read_adv_media")->save($data); //relation 的name只能是对应的link的值 ``` ### 关联更新的规则 HAS_ONE: 关联数据的更新直接赋值 HAS_MANY: 的关联数据如果传入主键的值 则表示更新 否则就表示新增 MANY_TO_MANY: 的数据更新是删除之前的数据后重新写入 ### 关联删除 `$result = $User->relation("Profile")->delete("3");` ## 模型的scope 场景设置 ``` namespace Home\Model; use Think\Model; class NewsModel extends Model { protected $_scope = array( 'normal'=>array( 'where'=>array('status'=>1), ), 'latest'=>array( 'order'=>'create_time DESC', 'limit'=>10, ), // 默认的命名范围 'default'=>array( 'where'=>array('status'=>1), 'limit'=>10, ), ); } //调用 D("News")->scope('normal')->select(); //混合使用 $Model->scope('normal')->limit(8)->order('id desc')->select(); //支持属性 //where , field , order , limit , page , having , group , lock , distinct , cache\ //支持连贯调用 $Model->scope('normal')->scope('latest')->select(); $Model->scope('normal,latest')->select(); //简便操作,若冲突,则前面覆盖后面 //默认调用 $Model->scope()->select(); ``` ## 用视图模型进行多表查询 ViewModel 关联表 ``` 在模块下的Model目录 class ChannelViewModel extends ViewModel{ protected $viewFields=array( 'Channel'=>array('id','channel_name','token','_type'=>'RIGHT'), //right对应下表的 'Member'=>array('name','idcard','_on'=>'Channel.id=Member.channel_id') ); } 在控制器中调用 D("ChannelView")->where(array('id' => 47))->select() 以普通视图一样 ``` ## 数据库操作 ### 添加操作 ```php if(!$channel->create($data)){ $this->error($channel->getError()); }else{ $channel->create_time =time(); $channel->add(); } ``` ### 更新操作 1. 方法一,不使用create 方法 ```php $channelData =D("Channel")->where(array('id'=>1)); //判断是否有值 if(!$channelData->find()){ $this->error(暂无数据); } $channel->status=1; //没有报错后继续赋值 $channel->save() ``` 2. 方法二 ``` $channel = D("Channel"); //直接在参数中写入主键,则视为更新 $data=array( 'id'=>1, 'create_time'=>111, 'update_time'=>1112, 'token'=>'', ); if(!$channel->create($data)){ $this->error($channel->getError()); }else{ $channel->save(); } ``` ### 查询操作 ```php //符合条件的一个值 D("test")->where(['age'=>11])->getField('id'); //return String 2 //查询符合条件的多个值,第二个参数加true D("test")->where(['age'=>11])->getField('id',true); //return array ( 0 => '2', 1 => '3') //通过条件查询整条数据 $data=M('Test')->getByName('白俊遥'); //通过条件查询字段 M('read_adv_media')->getFieldById($id,'aid'); //return string 12 ``` ### 自动验证 model 模型中 ``` protected $_validate = array( ['phone','require','手机号必填',self::EXISTS_VALIDATE,], //self::EXISTS_VALIDATE =0 表单存在字段则验证 ['phone',PHONE_REGEX,'手机号格式错误',self::EXISTS_VALIDATE,'regex'], ['phone','','手机号已被注册',self::EXISTS_VALIDATE,'unique'], ['password','require','密码必填',self::EXISTS_VALIDATE], ['password','3,13','长度过短',self::EXISTS_VALIDATE,'length'], ['password_2','password','密码不一致',self::EXISTS_VALIDATE,'confirm'], //confirm 表示password_2字段与password字段 是否相等 ['check','123','与check1不相等',self::EXISTS_VALIDATE,'equal'], //equal 表示check字段是否等于 123 ['tel','usecall','tel不通过',self::EXISTS_VALIDATE,'callback','0575'], //第六个参数 就是回调函数的第一个参数可以是数组 ); //只能进行布尔判断,不能重新赋值 protected function usecall($pre){ $user = D("user")->where(['user'=>'demo'])->find(); if($user){ return true; }else{ return false; } } //验证后的操作 protected $_auto = [ ['ip','2',self::MODEL_UPDATE], //更新时为1 ['ip','1',self::MODEL_INSERT], //添加时为2 ['password', 'md5_pwd', self::MODEL_BOTH, 'callback'] ]; //默认参数就是字段的参数 public function md5_pwd($pas){ return md5($pas."abc"); } ``` 控制器中 ``` $member = D("Member"); //注意有 ! 号 if (!$member->create($this->postData)){ // 如果为$_POST提交则不选在create中传入数据 $this->error(303,$member->getError()); } $member->add(); ``` ## 设置数据库缓存 在`config.php`中配置 `DATA_CACHE_TIME和DATA_CACHE_TYPE` ``` //不带标识符 M('User')->where('id=5')->cache(true)->find(); //不带标识符,带过期时间 M('User')->where('id=5')->cache(true,60)->find(); /带标识符 M('User')->cache('key',60)->find(); ``` ## 指定调用的模型 ``` D('Common/Dept'); D('Common/Dept','Logic'); //调用逻辑层 目录结构为 Common/Logic/DeptLogic.class.php ``` ## 数据库的前置,后置操作 > 注意: 所有增改查的操作,数组必定是过滤了非字段的key > 所有的option 选项必定包含了 表明和模型名 > 批量添加不触发前置,后置操作 1. 前置类型 ``` _betore_write(&$data) //包括新增和添加 _before_delete($options) //$data 需要更新的数组 _before_insert(&$data, $options) _before_update(&$data, $options) //$data 需要更新的数组 ``` 2. 后置操作 ``` _after_db() //切换数据库后,无参数 _after_find(&$result, $options) _after_select(&$resultSet, $options) //select 是获取所有的值的结果 _after_delete($data, $options) //$data : 主键的where 值 ,以下接口相同 _after_insert($data, $options) _after_update($data, $options) ```