callable 字段名格式化回调,如 fn($f)=>snake_case($f) * - 'postFormatter' => callable 结果级加工回调,接收整个数组并返回 * * @return array 转换并加工后的纯 PHP 数组 */ protected function transformData( mixed $rawData, ?callable $postFormatter = null, ?callable $fieldFormatter = null ): array { try { $fieldFormatter = $fieldFormatter ?: fn($field) => $field; if ($rawData instanceof LengthAwarePaginator) { $arr = $this->formatPaginated($rawData, $postFormatter, $fieldFormatter); } elseif ($rawData instanceof Model) { $arr = $this->formatModel($rawData, $fieldFormatter); } elseif ($rawData instanceof Collection) { $arr = $this->formatCollection($rawData, $fieldFormatter); } elseif (is_array($rawData)) { $arr = $this->formatArray($rawData, $fieldFormatter); } else { $arr = (array)$rawData; } if (is_callable($postFormatter)) { $arr = $postFormatter($arr); } return $arr; } catch (\Throwable $e) { return [ 'error' => true, 'message' => $e->getMessage(), // 'message' => $e->getMessage()."\n".$e->getLine()."\n".$e->getFile(), 'code' => $e->getCode(), ]; } } /** * 格式化分页数据:转换每条记录 * * @param LengthAwarePaginator $p * @param callable $fmt * @return array{records: array, total: int, current: int, size: int} */ protected function formatPaginated( LengthAwarePaginator $p, ?callable $postFormatter, callable $fmt ): array { $records = $p->getCollection() ->map(fn($item) => $this->transformData($item, $postFormatter, $fmt)) ->toArray(); return [ 'records' => $records, 'total' => $p->total(), 'current' => $p->currentPage(), 'size' => $p->perPage(), ]; } /** * 格式化 Eloquent 模型:主表属性 + 关联递归 * * @param Model $model * @param callable $fmt * @return array */ protected function formatModel( Model $model, callable $fmt ): array { $out = []; // 1) 主表字段 foreach ($model->getAttributes() as $key => $value) { $out[$fmt($key)] = $value; } // 2) 关联递归 foreach ($model->getRelations() as $rel => $relData) { if ($relData instanceof Model) { $out[$rel] = $this->formatModel($relData, $fmt); } elseif ($relData instanceof Collection) { $out[$rel] = $relData ->map(fn($item) => $this->transformData($item, null, $fmt)) ->toArray(); } else { $out[$rel] = $relData; } } return $out; } /** * 格式化集合数据:对每个元素递归调用 transformData * * @param Collection $c * @param callable $fmt * @return array */ protected function formatCollection( Collection $c, callable $fmt ): array { return $c ->map(fn($item) => $this->transformData($item, null, $fmt)) ->toArray(); } /** * 格式化普通数组:递归处理可能出现的模型或集合 * * @param array $arr * @param callable $fmt * @return array */ protected function formatArray( array $arr, callable $fmt ): array { return array_map(function($item) use ($fmt) { if (is_array($item) || $item instanceof Model || $item instanceof Collection || $item instanceof LengthAwarePaginator ) { return $this->transformData($item, null, $fmt); } return $item; }, $arr); } }