Files
fdesk/app/common/traits/DataTransformer.php
T

152 lines
4.7 KiB
PHP
Raw Normal View History

2025-07-11 15:21:00 +08:00
<?php
namespace app\common\traits;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Collection;
2025-07-18 17:32:42 +08:00
/**
* 数据转换器 Trait
* 用于将原始数据(如模型、集合、分页等)统一转换为数组格式,
* 并支持字段级与结果级的灵活后置加工。
*/
2025-07-11 15:21:00 +08:00
trait DataTransformer
{
/**
2025-07-18 17:32:42 +08:00
* 核心转换方法
2025-07-11 15:21:00 +08:00
*
2025-07-18 17:32:42 +08:00
* @param mixed $rawData 原始数据:Model、Collection、Paginator、数组等
* @param array $opts 可选配置:
* - 'fieldFormatter' => callable 字段名格式化回调,如 fn($f)=>snake_case($f)
* - 'postFormatter' => callable 结果级加工回调,接收整个数组并返回
2025-07-11 15:21:00 +08:00
*
2025-07-18 17:32:42 +08:00
* @return array 转换并加工后的纯 PHP 数组
2025-07-11 15:21:00 +08:00
*/
protected function transformData(
mixed $rawData,
2025-07-18 17:32:42 +08:00
?callable $postFormatter = null,
2025-07-11 15:21:00 +08:00
?callable $fieldFormatter = null
): array {
try {
$fieldFormatter = $fieldFormatter ?: fn($field) => $field;
if ($rawData instanceof LengthAwarePaginator) {
2025-07-18 17:32:42 +08:00
$arr = $this->formatPaginated($rawData, $postFormatter, $fieldFormatter);
2025-07-11 15:21:00 +08:00
} elseif ($rawData instanceof Model) {
2025-07-18 17:32:42 +08:00
$arr = $this->formatModel($rawData, $fieldFormatter);
2025-07-11 15:21:00 +08:00
} elseif ($rawData instanceof Collection) {
2025-07-18 17:32:42 +08:00
$arr = $this->formatCollection($rawData, $fieldFormatter);
2025-07-11 15:21:00 +08:00
} elseif (is_array($rawData)) {
2025-07-18 17:32:42 +08:00
$arr = $this->formatArray($rawData, $fieldFormatter);
2025-07-11 15:21:00 +08:00
} else {
2025-07-18 17:32:42 +08:00
$arr = (array)$rawData;
2025-07-11 15:21:00 +08:00
}
2025-07-18 17:32:42 +08:00
if (is_callable($postFormatter)) {
$arr = $postFormatter($arr);
2025-07-11 15:21:00 +08:00
}
2025-07-18 17:32:42 +08:00
return $arr;
2025-07-11 15:21:00 +08:00
} catch (\Throwable $e) {
return [
'error' => true,
'message' => $e->getMessage(),
2025-09-16 10:53:57 +08:00
// 'message' => $e->getMessage()."\n".$e->getLine()."\n".$e->getFile(),
2025-07-11 15:21:00 +08:00
'code' => $e->getCode(),
];
}
}
/**
2025-07-18 17:32:42 +08:00
* 格式化分页数据:转换每条记录
2025-07-11 15:21:00 +08:00
*
2025-07-18 17:32:42 +08:00
* @param LengthAwarePaginator $p
* @param callable $fmt
* @return array{records: array, total: int, current: int, size: int}
2025-07-11 15:21:00 +08:00
*/
protected function formatPaginated(
2025-07-18 17:32:42 +08:00
LengthAwarePaginator $p,
?callable $postFormatter,
callable $fmt
2025-07-11 15:21:00 +08:00
): array {
2025-07-18 17:32:42 +08:00
$records = $p->getCollection()
->map(fn($item) => $this->transformData($item, $postFormatter, $fmt))
->toArray();
2025-07-11 15:21:00 +08:00
return [
2025-07-18 17:32:42 +08:00
'records' => $records,
'total' => $p->total(),
'current' => $p->currentPage(),
'size' => $p->perPage(),
2025-07-11 15:21:00 +08:00
];
}
/**
2025-07-18 17:32:42 +08:00
* 格式化 Eloquent 模型:主表属性 + 关联递归
2025-07-11 15:21:00 +08:00
*
* @param Model $model
2025-07-18 17:32:42 +08:00
* @param callable $fmt
2025-07-11 15:21:00 +08:00
* @return array
*/
2025-07-18 17:32:42 +08:00
protected function formatModel(
Model $model,
callable $fmt
): array {
$out = [];
// 1) 主表字段
2025-07-11 15:21:00 +08:00
foreach ($model->getAttributes() as $key => $value) {
2025-07-18 17:32:42 +08:00
$out[$fmt($key)] = $value;
2025-07-11 15:21:00 +08:00
}
2025-07-18 17:32:42 +08:00
// 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))
2025-07-11 15:21:00 +08:00
->toArray();
2025-07-18 17:32:42 +08:00
} else {
$out[$rel] = $relData;
2025-07-11 15:21:00 +08:00
}
}
2025-07-18 17:32:42 +08:00
return $out;
2025-07-11 15:21:00 +08:00
}
/**
2025-07-18 17:32:42 +08:00
* 格式化集合数据:对每个元素递归调用 transformData
2025-07-11 15:21:00 +08:00
*
2025-07-18 17:32:42 +08:00
* @param Collection $c
* @param callable $fmt
2025-07-11 15:21:00 +08:00
* @return array
*/
2025-07-18 17:32:42 +08:00
protected function formatCollection(
Collection $c,
callable $fmt
): array {
return $c
->map(fn($item) => $this->transformData($item, null, $fmt))
->toArray();
2025-07-11 15:21:00 +08:00
}
/**
2025-07-18 17:32:42 +08:00
* 格式化普通数组:递归处理可能出现的模型或集合
2025-07-11 15:21:00 +08:00
*
2025-07-18 17:32:42 +08:00
* @param array $arr
* @param callable $fmt
2025-07-11 15:21:00 +08:00
* @return array
*/
2025-07-18 17:32:42 +08:00
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);
2025-07-11 15:21:00 +08:00
}
}