丰富 Eloquent ORM 的 where 查询条件的解析场景

Posted big_cat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了丰富 Eloquent ORM 的 where 查询条件的解析场景相关的知识,希望对你有一定的参考价值。

个人感觉 Eloquent ORMwhere 条件解析场景并不是那么的丰富,很多条件的拼装都需要引入额外的 orWhere, whereNotIn, whereBetween, whereNotBetween 来辅助完成。这样在做一些抽象的底层查询方法时,不是很友好,上层传递的查询条件是不确定的,如果能灵活的解析各种混合式的查询条件(用数组的方式描述),使用起来会更高效灵活些。

/**
 * 渲染复杂的 where 查询条件
 * @param Builder $query
 * @param         $conditions
 */
public static function renderWhereMixedEloquent(Builder $query, $conditions)
{
    $lastEl = end($conditions);
    reset($conditions);
    if (is_string($lastEl) && ((\'or\' == $lastEl || \'and\' == $lastEl))) {
        $logic = $lastEl;
        array_pop($conditions);
    } else {
        $logic = \'and\';
    }
    $conditionsKeys     = array_keys($conditions);
    $conditionsKeyFirst = $conditionsKeys[0];

    if (is_numeric($conditionsKeyFirst)) {
        if (is_array($conditions[$conditionsKeyFirst])) {
            if (\'or\' == $logic) {
                $query->where(function (Builder $query) use ($conditions) {
                    foreach ($conditions as $conditionsSub) {
                        $query->orWhere(function (Builder $query) use ($conditionsSub) {
                            static::renderWhereMixedEloquent($query, $conditionsSub);
                        });
                    }
                });
            } else {
                $query->where(function (Builder $query) use ($conditions) {
                    foreach ($conditions as $conditionsSub) {
                        $query->where(function (Builder $query) use ($conditionsSub) {
                            static::renderWhereMixedEloquent($query, $conditionsSub);
                        });
                    }
                });
            }
        } else {
            $operator = $conditions[1];
            switch ($operator) {
                case \'in\':
                    $query->whereIn($conditions[0], $conditions[2], $logic);
                    break;
                case \'between\':
                    $query->whereBetween($conditions[0], $conditions[2], $logic);
                    break;
                case \'not in\':
                    $query->whereIn($conditions[0], $conditions[2], $logic, true);
                    break;
                case \'not between\':
                    $query->whereBetween($conditions[0], $conditions[2], $logic, true);
                    break;
                default:
                    $query->where(...$conditions);
            }
        }
    } else {
        $query->where(function (Builder $query) use ($logic, $conditions) {
            if (\'and\' == $logic) {
                foreach ($conditions as $col => $val) {
                    $query->where([$col => $val]);
                }
            } else {
                foreach ($conditions as $col => $val) {
                    $query->orWhere([$col => $val]);
                }
            }
        });
    }
}

使用示例

简单的and条件

$conditions = [
    \'name\' => \'lily\',
    \'sex\'   => \'f\',
];
$conditions = [
    \'name\' => \'lily\',
    \'sex\'   => [\'f\', \'m\'],
];

简单的or条件

$conditions = [
    \'name\' => \'lily\',
    \'sex\'   => [\'f\', \'m\'],
    \'or\'
];

复杂的and/or查询

$conditions = [
    [
        [\'id\', \'>\', 5],
        [\'hobby\', \'in\', [\'football\', \'swimming\']],
        [\'created_at\', \'between\', [strtotime(\'2020-05-20 10:38:41\'), strtotime(\'2021-05-25 10:39:41\')]],
    ],
    [
        [\'id\', \'>\', 5],
        [\'hobby\', \'in\', [\'football\', \'swimming\']],
        [\'created_at\', \'between\', [strtotime(\'2020-05-20 10:38:41\'), strtotime(\'2021-05-25 10:39:41\')]],
    ],
];//组1 and 组2
$conditions = [
    [
        [\'id\', \'=\', 5],
        [\'hobby\', \'in\', [\'football\', \'swimming\']],
        [\'created_at\', \'between\', [strtotime(\'2020-05-20 10:38:41\'), strtotime(\'2021-05-25 10:39:41\')]],
        \'or\'//组1的内部做 or
    ],
    [
        [\'id\', \'>\', 5],
        [\'hobby\', \'not in\', [\'football\', \'swimming\']],
        [\'created_at\', \'not between\', [strtotime(\'2020-05-20 10:38:41\'), strtotime(\'2021-05-25 10:39:41\')]],
    ],
    \'or\',//组1 or 组2
];
$conditions = [
    \'sex\' => [\'f\', \'m\'],//没问题,只要表达式的语义正确,只要你头不晕,就能混拼,
    [\'name\', \'=\', \'test\'],
    [
        [\'id\', \'>\', 5],
        [\'hobby\', \'in\', [\'football\', \'swimming\']],
        [\'created_at\', \'between\', [strtotime(\'2020-05-20 10:38:41\'), strtotime(\'2021-05-25 10:39:41\')]],
        \'or\'//组1的内部做 or
    ],
    [
        [\'id\', \'>\', 5],
        [\'hobby\', \'in\', [\'football\', \'swimming\']],
        [\'created_at\', \'between\', [strtotime(\'2020-05-20 10:38:41\'), strtotime(\'2021-05-25 10:39:41\')]],
    ],
    \'or\',//组1 or 组2
];

使用实例

// < 8.0
$query = User::select("*");//主要是拿到 Builder 对象
// $query 是对象 引用传值
User::renderWhereMixedEloquent($query, $conditions);
$query->get();

// 8.0
$query = User::query();
// $query 是对象 引用传值
User::renderWhereMixedEloquent($query, $conditions);
$query->get();

以上是关于丰富 Eloquent ORM 的 where 查询条件的解析场景的主要内容,如果未能解决你的问题,请参考以下文章

Eloquent ORM ->where 和 ->save

在 Eloquent ORM 中左加入 Where

Laravel Eloquent ORM 中的 join()->where()

Laravel Eloquent ORM 的本地作用域

PHP笔记-laravel框架中Eloquent ORM实现增删改查

Lavavel笔记 Eloquent ORM分页源码分析