TP框架中加入自定义的模型搜索方法,适用于TP5.1,TP6

阅读次数: 540

  • A+
所属分类:PHP PHP 建站 语言学习

最近项目要用到TP

在使用过程中感觉在使用条件搜索功能时语法和写法有些复杂,特此自己写一个方法来实现

TP6:

需要修改的文件

vendor\topthink\think-orm\src\db\concern\WhereQuery.php

vendor\topthink\think-orm\src\db\Builder.php

WhereQuery.php中添加的方法

 /* 组装 搜索查询语句 start */
    public function whereCreate($where){
        //数组类型的 循环组装
        if(count($where) <= 0){
            return array('code'=>0,'msg'=>"查询条件错误");
        }
        $this->options['where'] = $where;
        $this->options['is_jack'] = 1;
        return $this;
    }
    /* 组装 搜索查询语句 end */

Builder.php 中添加的方法

    protected $comparison      = array('eq'=>'=','neq'=>'<>','gt'=>'>','egt'=>'>=','lt'=>'<','elt'=>'<=','notlike'=>'NOT LIKE','like'=>'LIKE','in'=>'IN','not in'=>'NOT IN');


 /* jack where 分析 start */
    protected function parseWhereJack($where){
        $whereStr = '';
        if(is_string($where)) {
            $whereStr = $where;
        }elseif(is_array($where)){
            if(isset($where['_op'])) {
                // 定义逻辑运算规则 例如 OR XOR AND NOT
                $operate    =   ' '.strtoupper($where['_op']).' ';
                unset($where['_op']);
            }else{
                $operate	=   ' AND ';
            }
            foreach ($where as $key=>$val){  // $where = array();
//                $whereStr .= '( ';
//                if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){
//                    $error = 'Model Error: args '.$key.' is wrong!';
//                    throw_exception($error);
//                }
//                $key = trim($key);
//                $whereStr   .= $this->parseWhereItems($this->parseKeyJack($key),$val);
//                $whereStr .= ' )'.$operate;
                $whereStrTemp = '';
                if(0===strpos($key,'_')) {
                    // 解析特殊条件表达式
//                    $whereStr   .= $this->parseThinkWhere($key,$val);
                }else{
                    // 查询字段的安全过滤
                    if(!preg_match('/^[A-Z_\|\&\-.a-z0-9]+$/',trim($key))){
                        try {
                            throw new Exception("传输的字符有问题", 0);

                        } catch (Exception $e) {
                            return json(['code'=>$e->getCode(),'msg'=>$e->getMessage()]);
                        }
                    }
                    // 多条件支持
                    // 如果 $where 的其中一个 $val 也是数组 并且包含 key _multi 则$multi为真
                    $multi = is_array($val) &&  isset($val['_multi']);

                    $key = trim($key); // 两边清空 空格及其他字符
                    if(strpos($key,'|')) { // 支持 name|title|nickname 方式定义查询字段
                        $array   =  explode('|',$key);
                        $str   = array();
                        foreach ($array as $m=>$k){
                            $v =  $multi?$val[$m]:$val;
                            $str[]   = '('.$this->parseWhereItems($this->parseKeyJack($k),$v).')';
                        }
                        $whereStrTemp .= implode(' OR ',$str);
                    }elseif(strpos($key,'&')){
                        $array   =  explode('&',$key);
                        $str   = array();
                        foreach ($array as $m=>$k){
                            $v =  $multi?$val[$m]:$val;
                            $str[]   = '('.$this->parseWhereItems($this->parseKeyJack($k),$v).')';
                        }
                        $whereStrTemp .= implode(' AND ',$str);
                    }else{
                        $whereStrTemp   .= $this->parseWhereItems($this->parseKeyJack($key),$val);
                    }
                }
                if(!empty($whereStrTemp)) {
                    $whereStr .= '( '.$whereStrTemp.' )'.$operate;
                }
            }
            $whereStr = substr($whereStr,0,-strlen($operate));
        }
        // p($whereStr);
        // die();
        return empty($whereStr)?'':' WHERE '.$whereStr;
    }
    /* jack where 分析 end */

    // where子单元分析
    protected function parseWhereItems($key,$val) {
        $whereStr = '';
        if(is_array($val)) {
            if(is_string($val[0])) {
                if(preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT|NOTLIKE|LIKE)$/i',$val[0])) { // 比较运算
                    $whereStr .= $key.' '.$this->comparison[strtolower($val[0])].' '.$this->parseValue($val[1]);
                }elseif('exp'==strtolower($val[0])){ // 使用表达式
//                    $whereStr .= ' ('.$key.' '.$val[1].') ';
                    $whereStr .= $val[1];
                }elseif(preg_match('/IN/i',$val[0])){ // IN 运算
                    if(isset($val[2]) && 'exp'==$val[2]) {
                        $whereStr .= $key.' '.strtoupper($val[0]).' '.$val[1];
                    }else{
                        if (empty($val[1])){
                            $whereStr .= $key.' '.strtoupper($val[0]).'(\'\')';
                        }elseif(is_string($val[1]) || is_numeric($val[1])) {
                            $val[1] =  explode(',',$val[1]);
                            $zone   =   implode(',',$this->parseValue($val[1]));
                            $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';
                        }elseif(is_array($val[1])){
                            $zone   =   implode(',',$this->parseValue($val[1]));
                            $whereStr .= $key.' '.strtoupper($val[0]).' ('.$zone.')';
                        }
                    }
                }elseif(preg_match('/BETWEEN/i',$val[0])){
                    $data = is_string($val[1])? explode(',',$val[1]):$val[1];
                    if($data[0] && $data[1]) {
                        $whereStr .=  ' ('.$key.' '.strtoupper($val[0]).' '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1]).' )';
                    } elseif ($data[0]) {
                        $whereStr .= $key.' '.$this->comparison['gt'].' '.$this->parseValue($data[0]);
                    } elseif ($data[1]) {
                        $whereStr .= $key.' '.$this->comparison['lt'].' '.$this->parseValue($data[1]);
                    }
                }elseif(preg_match('/TIME/i',$val[0])){
                    $data = is_string($val[1])? explode(',',$val[1]):$val[1];
                    if($data[0] && $data[1]) {
                        $whereStr .=  ' ('.$key.' BETWEEN '.$this->parseValue($data[0]).' AND '.$this->parseValue($data[1] + 86400 -1).' )';
                    } elseif ($data[0]) {
                        $whereStr .= $key.' '.$this->comparison['gt'].' '.$this->parseValue($data[0]);
                    } elseif ($data[1]) {
                        $whereStr .= $key.' '.$this->comparison['lt'].' '.$this->parseValue($data[1] + 86400);
                    }
                }else{
                    $error = 'Model Error: args '.$val[0].' is error!';
                    throw new Exception($error,0);
                }
            }else {
                $count = count($val);
                if(in_array(strtoupper(trim($val[$count-1])),array('AND','OR','XOR'))) {
                    $rule = strtoupper(trim($val[$count-1]));
                    $count   =  $count -1;
                }else{
                    $rule = 'AND';
                }
                for($i=0;$i<$count;$i++) {
                    if (is_array($val[$i])){
                        if (is_array($val[$i][1])){
                            $data = implode(',',$val[$i][1]);
                        }else{
                            $data = $val[$i][1];
                        }
                    }else{
                        $data = $val[$i];
                    }
                    if('exp'==strtolower($val[$i][0])) {
                        $whereStr .= '('.$key.' '.$data.') '.$rule.' ';
                    }else{
                        $op = is_array($val[$i])?$this->comparison[strtolower($val[$i][0])]:'=';
                        if(preg_match('/IN/i',$op)){
                            $whereStr .= '('.$key.' '.$op.' ('.$this->parseValue($data).')) '.$rule.' ';
                        }else{
                            $whereStr .= '('.$key.' '.$op.' '.$this->parseValue($data).') '.$rule.' ';
                        }

                    }
                }
                $whereStr = substr($whereStr,0,-4);
            }
        }else {
            $whereStr .= $key.' = '.$this->parseValue($val);
        }
        return $whereStr;
    }

    protected function parseValue($value) {
        if(is_string($value) || is_numeric($value)) {
            $value = '\''.$this->escapeString($value).'\'';
        }elseif(isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp'){
            $value   =  $value[1];
        }elseif(is_array($value)) {
            $value   =  array_map(array($this, 'parseValue'),$value);
        }elseif(is_null($value)){
            $value   =  'NULL';
        }
        return $value;
    }

    public function escapeString($str) {
        $str = addslashes(stripslashes($str));//重新加斜线,防止从数据库直接读取出错
        return $str;
    }
    protected function parseKeyJack(&$key) {
        return $key;
    }

TP5.1对应修改文件

thinkphp\library\think\db\Query.php

thinkphp\library\think\db\Builder.php

内容与上边是一样的

用法

1. 某字段等于某个值

$model = new ShopGoods();//模型
$where['goods_name'] = "螺栓";//条件
$result = $model->whereCreate($where)->select();
p($result);

2.某字段包含某个值

$model = new ShopGoods();//模型
$search = "螺栓";
$where['goods_name'] = array("like","%{$search}%");
$result = $model->whereCreate($where)->select();
p($result);

3.某字段在某个区间

$model = new ShopGoods();//模型
$start = 1;
$end = 2;
$where['add_time'] = array("between",array($start,$end));
$result = $model->whereCreate($where)->select();
p($result);

4.大于小于 等于 都是类似的

$model = new ShopGoods();//模型
$value = 1;
$where['add_time'] = array("gt",$value);
$result = $model->whereCreate($where)->select();
p($result);

5.万能条件写法

搜索 (产品名称包含 螺栓 或者 分类ID小于20) 并且 产品状态是上架中的 数据 如下
$model = new ShopGoods();//模型
$where['goods_name|class_id&goods_state'] = array(
    array('like',"%螺栓%"),
    array('lt',20),
    array('eq',1)
);

$result = $model->whereCreate($where)->select();
p($result);

TP模型的用法记录

1.关联统计

情景:

主表id 子表job_id 关联主表的ID

主表模型中添加方法

// 关联:消息数量
public function MsgCount(){

    //一对一
    // return $this->hasOne(JobMsgStaffConsult::class,'msg_id','id')->bind([
    //     "consult_id"=>"id"
    // ]);

    //一对多
    return $this->hasMany(JobMsgStaffConsult::class,'msg_id','id');
}

调用方法

->with(['MsgCount'])//直接查询出来数据
->with(['MsgCount'=>function($data){
     $data->field("id,staff_id,msg_id");
}])//限制字段
->withCount(['linkCount'=>'consult_num'],false) //统计数量
  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: