You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Laravel Eloquent查询构建器复现旧MySQLi代码的输出结果

问题场景

我正在将基于MySQLi开发的遗留应用迁移至Laravel框架,需要把所有数据查询逻辑转换为Laravel适配的PDO/Eloquent实现,目前卡在结果集按指定字段为键返回的逻辑复现上。

原有遗留代码逻辑

旧代码自定义了to_array()方法,支持传入字段名作为返回数组的键:查询permissions表的ID/Name/Level/Secondary字段并按Level排序后,分别生成以ID为键的$Classes数组、以Level为键的$ClassLevels数组返回,同时内置字符串转义逻辑。
原有核心代码如下:

public static function get_permissions()
{
    $db->query('SELECT ID, Name, Level, Secondary FROM permissions ORDER BY Level');
    $Classes = $db->to_array('ID');
    $ClassLevels = $db->to_array('Level');

    return [$Classes, $ClassLevels];
}

public function to_array($Key = false, $Type = \MYSQLI_BOTH, $Escape = true)
{
    $Return = [];
    if (!is_bool($this->QueryID)) {
        dump($this->QueryID);
        while ($Row = mysqli_fetch_array($this->QueryID, $Type)) {
            if ($Escape !== false) {
                $Row = Arr::display_array($Row, $Escape);
            }
            if ($Key !== false) {
                $Return[$Row[$Key]] = $Row;
            } else {
                $Return[] = $Row;
            }
        }

        mysqli_data_seek($this->QueryID, 0);
    }
}

public static function display_array($Array, $Escape = [])
{
    foreach ($Array as $Key => $Val) {
        if ((!is_array($Escape) && $Escape == true) || !in_array($Key, $Escape)) {
            $Array[$Key] = display_str($Val);
        }
    }

    return $Array;
}

/* 输出示例
$Classes = array:8 [▼
  100 => array:4 [▼
    "ID" => 2
    "Name" => "User"
    "Level" => 100
    "Secondary" => 0
  ]
  150 => array:4 [▶]
  200 => array:4 [▶]
  201 => array:4 [▶]
  202 => array:4 [▶]
  250 => array:4 [▶]
  800 => array:4 [▶]
  1000 => array:4 [▶]
*/

当前Laravel实现进度

目前已经写了基础的查询+缓存逻辑,但不知道怎么复现旧代码按指定字段作为数组键返回结果的功能,当前代码如下:

public static function getPermissions()
{
    if (Cache::has('permissions')) {
        return Cache::get('permissions');
    }

    return Cache::rememberForever('permissions', static function () {
        return self::query()
            ->select(['ID', 'Name', 'Level', 'Secondary'])
            ->orderBy('Level')
            ->get()
            ->toArray();
    });
}
实现方案

Laravel Eloquent 集合原生支持按指定字段作为集合键的能力,不需要手动写循环遍历,直接调用集合的keyBy()方法即可实现和旧代码to_array('指定键')完全一致的效果,同时原有缓存逻辑可以简化,不需要手动判断缓存是否存在,rememberForever会自动处理缓存命中判断。
另外旧代码里的字符串转义逻辑不建议在查询层实现,Laravel的Blade模板渲染、e()辅助函数会在输出时自动处理XSS转义,提前转义存到缓存反而容易出现二次转义的问题。
最终可直接替换的代码如下,返回值结构和旧代码完全一致,上层调用无需修改:

public static function getPermissions()
{
    return Cache::rememberForever('permissions', static function () {
        // 仅查询一次数据库,避免重复开销
        $permissionList = self::query()
            ->select(['ID', 'Name', 'Level', 'Secondary'])
            ->orderBy('Level')
            ->get();
        
        // 分别按ID、Level做键名,对应旧代码的两个返回结果
        $classes = $permissionList->keyBy('ID')->toArray();
        $classLevels = $permissionList->keyBy('Level')->toArray();

        return [$classes, $classLevels];
    });
}

逻辑说明

  • 数据库仅需查询一次,比旧代码两次遍历结果集的性能更优,keyBy是Laravel集合的内置方法,底层单次遍历即可完成键名重置,无额外开销
  • keyBy('字段名')的效果完全等价于旧代码中to_array('字段名')的逻辑:将指定字段的值作为对应数据行的数组键
  • 缓存逻辑直接返回rememberForever的结果即可,无需提前调用Cache::has判断,减少冗余代码
  • 如果必须和旧代码的提前转义逻辑完全对齐,可以在转数组前通过集合的map方法批量处理字段:
    $permissionList = $permissionList->map(function ($item) {
        return [
            'ID' => $item->ID,
            'Name' => e($item->Name),
            'Level' => $item->Level,
            'Secondary' => $item->Secondary
        ];
    });
    

内容的提问来源于stack exchange,提问作者Rio

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 17:51:23