TP5如何实现yii2的filterWhere


为什么要filterWhere

使用TP5开发时,当遇到获取数据库数据,需要筛选前端传输的筛选项时,你的代码会不会类似下面这样?

$searchId = Request::get('id', null);                               //用户ID
$searchName = Request::get('name', '');                             //用户名称
$searchSexArr = Request::get('sex', [0, 1]);                        //0-男 1-女
$searchStartTime = Request::get('start_time', date('Y-m-d H:i:s')); //用户注册起始时间

$query = UserModel::field(['id', 'name', 'sex', 'create_time']);

if (!empty($searchId)) {
    $query->where('id', $searchId);
}

if (!empty($searchName)) {
    $query->where('name', 'like', "%$searchName%");
}

if (!empty($searchSexArr)) {
    $query->where('sex', 'in', $searchSexArr);
}

if (!empty($searchStartTime)) {
    $query->where('create_time', '>=', $searchStartTime);
}

$query->select();

或者

$whereMap = [];
$searchId = Request::get('id', null);                               //用户ID
$searchName = Request::get('name', '');                    			//用户名称
$searchSexArr = Request::get('sex', [0, 1]);                		//0-男 1-女
$searchStartTime = Request::get('start_time', date('Y-m-d H:i:s')); //用户注册起始时间

if (!empty($searchId)) {
    $whereMap = ['id', $searchId];
}

if (!empty($searchName)) {
    $whereMap = ['name', 'like', "%$searchName%"];
}

if (!empty($searchSexArr)) {
    $whereMap = ['sex', 'in', $searchSexArr];
}

if (!empty($searchStartTime)) {
    $whereMap = ['create_time', '>=', $searchStartTime];
}

UserModel::field(['id', 'name', 'sex', 'create_time'])
    ->where($whereMap)
    ->select();

可是,如果使用Yii2来处理同样的功能,完全可以使用filterWhere方法来处理

$searchId = $this->getRequest()->get('id', null);                     			//用户ID
$searchName = $this->getRequest()->get('name', '');                    			//用户名称
$searchSexArr = $this->getRequest()->get('sex', [0, 1]);                		//0-男 1-女
$searchStartTime = $this->getRequest()->get('start_time', date('Y-m-d H:i:s')); //用户注册起始时间

UserModel::find()
    ->filterWhere(['id' => $searchId])
    ->andFilterWhere(['like', 'name', $searchName])
    ->andFilterWhere(['in', 'sex', $searchSexArr])
    ->andFilterWhere(['>=', 'create_time', $searchStartTime])
    ->all();

使用filterWhere这代码也太简洁、太好看了吧!不行,给TP也安排个。



创建filterWhere的基本设计思路

TP5中,并没有支持filterWhere方法,那么要自己去框架内部实现这个方法?可以,但也强烈不推荐。原因如下:

  1. 改动了第三方依赖,那么后续第三方依赖更新,将会存在功能错乱及重复的风险
  2. 需要深入了解TP5内部逻辑,才能尽可能好的创造出该功能,耗时耗力

那么,不改动框架内部代码,要怎么样去实现呢?很简单,框架内部不改动,那么只要在基于框架创建一个属于自己的底层来改动便足够了。也就是创建一个基于think\Model类的公共底层Model(下文简称BaseModel),在其上实现自己的功能即可。

这里利用了TP5的查询范围调用方式,感兴趣的同学可以去看看



完整代码和使用示例

由于本人懒癌发作 为了看官大人能够快速判断本文是否为您所需要使用的内容,下面直接抛出最终结果。如果对该方法的使用存在兴趣或疑问,也非常欢迎在屏幕下方留言评论。


1. 创建BaseModel文件,完成scopeFilterWhere方法

创建BaseModel类文件,只要其他的Model层继承它,那么便能够正常的使用filterWhere方法了

# 根据自己需要,将BaseModel文件放到自己业务需要的地方,修改命名空间

<?php

namespace app\common\model;

use think\db\Query;
use think\Model;

/**
 * @method $this filterWhere(mixed $field, string $op = null, mixed $condition = null) static 筛选不为空的where条件
 */
class BaseModel extends Model
{
   public function scopeFilterWhere(Query $query, $field, $op = null, $condition = null)
   {

       if (is_null(params_filter($field))) {
           return;
       }

       if ($op !== null
           && is_null(params_filter($op))) {
           return;
       }

       if ($condition !== null
           && is_null(params_filter($condition))) {
           return;
       }

       $query->where($field, $op, $condition);
   }
}

2. 补充一下params_filter函数

params_filter函数其实改造自array_filter_recursive函数,是用来过滤掉多维数组里面所有空的内容,不过此处的话需要特别处理:将%也过滤掉,为的是防止模糊查询的%语句没有成功过滤。

# 可以将本函数放在公共函数文件中,或者放在类中也是没问题的,只是注意上文调用可能变化

function params_filter(&$fieldOps)
{
   if (!is_array($fieldOps)) {
       if (is_string($fieldOps)
         && trim($fieldOps, " \t\n\r\0\x0B%") === ''
        ) {
         return null;
     }
       return $fieldOps;
   }

   foreach ($fieldOps as $k => $v) {
       if (is_null(params_filter($v))) {
           unset($fieldOps[$k]);
       }
   }

   $fieldOps = $fieldOps ?: null;
   return $fieldOps;
}

3. 创建业务Model文件,继承BaseModel

这一步建议所有业务Model都是继承BaseModel,要搞特殊也当然ok,根据自己需要即可

# 根据自己需要,将Model文件放到自己业务需要的地方,但一定要继承刚才创建的BaseModel

<?php

namespace app\common\model;

/**
 * @property int $id
 * @property string name
 * @property integer sex
 * @property string create_time
 */
class UserModel extends BaseModel
{
    protected $name = 'user';
    protected $pk = 'id';
}

4. 调用业务Model的filterWhere方法(使用示例)

下面直接给几个正常实现filterWhere的示例(由于TP5.0和TP5.1中where方法存在调整,下面示例以TP5.1为准)


示例一:表达式查询(TP5.0 & TP5.1)

# 下面代码实现查询 name、sex
$searchId = Request::get('id', null);                     //用户ID
$searchName = Request::get('name', '');                    //用户名称
$searchSexArr = Request::get('sex', [0, 1]);                //0-男 1-女
$searchStartTime = Request::get('start_time', date('Y-m-d H:i:s')); //用户注册起始时间

UserModel::field(['id', 'name', 'sex', 'create_time'])
    ->filterWhere('id', $searchId)
    ->filterWhere('name', 'like', "%$searchName%")
    ->filterWhere('sex', 'in', $searchSexArr)
    ->filterWhere('create_time', '>=', $searchStartTime)
    ->select();

注意:如果查询值为0的话,是不会过滤的,所以上面获取id时的默认值不为0,避免错误筛选


示例二:数组条件普通查询(TP5.0 & TP5.1)

$whereMap['id'] = Request::get('id', null);           //用户ID
$whereMap['sex'] = Request::get('sex', [0, 1]);        //0-男 1-女

UserModel::field(['id', 'name', 'sex', 'create_time'])
    ->filterWhere($whereMap)
    ->select();

示例三:数组条件表达式查询(TP5.1)

$whereMap[] = ['name', 'like', '%' . Request::get('name', '') . '%'];            //用户名称
$whereMap[] = ['sex', 'in', Request::get('sex', [0, 1])];                    //0-男 1-女
$whereMap[] = ['create_time', '>=', Request::get('start_time', date('Y-m-d H:i:s'))];  //用户注册起始时间

UserModel::field(['id', 'name', 'sex', 'create_time'])
    ->filterWhere($whereMap)
    ->select();



附录

测试用表结构及数据

CREATE TABLE `user`  (
  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID',
  `name` varchar(20) NOT NULL DEFAULT '' COMMENT '用户名',
  `sex` tinyint(1) UNSIGNED NOT NULL DEFAULT 1 COMMENT '性别:0-男 1-女',
  `create_time` datetime(0) NULL DEFAULT CURRENT_TIMESTAMP(0) COMMENT '注册日期',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB COMMENT = '用户表';


INSERT INTO `user` VALUES (1, 'test1', 1, '2021-03-28 21:37:17');
INSERT INTO `user` VALUES (2, 'test2', 0, '2021-03-10 21:37:26');
INSERT INTO `user` VALUES (3, 'three', 1, '2021-03-26 21:38:04');

让编辑器识别filterWhere方法

该方法目前已经能够被正常调用了,不过phpstorm编辑器却识别这个方法不存在。嘛,怎么说实际的方法名也是scopeFilerWhere,编辑器能够基于类来判断是否存在某方法已经很智能了,可不能期待它跟xx框架功能有什么强耦合。

但是这个看起来是真的丑啊,有没有什么办法可以让编辑器识别该类存在这个方法呢?有!在类的块注释中添加下面注释即可

/**
 * @method filterWhere(mixed $field, string $op = null, mixed $condition = null) static 筛选不为空的where条件
 */
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值