Order model.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; }
Order type.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:
#[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 being validated and I'm trying to figure it out. Any ideas would be greatly appreciated.
P粉3279030452024-03-30 12:25:10
I think you are missing the form name as a top level key in the submitted data. You are trying to send this:
{ "id": "dsdas", "customerId": 1, "total": "500.50" }
Your code ($request->request->get($form->getName())) expects this (if the form name is "order_type")
{ "order_type": { "id": "dsdas", "customerId": 1, "total": "500.50" } }
One solution is to create a named form...without a 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)); } } }
The third option (but not the best one) is that you always send the data to the controller along with the form key, but I wouldn't choose this option if it was an API endpoint. So only when it is a regular form submission and the submitted form fields are all generated with the original form name prefix.
As a final option, you can also capture the incoming data in both formats. Maybe something like this and you can actually send with or without a key:
$finalData = $request->request->get($form->getName()) ?: $request->request->all(); $form->submit([$form->getName() => $finalData]);