如何使用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
相关产品推荐
相关产品推荐

