本文目录导读:

- 基础 DTO 类实现
- 使用 Spatie Data Transfer Object 包
- 使用 Laravel Eloquent API Resources
- 使用 AutoMapper 模式
- 高级实现 - 通用 DTO 映射器
- 使用 PHP 8 Attributes 自动映射
- 使用 Factory 模式
- 推荐方案
在 Laravel 中实现数据映射到 DTO(Data Transfer Object)有多种方式,我来介绍几种常用的实现方法:
基础 DTO 类实现
<?php
namespace App\DTOs;
class UserDTO
{
public function __construct(
public readonly int $id,
public readonly string $name,
public readonly string $email,
public readonly ?string $phone,
public readonly ?\DateTime $createdAt
) {}
public static function fromArray(array $data): self
{
return new self(
id: $data['id'],
name: $data['name'],
email: $data['email'],
phone: $data['phone'] ?? null,
createdAt: isset($data['created_at'])
? new \DateTime($data['created_at'])
: null
);
}
public static function fromModel($model): self
{
return new self(
id: $model->id,
name: $model->name,
email: $model->email,
phone: $model->phone,
createdAt: $model->created_at
);
}
public function toArray(): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'phone' => $this->phone,
'created_at' => $this->createdAt?->format('Y-m-d H:i:s')
];
}
}
使用 Spatie Data Transfer Object 包
安装包:
composer require spatie/data-transfer-object
<?php
namespace App\DTOs;
use Spatie\DataTransferObject\DataTransferObject;
class UserDTO extends DataTransferObject
{
public int $id;
public string $name;
public string $email;
public ?string $phone;
public ?\DateTimeInterface $createdAt;
// 可选:添加验证规则
public function getValidationRules(): array
{
return [
'name' => ['required', 'string', 'max:255'],
'email' => ['required', 'email'],
];
}
}
// 使用示例
$userDTO = new UserDTO([
'id' => 1,
'name' => 'John Doe',
'email' => 'john@example.com',
'phone' => null,
'createdAt' => now(),
]);
使用 Laravel Eloquent API Resources
<?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,
'phone' => $this->phone,
'created_at' => $this->created_at,
'roles' => RoleResource::collection($this->whenLoaded('roles')),
];
}
}
// 控制器中使用
public function show(User $user): UserResource
{
return new UserResource($user);
}
// 集合
public function index(): ResourceCollection
{
return UserResource::collection(User::paginate());
}
使用 AutoMapper 模式
<?php
namespace App\Mappers;
use App\DTOs\UserDTO;
use App\Models\User;
class UserMapper
{
public function toDTO(User $user): UserDTO
{
return new UserDTO(
id: $user->id,
name: $user->name,
email: $user->email,
phone: $user->phone,
createdAt: $user->created_at
);
}
public function toDTOs($users): array
{
return $users->map(fn($user) => $this->toDTO($user))->toArray();
}
public function toModel(UserDTO $dto): User
{
$user = new User();
$user->name = $dto->name;
$user->email = $dto->email;
$user->phone = $dto->phone;
return $user;
}
public function updateFromDTO(User $user, UserDTO $dto): User
{
$user->name = $dto->name;
$user->email = $dto->email;
$user->phone = $dto->phone;
return $user;
}
}
高级实现 - 通用 DTO 映射器
<?php
namespace App\DTOs;
use Illuminate\Support\Str;
abstract class BaseDTO
{
public static function fromArray(array $data): static
{
$dto = new static();
foreach ($data as $key => $value) {
$property = Str::camel($key);
if (property_exists($dto, $property)) {
$dto->$property = $value;
}
}
return $dto;
}
public static function fromModel($model): static
{
return static::fromArray($model->toArray());
}
public function toArray(): array
{
$data = [];
foreach (get_object_vars($this) as $property => $value) {
$data[Str::snake($property)] = $value;
}
return $data;
}
}
// 使用
class UserDTO extends BaseDTO
{
public int $id;
public string $name;
public string $email;
public ?string $phone;
public ?string $createdAt;
}
// 控制器中使用
$userDTO = UserDTO::fromModel($user);
$usersDTOs = User::all()->map(fn($user) => UserDTO::fromModel($user));
使用 PHP 8 Attributes 自动映射
<?php
namespace App\Attributes;
use Attribute;
#[Attribute(Attribute::TARGET_PROPERTY)]
class MapFrom
{
public function __construct(
public string $source,
public ?string $callback = null
) {}
}
// DTO 实现
class AdvancedUserDTO
{
#[MapFrom('id')]
public int $id;
#[MapFrom('name')]
public string $name;
#[MapFrom('email')]
public string $email;
#[MapFrom('phone')]
public ?string $phone;
#[MapFrom('created_at', 'formatDate')]
public ?string $createdAt;
public static function fromModel($model): self
{
$dto = new self();
$reflection = new \ReflectionClass($dto);
foreach ($reflection->getProperties() as $property) {
$attributes = $property->getAttributes(MapFrom::class);
if (!empty($attributes)) {
$mapFrom = $attributes[0]->newInstance();
$sourceProperty = $mapFrom->source;
$value = $model->$sourceProperty ?? null;
if ($mapFrom->callback && method_exists($dto, $mapFrom->callback)) {
$value = $dto->{$mapFrom->callback}($value);
}
$property->setValue($dto, $value);
}
}
return $dto;
}
protected function formatDate($value): ?string
{
return $value ? $value->format('Y-m-d H:i:s') : null;
}
}
使用 Factory 模式
<?php
namespace App\Factories;
use App\DTOs\UserDTO;
use App\Models\User;
class UserDTOFactory
{
public function makeFromRequest(array $requestData): UserDTO
{
return new UserDTO(
id: $requestData['id'] ?? null,
name: $requestData['name'],
email: $requestData['email'],
phone: $requestData['phone'] ?? null,
createdAt: now()
);
}
public function makeFromModel(User $user): UserDTO
{
return new UserDTO(
id: $user->id,
name: $user->name,
email: $user->email,
phone: $user->phone,
createdAt: $user->created_at
);
}
public function makeCollection($users): array
{
return $users->map(fn($user) => $this->makeFromModel($user))->toArray();
}
}
// 注册为服务提供者
public function register()
{
$this->app->singleton(UserDTOFactory::class, function ($app) {
return new UserDTOFactory();
});
}
// 控制器中使用
public function index(UserDTOFactory $factory)
{
$users = User::all();
return $factory->makeCollection($users);
}
推荐方案
对于新项目,我推荐使用 Spatie Data Transfer Object 包,它提供了:
- 类型安全
- 自动验证
- 序列化和反序列化
- 不变性(可选)
- 嵌套 DTO 支持
选择哪种方案取决于你的具体需求:
- 简单项目:基础 DTO 类
- 需要验证:Spatie DTO 包
- API 响应:Laravel API Resources
- 复杂映射:AutoMapper 模式
版权声明: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直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播