登录
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace app\common\traits;
|
||||
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* 数据转换器 Trait
|
||||
* 用于将原始数据(如模型、集合、分页等)统一转换为数组格式,
|
||||
* 并支持字段级与结果级的灵活后置加工。
|
||||
*/
|
||||
trait DataTransformer
|
||||
{
|
||||
/**
|
||||
* 核心转换方法
|
||||
*
|
||||
* @param mixed $rawData 原始数据:Model、Collection、Paginator、数组等
|
||||
* @param array $opts 可选配置:
|
||||
* - 'fieldFormatter' => 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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user