如何在Rest API操作中过滤/清理/验证Symfony 5.4的请求参数
P粉617237727
P粉617237727 2023-12-18 18:58:41
0
1
498

我对 Symfony 5.4 相当陌生,最近使用该版本创建了我的第一个 API

对于我的特定 API 端点,参数之一是 ID 数组。

我需要通过以下方式验证该数组:

  • 确保这是一个数组;
  • 确保数组中的 ID 实际上引用数据库记录;

我以一种简单的方式实现了它,在使用类型转换和现有的 Repository 持久化实体之前检查数组:

$parentPropertyIds = (array)$request->request->get('parent_property_ids');
if ($parentPropertyIds) {
   $parentCount = $doctrine->getRepository(Property::class)->countByIds($parentPropertyIds);

   if ($parentCount !== count($parentPropertyIds)) {
       return $this->json([
            'status'  => 'error',
            'message' => 'parent_property_id_invalid'
       ], 422);
   }

   foreach ($parentPropertyIds as $parentPropertyId) {
      $parentProperty = $doctrine->getRepository(Property::class)->find($parentPropertyId);
      $property->addParent($parentProperty);
   }
}

但是,这使得我的控制器操作变得过于“身体积极”,并且感觉像是可以以更优雅的方式实现的东西。

我无法在 Symfony 5.4 文档中找到任何内容。

目前我想知道是否:

  • Symfony 中有一种过滤/清理请求参数的方法;
  • 有一种优雅的内置方法可以将自定义验证器约束应用于请求参数(类似于记录良好的实体字段验证);

完整端点代码:

/**
     * @Route("/property", name="property_new", methods={"POST"})
     */
    public function create(ManagerRegistry $doctrine, Request $request, ValidatorInterface $validator): Response
    {
        $entityManager = $doctrine->getManager();

        $property = new Property();
        $property->setName($request->request->get('name'));
        $property->setCanBeShared((bool)$request->request->get('can_be_shared'));

        $parentPropertyIds = (array)$request->request->get('parent_property_ids');
        if ($parentPropertyIds) {
            $parentCount = $doctrine
                ->getRepository(Property::class)
                ->countByIds($parentPropertyIds);

            if ($parentCount !== count($parentPropertyIds)) {
                return $this->json([
                    'status'  => 'error',
                    'message' => 'parent_property_id_invalid'
                ], 422);
            }

            foreach ($parentPropertyIds as $parentPropertyId) {
                $parentProperty = $doctrine->getRepository(Property::class)->find($parentPropertyId);
                $property->addParent($parentProperty);
            }
        }

        $errors = $validator->validate($property);

        if (count($errors) > 0) {
            $messages = [];
            foreach ($errors as $violation) {
                $messages[$violation->getPropertyPath()][] = $violation->getMessage();
            }
            return $this->json([
                'status'   => 'error',
                'messages' => $messages
            ], 422);
        }

        $entityManager->persist($property);
        $entityManager->flush();

        return $this->json([
            'status' => 'ok',
            'id'     => $property->getId()
        ]);
    }

P粉617237727
P粉617237727

全部回复(1)
P粉635509719

您可以将数据传输对象 (DTO) 与 验证服务。有许多预定义约束,或者您可以创建一个自定义约束。

例如,如何使用简单约束作为注释:

class PropertyDTO {
  /**
   * @Assert\NotBlank
   */
  public string $name = "";
  public bool $shared = false;
}

然后将数据分配给DTO:

$propertyData = new PropertyDTO();
$propertyData->name = $request->request->get('name');
...

在某些情况下,最好在 DTO 中定义构造函数,然后从 请求并立即传递给DTO:

$data = $request->getContent(); // or $request->getArray(); depends on your content type
$propertyData = new PropertyDTO($data);

然后验证它:

$errors = $validator->validate($propertyData);

if (count($errors) > 0) {
    /*
     * Uses a __toString method on the $errors variable which is a
     * ConstraintViolationList object. This gives us a nice string
     * for debugging.
     */
    $errorsString = (string) $errors;

    return $this->json([
                'status'  => 'error',
                'message' => 'parent_property_id_invalid'
            ], 422);
}

//...
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!