本文目录导读:

在Laravel中处理数据转换与格式化有多种方法,我将为您详细介绍最常用的几种方式。
API Resource(最推荐)
基础Resource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at->format('Y-m-d H:i:s'),
'profile' => [
'avatar' => $this->profile->avatar_url ?? null,
'bio' => $this->profile->bio ?? null,
],
'roles' => RoleResource::collection($this->whenLoaded('roles')),
];
}
}
带条件的Resource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class OrderResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'order_no' => $this->order_no,
'total_amount' => $this->formatAmount($this->total_amount),
'status' => $this->status,
'status_text' => $this->getStatusText(),
// 使用when条件
'items' => OrderItemResource::collection($this->whenLoaded('items')),
'invoice' => $this->when($this->hasInvoice(),
new InvoiceResource($this->invoice)
),
// 使用whenHas
'coupon' => $this->whenHas('coupon', function() {
return [
'code' => $this->coupon->code,
'discount' => $this->coupon->discount
];
}),
// 只返回特定角色才能看到的字段
'internal_notes' => $this->when(
$request->user()->isAdmin(),
$this->internal_notes
),
];
}
private function formatAmount($amount)
{
return number_format($amount, 2, '.', ',');
}
private function getStatusText()
{
return [
'pending' => '待处理',
'processing' => '处理中',
'completed' => '已完成',
'cancelled' => '已取消'
][$this->status] ?? $this->status;
}
}
Eloquent Accessors(模型访问器)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;
class Product extends Model
{
// 使用Attribute类(Laravel 9+)
protected function price(): Attribute
{
return Attribute::make(
get: fn ($value) => $value / 100, // 分转元
set: fn ($value) => $value * 100 // 元转分
);
}
// 传统方式
public function getPriceFormatAttribute()
{
return '¥' . number_format($this->price, 2);
}
public function getStatusColorAttribute()
{
return [
'active' => 'green',
'inactive' => 'gray',
'soldout' => 'red'
][$this->status] ?? 'gray';
}
// 复合访问器
protected function displayName(): Attribute
{
return Attribute::make(
get: fn () => $this->name . ' (' . $this->sku . ')'
);
}
}
日期格式转换
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Event extends Model
{
protected $casts = [
'started_at' => 'datetime:Y-m-d H:i:s',
'ends_at' => 'datetime:Y-m-d H:i:s',
'is_active' => 'boolean',
'config' => 'array',
'metadata' => 'object',
];
// 自定义日期格式
protected function startDate(): Attribute
{
return Attribute::make(
get: fn () => $this->started_at?->format('m/d/Y'),
set: fn ($value) => Carbon::parse($value)
);
}
}
// 在Resource中使用
class EventResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'title' => $this->title,
'start_date' => $this->start_date,
'end_date' => $this->ends_at->translatedFormat('d F Y'),
'duration' => $this->getDurationHuman()
];
}
}
集合转换与格式化
<?php
namespace App\Http\Controllers\API;
use App\Models\User;
use Illuminate\Support\Collection;
class UserController extends Controller
{
public function index()
{
$users = User::with('roles')->latest()->get();
// 使用Collection的方法
$formatted = $users->map(function ($user) {
return [
'name' => $user->name,
'email' => $user->email,
'role_names' => $user->roles->pluck('name')->implode(', '),
'age' => $user->birthday?->age ?? '未知'
];
})->filter(function ($user) {
return !empty($user['role_names']);
})->values();
// 分组转换
$grouped = $users->groupBy('role')->map->count();
// 排序
$sorted = $users->sortByDesc(function ($user) {
return $user->orders_count;
})->values();
return response()->json([
'data' => $formatted,
'meta' => [
'total' => $users->count(),
'grouped' => $grouped
]
]);
}
}
数据转换中间件
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class FormatResponse
{
public function handle(Request $request, Closure $next)
{
$response = $next($request);
// 只处理JSON响应
if ($response instanceof \Illuminate\Http\JsonResponse) {
$data = $response->getData(true);
// 统一响应格式
$formatted = [
'success' => $response->getStatusCode() < 400,
'data' => $data['data'] ?? $data,
'message' => $data['message'] ?? '',
'timestamp' => now()->toISOString(),
'status_code' => $response->getStatusCode()
];
if ($response->getStatusCode() >= 400) {
$formatted['errors'] = $data['errors'] ?? null;
}
$response->setData($formatted);
}
return $response;
}
}
复杂转换示例
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class DashboardResource extends JsonResource
{
public function toArray($request)
{
return [
'user' => new UserResource($this->user),
'statistics' => $this->getStatistics(),
'notifications' => $this->getNotifications(),
'recent_orders' => $this->getRecentOrders(),
'chart_data' => [
'labels' => $this->getChartLabels(),
'datasets' => $this->getChartDatasets()
]
];
}
private function getStatistics(): array
{
return [
'total_revenue' => money_format($this->totalRevenue),
'orders_count' => $this->ordersCount,
'customers_count' => $this->customersCount,
'avg_order_value' => money_format(
$this->totalRevenue / max($this->ordersCount, 1)
),
'growth_rate' => $this->calculateGrowthRate() . '%'
];
}
private function getNotifications(): Collection
{
return $this->notifications
->take(5)
->map(fn ($notification) => [
'id' => $notification->id,
'type' => $notification->type,
'message' => $notification->data['message'],
'read' => (bool) $notification->read_at,
'time_ago' => $notification->created_at->diffForHumans()
]);
}
private function getChartDatasets(): array
{
$colors = ['#FF6384', '#36A2EB', '#FFCE56'];
return $this->statisticsByMonth
->map(function ($data, $index) use ($colors) {
return [
'label' => $data->month,
'color' => $colors[$index % count($colors)],
'data' => [...array_values($data->values)],
'borderWidth' => 2
];
})
->values()
->all();
}
}
使用Traits复用转换逻辑
<?php
namespace App\Traits;
trait FormatsModelData
{
public function formatMoney($amount, $currency = 'USD'): string
{
$symbols = [
'USD' => '$',
'CNY' => '¥',
'EUR' => '€'
];
$symbol = $symbols[$currency] ?? '$';
return $symbol . number_format($amount, 2);
}
public function formatDate($date, $format = 'Y-m-d'): ?string
{
return $date ? $date->format($format) : null;
}
public function formatBytes($bytes, $precision = 2): string
{
$units = ['B', 'KB', 'MB', 'GB', 'TB'];
$bytes = max($bytes, 0);
$pow = floor(($bytes ? log($bytes) : 0) / log(1024));
$pow = min($pow, count($units) - 1);
$bytes /= pow(1024, $pow);
return round($bytes, $precision) . ' ' . $units[$pow];
}
}
// 在模型中使用
class File extends Model
{
use FormatsModelData;
public function getHumanSizeAttribute(): string
{
return $this->formatBytes($this->size);
}
public function getUploadedAtAttribute($value): string
{
return $this->formatDate($value, 'Y-m-d H:i') ?? '未知';
}
}
实用转换方法集合
<?php
namespace App\Helpers;
class DataFormatter
{
public static function normalizePhone($phone): string
{
$phone = preg_replace('/[^0-9+]/', '', $phone);
// 中国手机号格式化
if (strlen($phone) === 11 && substr($phone, 0, 1) === '1') {
return substr($phone, 0, 3) . '-' . substr($phone, 3, 4) . '-' . substr($phone, 7);
}
return $phone;
}
public static function maskEmail($email, $visibleChars = 3): string
{
[$username, $domain] = explode('@', $email);
$maskedUsername = substr($username, 0, $visibleChars) . str_repeat('*', max(0, strlen($username) - $visibleChars));
return $maskedUsername . '@' . $domain;
}
public static function generateSlug($text, $maxLength = 60): string
{
$text = strtolower($text);
$text = preg_replace('/[^a-z0-9]+/', '-', $text);
$text = trim($text, '-');
return substr($text, 0, $maxLength);
}
public static function formatAddress(array $address): string
{
return implode(' ', array_filter([
$address['province'] ?? '',
$address['city'] ?? '',
$address['district'] ?? '',
$address['detail'] ?? ''
]));
}
}
使用这些转换方法时,请根据您的具体需求选择合适的方式。API Resource 最适合API响应格式转换,Accessors 适合模型层的数据格式化,而Collection方法 适合数据处理和转换。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播