135 lines
4.4 KiB
PHP
135 lines
4.4 KiB
PHP
<?php
|
|
|
|
namespace app\common\traits;
|
|
|
|
use Illuminate\Pagination\LengthAwarePaginator;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Support\Collection;
|
|
|
|
trait DataTransformer
|
|
{
|
|
/**
|
|
* 核心方法:对任意数据进行转换并返回数组
|
|
*
|
|
* @param mixed $rawData 原始数据,可为 Paginator / Model / Collection / array 等
|
|
* @param callable|null $postProcessor 可选的后置处理回调,接受处理完的数组再返回新的数组
|
|
* @param callable|null $fieldFormatter 可选的字段命名转换回调,如 snake_case
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function transformData(
|
|
mixed $rawData,
|
|
?callable $postProcessor = null,
|
|
?callable $fieldFormatter = null
|
|
): array {
|
|
try {
|
|
$fieldFormatter = $fieldFormatter ?: fn($field) => $field;
|
|
|
|
if ($rawData instanceof LengthAwarePaginator) {
|
|
$formatted = $this->formatPaginated($rawData, $postProcessor, $fieldFormatter);
|
|
} elseif ($rawData instanceof Model) {
|
|
$formatted = $this->formatModel($rawData, $fieldFormatter);
|
|
} elseif ($rawData instanceof Collection) {
|
|
$formatted = $this->formatCollection($rawData, $fieldFormatter);
|
|
} elseif (is_array($rawData)) {
|
|
$formatted = $this->formatArray($rawData, $fieldFormatter);
|
|
} else {
|
|
$formatted = (array) $rawData;
|
|
}
|
|
|
|
if (is_callable($postProcessor)) {
|
|
$formatted = $postProcessor($formatted);
|
|
}
|
|
|
|
return $formatted;
|
|
} catch (\Throwable $e) {
|
|
return [
|
|
'error' => true,
|
|
'message' => $e->getMessage(),
|
|
'code' => $e->getCode(),
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 格式化分页数据:将每条记录也进行 transformData 递归处理
|
|
*
|
|
* @param LengthAwarePaginator $paginator
|
|
* @param callable|null $postProcessor
|
|
* @param callable $fieldFormatter
|
|
* @return array
|
|
*/
|
|
protected function formatPaginated(
|
|
LengthAwarePaginator $paginator,
|
|
?callable $postProcessor,
|
|
callable $fieldFormatter
|
|
): array {
|
|
$list = $paginator->getCollection()->map(function ($item) use ($postProcessor, $fieldFormatter) {
|
|
return $this->transformData($item, $postProcessor, $fieldFormatter);
|
|
})->toArray();
|
|
|
|
return [
|
|
'records' => $list,
|
|
'total' => $paginator->total(),
|
|
'current' => $paginator->currentPage(),
|
|
'size' => $paginator->perPage()
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 格式化 Eloquent 模型:递归嵌套关联
|
|
*
|
|
* @param Model $model
|
|
* @param callable $fieldFormatter
|
|
* @return array
|
|
*/
|
|
protected function formatModel(Model $model, callable $fieldFormatter): array
|
|
{
|
|
$formatted = [];
|
|
|
|
// 主表字段
|
|
foreach ($model->getAttributes() as $key => $value) {
|
|
$formatted[$fieldFormatter($key)] = $value;
|
|
}
|
|
|
|
// 关联数据,递归嵌套
|
|
foreach ($model->getRelations() as $relation => $relationData) {
|
|
if ($relationData instanceof Model) {
|
|
// 单个关联模型
|
|
$formatted[$relation] = $this->formatModel($relationData, $fieldFormatter);
|
|
} elseif ($relationData instanceof Collection) {
|
|
// 关联集合
|
|
$formatted[$relation] = $relationData
|
|
->map(fn($item) => $this->transformData($item, null, $fieldFormatter))
|
|
->toArray();
|
|
}
|
|
}
|
|
|
|
return $formatted;
|
|
}
|
|
|
|
/**
|
|
* 格式化集合
|
|
*
|
|
* @param Collection $collection
|
|
* @param callable $fieldFormatter
|
|
* @return array
|
|
*/
|
|
protected function formatCollection(Collection $collection, callable $fieldFormatter): array
|
|
{
|
|
return $collection->map(fn($item) => $this->transformData($item, null, $fieldFormatter))
|
|
->toArray();
|
|
}
|
|
|
|
/**
|
|
* 格式化普通数组
|
|
*
|
|
* @param array $array
|
|
* @param callable $fieldFormatter
|
|
* @return array
|
|
*/
|
|
protected function formatArray(array $array, callable $fieldFormatter): array
|
|
{
|
|
return array_map(fn($item) => $this->transformData($item, null, $fieldFormatter), $array);
|
|
}
|
|
} |