简体   繁体   English

Symfony POST 请求在应该给出错误的地方通过了验证

[英]Symfony POST request is passing validation where it should be giving errors

OrderModel.php OrderModel.php

<?php

namespace App\Dto\Request\Model;

use Symfony\Component\Validator\Constraints as Assert;

class OrderModel
{
    #[Assert\Uuid(message: "Order id must be an unique identifier value.")]
    #[Assert\Positive(message: "Order id must be a positive integer value.")]
    public int $id;

    /**
     * @Assert\Positive(message="customerId must be a positive integer value.")
     */
    public int $customerId;

    public array $items;

    /**
     * @Assert\Type("string", message="Order total must be a string float value.")
     * @Assert\Type("float", message="Order total must be a string float value.")
     */
    public string $total;
}

OrderType.php OrderType.php

<?php

use App\Dto\Request\Model\OrderModel;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class OrderType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('id', IntegerType::class)
            ->add('customerId', IntegerType::class)
            ->add('items', CollectionType::class, [
                'entry_type' => ItemType::class
            ])
            ->add('total', TextType::class);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => OrderModel::class
        ]);
    }
}

OrderController.php:订单控制器.php:

#[Route('/order', name:'order_new', methods: 'POST')]
public function create(ManagerRegistry $doctrine, Request $request): JsonResponse|Response
{
    $form = $this->createForm(\OrderType::class);
    if ($request->isMethod('POST')) {
        $form->submit($request->request->get($form->getName()));
        if(!$form->isSubmitted() || !$form->isValid()){
            return $this->handleView($this->view($form, Response::HTTP_BAD_REQUEST));
        }
    }
}

My Post Request:我的发帖请求:

{
  "id": "dsdas",
  "customerId": 1,
  "items": [
      {
          "productId": 1,
          "quantity": 1,
          "unitPrice": "250.25",
          "total": "250.25"
      },
      {
          "productId": 1,
          "quantity": 1,
          "unitPrice": "250.25",
          "total": "250.25"
      }
  ],
  "total": "500.50"
}

This request is passing validation and I'm trying to figure out.此请求正在通过验证,我正在尝试弄清楚。 Any ideas would be appreciated.任何想法,将不胜感激。

I think you are missing the form name in the submitted data as top-level key.我认为您在提交的数据中缺少表单名称作为顶级键。 You are trying to send this:您正在尝试发送:

{
    "id": "dsdas",
    "customerId": 1,
    "total": "500.50"
}

And your code ($request->request->get($form->getName())) expects this (if the form name is "order_type")你的代码 ($request->request->get($form->getName())) 期望这个(如果表单名称是“order_type”)

{
    "order_type": {
        "id": "dsdas",
        "customerId": 1,
        "total": "500.50"
    }
}

One solution is to create a named form with... no name:)一种解决方案是创建一个命名表单...没有名称:)

public function create(
    Request $request,
    FormFactoryInterface $formFactory
) {
    // Create form with no name: setting the first parameter to '' means no name (ideal for API endpoints)
    $form = $formFactory->createNamed('', OrderType::class);
    $form->handleRequest($request);
    if(
        !$form->isSubmitted() ||
        !$form->isValid()
    ) {
        // ...
    } else {
        // ...
    }
}

The second solution is to add the form name yourself第二种方案是自己添加表单名称

public function create(Request $request): JsonResponse|Response
{
    $form = $this->createForm(\OrderType::class);
    if ($request->isMethod('POST')) {
        $form->submit([
            // You can also add the key yourself right before submitting
            $form->getName() => $request->request->all(),
        ]);
        if(
            !$form->isSubmitted() ||
            !$form->isValid()
        ){
            return $this->handleView($this->view($form, Response::HTTP_BAD_REQUEST));
        }
    }
}

A third option but not the best one is that you always send your data WITH the form key to the controller, but I would not go for this option if it an API endpoint.第三个选项但不是最好的选项是您始终将带有表单密钥的数据发送到 controller,但如果它是 API 端点,我不会为此选项发送 go。 So only if it is a regular form submission and the submitted form fields are all generated with the original form name prefix.所以只有当是常规的表单提交,并且提交的表单字段都是以原始表单名称前缀生成的。

As a last option, you can also catch both data formats coming in. Maybe something like this so you can actually send with or without the key:作为最后一个选项,您还可以捕获两种数据格式。也许是这样的,这样您就可以使用或不使用密钥实际发送:

$finalData = $request->request->get($form->getName()) ?: $request->request->all();
$form->submit([$form->getName() => $finalData]);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM