Search code examples
restsymfonyfosrestbundle

Probleme validating a symfony form to submit POST request


I'm working on a POST REST service to create a new "User".

I follow this tutorial, it's french but the code I use should be the same.

https://zestedesavoir.com/tutoriels/1280/creez-une-api-rest-avec-symfony-3/developpement-de-lapi-rest/creer-et-supprimer-des-ressources/

So when I tried to add a User with my post rest service, it worked. When I add the form validation to verify args of my requests, each field return an error "This value should not be blank.", but I send correct values

Error returned using Postman :

{
  "code": 400,
  "message": "Validation Failed",
  "errors": {
    "errors": [
      "This form should not contain extra fields."
    ],
    "children": {
      "firstname": {
        "errors": [
          "This value should not be blank."
        ]
      },
      "lastname": {
        "errors": [
          "This value should not be blank."
        ]
      },
      "email": {
        "errors": [
          "This value should not be blank."
        ]
      }
    }
  }
}

I send this code using PostMan :

{
    "firstname": "Jimmy",
    "lastname": "Sample",
    "email": "mail@domain.com"
}

When I try to print $form->submit($request->request->all());, I got an empty array, so I suppose this is the problem. See User Controller code.

See the code I use :

USER

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
* @ORM\Entity()
* @ORM\Table(name="users",
*      uniqueConstraints={@ORM\UniqueConstraint(name="users_email_unique",columns={"email"})}
* )
*/
class User
{
   /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue
     */
    protected $id;

    /**
     * @ORM\Column(type="string")
     */
    protected $firstname;

    /**
     * @ORM\Column(type="string")
     */
    protected $lastname;

    /**
     * @ORM\Column(type="string")
     */
    protected $email;

    public function getId()
    {
        return $this->id;
    }

    public function setId($id)
    {
        $this->id = $id;
    }

    public function getFirstname()
    {
        return $this->firstname;
    }

    public function setFirstname($firstname)
    {
        $this->firstname = $firstname;
    }

    public function getLastname()
    {
        return $this->lastname;
    }

    public function setLastname($lastname)
    {
        $this->lastname = $lastname;
    }

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

USER CONTROLLER

<?php
namespace AppBundle\Controller;

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use FOS\RestBundle\Controller\Annotations as Rest; // alias pour toutes les annotations
use AppBundle\Form\Type\UserType;
use AppBundle\Entity\User;

class UserController extends Controller
{
[...]
    /**
     * @Rest\View(statusCode=Response::HTTP_CREATED)
     * @Rest\Post("/users")
     */
    public function postUsersAction(Request $request)
    {
        $user = new User();
        $form = $this->createForm(UserType::class, $user);

        $form->submit($request->request->all());

        if ($form->isValid()) {
            $em = $this->get('doctrine.orm.entity_manager');
            $em->persist($user);
            $em->flush();
            return $user;
        } else {
            return $form;
        }
    }
}

USER TYPE ( Form type )

<?php
namespace AppBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\EmailType;

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('firstname')
            ->add('lastname')
            ->add('email', EmailType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => 'AppBundle\Entity\User',
            'csrf_protection' => false
        ]);
    }
}

Validation YML file

AppBundle\Entity\User:
    constraints:
        - Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity: email
    properties:
        firstname:
            - NotBlank: {message: Noooooon il faut un prénom!!!}
            - Type: string
        lastname:
            - NotBlank: ~
            - Type: string
        email:
            - NotBlank: ~
            - Email: ~

Thank you


Solution

  • You are sending a json, then is required decode the json

        $json = $request->getContent();
        if ($decodedJson = json_decode($json, true)) {
            $data = $decodedJson;
        } else {
            $data = $request->request->all();
        }
        $formData = [];
        foreach ($form->all() as $name => $field) {
            if (isset($data[$name])) {
                $formData[$name] = $data[$name];
            }
        }
    
        $form->submit($formData);