aneterial/laravel-data-validator

Laravel 数据验证和请求注入 DTO 结构的方便包

1.0.1 2024-06-04 22:00 UTC

This package is auto-updated.

Last update: 2024-09-04 22:25:59 UTC


README

Build Status License Packagist PHP Laravel

内容

先决条件

  • PHP 8.2 或更高版本
  • Laravel 11

开发使用

  • PHPUnit &11
  • phpstan ^1.11
  • php-cs-fixer ^3.58

安装

使用 composer 安装包

composer require aneterial/laravel-data-validator

使用

现在,您有了一个类属性 DataValidator\Attributes\RequestProperty 可以使用。将其添加到 DTO 的属性中,并设置必要的配置字段

use DataValidator\Attributes\RequestProperty;

final readonly class ExampleDTO {
  #[RequestProperty(property: 'id', rules: 'required|integer|min:0')]
  public int $id;

  #[RequestProperty(property: 'email', rules: 'required|string|email')]
  public string $email;
}

字段说明

  • property:与属性匹配的请求键名
  • rules:基于组件语义的验证规则 Laravel 验证,接受字符串值
  • requestDataType:指示字段的位置 - 在请求体中(默认) const RequestProperty::BODY_TYPE 或在查询字符串中 const RequestProperty::QUERY_TYPE
  • listRules:如果值是数组(列表) - 根据语义设置每个元素的验证规则 Laravel 验证

接下来,您需要在控制器中从应用 DI 容器获取一个 DataValidator\DataManager 实例,并将请求本体传递给它,指明您希望在验证和填充数据后接收的 DTO 类。

$dataManager = app(\DataValidator\DataManager::class);

接下来,Laravel 验证器将检查请求实体(instanse of \Illuminate\Http\Request),如果数据不正确,将抛出 \Illuminate\Validation\ValidationException。如果数据正确,Manager 将创建并填充 DTO 对象,您可以在应用程序中使用它

/** @var ExampleDTO $dto */
$dto = $dataManager->validateAndConvert(from: $request, to: ExampleDTO::class);

如果您的端点涉及传递对象数组 [{...}, {...}, {...}],您可以使用一个方法来验证请求并返回 DTO 数组

/** @var ExampleDTO[] $dtos */
$dtos = $dataManager->validateAndConvertList(from: $request, to: ExampleDTO::class);

示例

以下是一些使用属性验证的示例

  1. 具有列表的 DTO
final readonly class ExampleDTO {
...

  /** @var string[] $emails */
  #[RequestProperty(property: 'emails', rules: 'required|list', listRules: 'string|email')]
  public array $emails;
  
  /** @var int[] $ids */
  #[RequestProperty(property: 'ids', rules: 'required|list', listRules: 'int|min:0')]
  public array $ids;

...
}
  1. 具有非必需属性的 DTO,如果不要求则应该是可空的,除了数组 - 它可以是空数组
final readonly class ExampleDTO {
  #[RequestProperty(property: 'id', rules: 'integer|min:0')]
  public ?int $id;

  #[RequestProperty(property: 'email', rules: 'string|email')]
  public ?string $email;

  /** @var int[] $ids */
  #[RequestProperty(property: 'ids', rules: 'list', listRules: 'int|min:0')]
  public array $ids;
}
  1. 具有嵌套对象的 DTO
final readonly class ExampleDTO {
...

  #[RequestProperty(property: 'child', rules: 'required|array')]
  public NestedDTO $child;

...
}

// NestedDTO should contain properties with attributes
final readonly class NestedDTO {
  #[RequestProperty(property: 'id', rules: 'required|integer|min:0')]
  public int $id;

  #[RequestProperty(property: 'email', rules: 'required|string|email')]
  public string $email;
}
  1. 具有嵌套对象列表的 DTO
final readonly class ExampleDTO {
...

  /** @var NestedDTO[] $children */
  #[RequestProperty(property: 'children', rules: 'required|list', listRules: NestedDTO::class)]
  public array $children;

...
}
  1. 具有 BackedEnum 属性枚举的 DTO,您应该将枚举类型设置为属性,无需更多规则,除非您想 - 指明枚举的类型
final readonly class ExampleDTO {
...

  #[RequestProperty(property: 'enum', rules: 'required|string')]
  public AnApplicationEnum $enum;

...
}
  1. 具有 BackedEnum 属性枚举的 DTO
final readonly class ExampleDTO {
...
  /** @var AnApplicationEnum[] $enums */
  #[RequestProperty(property: 'enums', rules: 'required|list', listRules: AnApplicationEnum::class)]
  public array $enums;

...
}

限制

- Important note: for different requestDataType

如果 DTO 有嵌套对象或嵌套对象的数组,则忽略这些实体的 requestDataType,并从父实体获取

所以如果您使用

final readonly class ExampleDTO {
...

  #[RequestProperty(property: 'child', rules: 'required|array', requestDataType: RequestProperty::BODY_TYPE)]
  public NestedDTO $child;

...
}

// NestedDTO should contain properties with attributes
final readonly class NestedDTO {
  #[RequestProperty(property: 'id', rules: 'required|integer|min:0', requestDataType: RequestProperty::QUERY_TYPE)]
  public int $id;

  #[RequestProperty(property: 'email', rules: 'required|string|email', requestDataType: RequestProperty::QUERY_TYPE)]
  public string $email;
}

嵌套对象中的 requestDataType 不会工作,它将是 RequestProperty::BODY_TYPE,就像父实体一样

- Another one: for list validation

DataManager::validateAndConvertList 方法只能与请求体中的数据一起使用,因此在此用法中,实体的所有属性都将强制转换为类型 RequestProperty::BODY_TYPE