我有一个 API Platform DataTransformer,它使用注入的 ValidatorInterface 来验证传入请求的 JSON POST 正文。它基本上是 docs:
中示例的副本<?php
namespace App\DataTransformer;
use ApiPlatform\Core\Validator\ValidatorInterface;
use ApiPlatform\Core\DataTransformer\DataTransformerInterface;
use App\Entity\Ticket;
use App\DTO\TicketInput;
class InputDataTransformer implements DataTransformerInterface
{
public function __construct(
private readonly ValidatorInterface $validator,
) {}
/**
* @param TicketInput $object
*/
public function transform($object, string $to, array $context = []): Ticket
{
// Validation
$this->validator->validate($object);
$ticket = new Ticket($object->id, $object->content);
return $ticket;
}
public function supportsTransformation($data, string $to, array $context = []): bool
{
return (Ticket::class === $to) && (($context['input']['class'] ?? null) === TicketInput::class);
}
}
通过 ContextBuilder 和
supportsTransformation()
,我确保传入的 $object
属于 TicketInput 类型。这堂课就是这么简单:
<?php
namespace App\DTO;
class TicketInput
{
public int $id;
public ?string $content;
}
我想知道的是:验证器通过
TicketInput::class
验证 $id
必须是整数并且不可为空。 $content
必须是字符串,且允许为空。
所以这些是有效输入:
{
"id": 123,
"content": null
},
{
"id": 123,
"content": "testtest"
}
这是无效并被拒绝(400 - 错误请求):
{
"id": null,
"content": "foobar"
}
到目前为止一切顺利。但我的一个单元测试使用此 JSON 作为请求正文:
{
"content": "foobar"
}
这破坏了我的代码,因为
$id
是结果 Ticket::class
的必需值。
我非常惊讶最后一个案例能够通过验证器,因为我在
$id
中明确将 TicketInput::class
定义为(不可为空)类变量。有人可能会争辩说,验证器没有义务在验证时验证“未初始化”的属性(根据 var_dump
,这里就是这种情况),但尽管如此,我还是对如何定义该属性是 mandatory 感兴趣。并且必须是 JSON POST 正文的一部分。 我能想到的最好的办法是 Symfony 验证约束
#[Assert\NotBlank(allowNull: false)]
(参见
docs),它检查
is_null()
并间接检查 isset()
,但我不敢相信这就是解决方案,而且我已经像这样标记每个属性(实际的TicketInput::class
比这个MWE更大更复杂)。是否没有任何验证器配置标志告诉它确保 DTO 中的属性在 JSON 正文中是强制性的?
每个简单的 JSON 模式验证器都能够做到这一点,我想知道为什么我在 Symfony 文档或 API 平台文档中都没有找到任何提示。
PATCH
方法允许仅发送您想要更新的字段,而
PUT
方法则需要整个数据都在那里。因此,根据方法,我想使用相同的 DTO 对象,但仅允许验证发送的字段。