博客 / 詳情

返回

Laravel Eloquent 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();
user avatar qingliao 頭像 lofanmi 頭像
2 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.