tangwei / dto
php hyperf dto
Installs: 123 536
Dependents: 2
Suggesters: 0
Security: 0
Stars: 14
Watchers: 2
Forks: 6
Open Issues: 0
pkg:composer/tangwei/dto
Requires
- php: >=8.1
- hyperf/di: ~3.0.0|~3.1.0
- hyperf/http-server: ~3.0.0|~3.1.0
- hyperf/validation: ~3.0.0|~3.1.0
- netresearch/jsonmapper: ~5.0.0
- phpdocumentor/reflection-docblock: ^5.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^3.0
- mockery/mockery: ^1.0
- phpstan/phpstan: ^1.0
- phpunit/phpunit: >=7.0
- symfony/property-access: ^5.0|^6.0
- symfony/serializer: ^5.0|^6.0
- symfony/var-dumper: ^5.1
- 3.1.x-dev
- dev-master / 3.1.x-dev
- v3.1.5
- v3.1.3
- v3.1.2
- v3.1.1
- 3.1.0
- 3.0.x-dev
- v3.0.9
- v3.0.8
- v3.0.7
- v3.0.6
- v3.0.5
- v3.0.4
- v3.0.3
- v3.0.2
- v3.0.1
- v3.0.0
- v3.0.0-beta6
- v3.0.0-beta5
- v3.0.0-beta4
- v3.0.0-beta3
- v3.0.0-beta2
- v3.0.0-beta1
- v2.2.0-beta2
- v2.2.0-beta1
- 2.1.x-dev
- v2.1.11
- v2.1.10
- v2.1.9
- v2.1.8
- v2.1.7
- v2.1.6
- v2.1.5
- v2.1.4
- v2.1.3
- v2.1.2
- v2.1.1
- v2.1.0
- 2.0.x-dev
- v2.0.0
- v2.0.0-beta1
- v1.0.3
- v1.0.2
- v1.0.0
- v0.3.0
- v0.2.2
- v0.2.1
- v0.2.0
- v0.1.0
- dev-test-swoole
- dev-data
This package is auto-updated.
Last update: 2025-12-15 08:05:19 UTC
README
English | 中文
基于 Hyperf 框架的 DTO (数据传输对象) 映射和验证库,使用 PHP 8.1+ 的属性(Attributes)特性,提供优雅的请求参数绑定和验证方案。
✨ 特性
- 🚀 自动映射 - 请求参数自动映射到 PHP DTO 类
- 🎯 类型安全 - 利用 PHP 8.1+ 的类型系统,提供完整的类型提示
- 🔄 递归支持 - 支持数组、嵌套对象、递归结构
- ✅ 数据验证 - 集成 Hyperf 验证器,提供丰富的验证注解
- 📝 多种参数源 - 支持 Body、Query、FormData、Header 等多种参数来源
- 🎨 代码优雅 - 基于 PHP 8 Attributes,代码简洁易读
- 🔧 易于扩展 - 支持自定义验证规则和类型转换
📋 环境要求
- PHP >= 8.1
- Hyperf
📦 安装
composer require tangwei/dto
安装后,组件会自动注册,无需额外配置。
📖 快速开始
基本使用
1. 创建 DTO 类
namespace App\Request; use Hyperf\DTO\Annotation\Validation\Required; use Hyperf\DTO\Annotation\Validation\Integer; use Hyperf\DTO\Annotation\Validation\Between; class DemoQuery { public string $name; #[Required] #[Integer] #[Between(1, 100)] public int $age; }
2. 在控制器中使用
namespace App\Controller; use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\GetMapping; use Hyperf\DTO\Annotation\Contracts\RequestQuery; use Hyperf\DTO\Annotation\Contracts\Valid; use App\Request\DemoQuery; #[Controller(prefix: '/user')] class UserController { #[GetMapping(path: 'info')] public function info(#[RequestQuery] #[Valid] DemoQuery $request): array { return [ 'name' => $request->name, 'age' => $request->age, ]; } }
📚 注解说明
参数来源注解
命名空间:
Hyperf\DTO\Annotation\Contracts
RequestBody
获取 POST/PUT/PATCH 请求的 Body 参数
use Hyperf\DTO\Annotation\Contracts\RequestBody; #[PostMapping(path: 'create')] public function create(#[RequestBody] CreateUserRequest $request) { // $request 会自动填充 Body 中的数据 }
RequestQuery
获取 URL 查询参数(GET 参数)
use Hyperf\DTO\Annotation\Contracts\RequestQuery; #[GetMapping(path: 'list')] public function list(#[RequestQuery] QueryRequest $request) { // $request 会自动填充 Query 参数 }
RequestFormData
获取表单请求数据(Content-Type: multipart/form-data)
use Hyperf\DTO\Annotation\Contracts\RequestFormData; #[PostMapping(path: 'upload')] public function upload(#[RequestFormData] UploadRequest $formData) { // $formData 会自动填充表单数据 // 文件上传需要通过 $this->request->file('field_name') 获取 }
RequestHeader
获取请求头信息
use Hyperf\DTO\Annotation\Contracts\RequestHeader; #[GetMapping(path: 'info')] public function info(#[RequestHeader] HeaderRequest $headers) { // $headers 会自动填充请求头数据 }
Valid
启用验证,必须与其他参数来源注解一起使用
#[PostMapping(path: 'create')] public function create(#[RequestBody] #[Valid] CreateUserRequest $request) { // 请求参数会先验证,验证失败会自动抛出异常 }
组合使用
可以在同一方法中组合使用多种参数来源:
#[PutMapping(path: 'update/{id}')] public function update( int $id, #[RequestBody] #[Valid] UpdateRequest $body, #[RequestQuery] QueryRequest $query, #[RequestHeader] HeaderRequest $headers ) { // 同时获取 Body、Query 和 Header 参数 }
⚠️ 注意:同一个方法不能同时使用
RequestBody和RequestFormData注解
📝 完整示例
控制器示例
namespace App\Controller; use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\GetMapping; use Hyperf\HttpServer\Annotation\PostMapping; use Hyperf\HttpServer\Annotation\PutMapping; use Hyperf\DTO\Annotation\Contracts\RequestBody; use Hyperf\DTO\Annotation\Contracts\RequestQuery; use Hyperf\DTO\Annotation\Contracts\RequestFormData; use Hyperf\DTO\Annotation\Contracts\Valid; #[Controller(prefix: '/demo')] class DemoController { #[GetMapping(path: 'query')] public function query(#[RequestQuery] #[Valid] DemoQuery $request): array { return [ 'name' => $request->name, 'age' => $request->age, ]; } #[PostMapping(path: 'create')] public function create(#[RequestBody] #[Valid] CreateRequest $request): array { // 处理创建逻辑 return ['id' => 1, 'message' => 'Created successfully']; } #[PutMapping(path: 'update')] public function update( #[RequestBody] #[Valid] UpdateRequest $body, #[RequestQuery] QueryParams $query ): array { // 同时使用 Body 和 Query 参数 return ['message' => 'Updated successfully']; } #[PostMapping(path: 'upload')] public function upload(#[RequestFormData] UploadRequest $formData): array { $file = $this->request->file('photo'); // 处理文件上传 return ['message' => 'Uploaded successfully']; } }
DTO 类示例
简单 DTO
namespace App\Request; use Hyperf\DTO\Annotation\Validation\Required; use Hyperf\DTO\Annotation\Validation\Integer; use Hyperf\DTO\Annotation\Validation\Between; use Hyperf\DTO\Annotation\Validation\Email; class CreateRequest { #[Required] public string $name; #[Required] #[Email] public string $email; #[Required] #[Integer] #[Between(18, 100)] public int $age; }
嵌套对象 DTO
namespace App\Request; class UserRequest { public string $name; public int $age; // 嵌套对象 public Address $address; } class Address { public string $province; public string $city; public string $street; }
数组类型 DTO
namespace App\Request; use Hyperf\DTO\Annotation\ArrayType; class BatchRequest { /** * @var int[] */ public array $ids; /** * @var User[] */ public array $users; // 使用 ArrayType 注解显式指定类型 #[ArrayType(User::class)] public array $members; }
自定义字段名
namespace App\Request; use Hyperf\DTO\Annotation\JSONField; class ApiRequest { // 将请求中的 user_name 映射到 userName #[JSONField('user_name')] public string $userName; #[JSONField('user_age')] public int $userAge; }
✅ 数据验证
内置验证注解
需要先安装 Hyperf 验证器:
composer require hyperf/validation
本库提供了丰富的验证注解,包括:
Required- 必填项Integer- 整数Numeric- 数字Between- 范围验证Min/Max- 最小/最大值Email- 邮箱格式Url- URL 格式Date- 日期格式DateFormat- 指定日期格式Boolean- 布尔值Alpha- 字母AlphaNum- 字母和数字AlphaDash- 字母、数字、破折号、下划线Image- 图片文件Json- JSON 格式Nullable- 可为空In- 在指定值中NotIn- 不在指定值中Regex- 正则表达式Unique- 数据库唯一Exists- 数据库存在
使用示例
基本验证
use Hyperf\DTO\Annotation\Validation\Required; use Hyperf\DTO\Annotation\Validation\Integer; use Hyperf\DTO\Annotation\Validation\Between; class DemoQuery { #[Required] public string $name; #[Required] #[Integer] #[Between(1, 100)] public int $age; }
在控制器中使用 #[Valid] 注解启用验证:
#[GetMapping(path: 'query')] public function query(#[RequestQuery] #[Valid] DemoQuery $request) { // 参数已经验证通过 }
自定义错误消息
class UserRequest { #[Required("用户名不能为空”)] public string $name; #[Between(18, 100, "年龄必须在 18-100 之间")] public int $age; }
使用 Validation 注解
Validation 注解支持 Laravel 风格的验证规则:
use Hyperf\DTO\Annotation\Validation\Validation; class ComplexRequest { // 使用管道符分隔多个规则 #[Validation("required|string|min:3|max:50”)] public string $username; // 数组元素验证 #[Validation("integer”, customKey: 'ids.*')] public array $ids; }
自定义验证规则
继承 BaseValidation 类即可创建自定义验证规则:
namespace App\Validation; use Attribute; use Hyperf\DTO\Annotation\Validation\BaseValidation; #[Attribute(Attribute::TARGET_PROPERTY | Attribute::IS_REPEATABLE)] class Phone extends BaseValidation { protected $rule = 'regex:/^1[3-9]\\d{9}$/'; public function __construct(string $messages = '手机号格式不正确') { parent::__construct($messages); } }
使用自定义验证:
use App\Validation\Phone; class RegisterRequest { #[Required] #[Phone] public string $mobile; }
🔧 高级功能
RPC 支持
在 JSON-RPC 服务中返回 PHP 对象,需要配置序列化支持。
1. 安装依赖
composer require symfony/serializer ^5.0|^6.0 composer require symfony/property-access ^5.0|^6.0
2. 配置 Aspect
在 config/autoload/aspects.php 中添加:
return [ \Hyperf\DTO\Aspect\ObjectNormalizerAspect::class, ];
3. 配置依赖
在 config/autoload/dependencies.php 中添加:
use Hyperf\Serializer\SerializerFactory; use Hyperf\Serializer\Serializer; return [ Hyperf\Contract\NormalizerInterface::class => new SerializerFactory(Serializer::class), ];
自定义类型转换
如果需要自定义类型转换逻辑,可以实现自己的转换器:
namespace App\Convert; use Hyperf\DTO\Type\ConvertCustom; class CustomConvert implements ConvertCustom { public function convert(mixed $value): mixed { // 自定义转换逻辑 return $value; } }
在 DTO 类中使用:
use Hyperf\DTO\Annotation\Dto; use Hyperf\DTO\Type\Convert; #[Dto(Convert::SNAKE)] class UserResponse { public string $name; public int $age; }
💡 最佳实践
1. DTO 类结构设计
- 为不同的请求类型创建独立的 DTO 类
- 使用有意义的类名,如
CreateUserRequest、UpdateUserRequest - 将 Request DTO 和 Response DTO 分开存放
2. 验证规则
- 优先使用内置验证注解,保持代码可读性
- 复杂验证使用
Validation注解 - 通用验证规则封装为自定义注解
3. 错误处理
验证失败会抛出 Hyperf\Validation\ValidationException 异常,可以通过异常处理器统一处理:
namespace App\Exception\Handler; use Hyperf\ExceptionHandler\ExceptionHandler; use Hyperf\Validation\ValidationException; use Psr\Http\Message\ResponseInterface; use Hyperf\HttpMessage\Stream\SwooleStream; class ValidationExceptionHandler extends ExceptionHandler { public function handle(\Throwable $throwable, ResponseInterface $response) { if ($throwable instanceof ValidationException) { $this->stopPropagation(); return $response->withStatus(422)->withBody( new SwooleStream(json_encode([ 'code' => 422, 'message' => 'Validation failed', 'errors' => $throwable->validator->errors()->toArray(), ])) ); } return $response; } public function isValid(\Throwable $throwable): bool { return $throwable instanceof ValidationException; } }
📚 常见问题
Q: 为什么验证没有生效?
A: 请确保:
- 已安装
hyperf/validation组件 - 在控制器方法参数上添加了
#[Valid]注解 - DTO 类中的属性添加了验证注解
Q: 如何处理嵌套数组?
A: 使用 PHPDoc 或 ArrayType 注解:
/** * @var User[] */ public array $users; // 或者 #[ArrayType(User::class)] public array $users;
Q: 可以同时使用 RequestBody 和 RequestFormData 吗?
A: 不可以。这两个注解是互斥的,因为它们处理不同的请求类型。
Q: 如何处理文件上传?
A: 使用 RequestFormData 注解,然后通过 $this->request->file() 获取文件。