For an API I'm currently building I'd like to be able to send a request with a JSON body with the following content
{"title": "foo"}
to create a new database record for an Entity called Project
.
I made a controller which subclasses FOSRestController
. To create a project, I made an action
/**
* @Route("/")
*
* @ApiDoc(
* section="Project",
* resource=true,
* input={"class"="AppBundle\Form\API\ProjectType"},
* description="Creates a new project",
* statusCodes={
* 201="Returned when successful",
* }
* )
*
* @Method("POST")
* @Rest\View(statusCode=201)
*/
public function createProjectAction(Request $request)
{
$project = new Project();
$form = $this->createForm(ProjectType::class, $project);
$form->submit(($request->request->get($form->getName())));
if ($form->isSubmitted() && $form->isValid()) {
return $project;
}
return View::create($form, 400);
}
The ProjectType
looks like this
class ProjectType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('title');
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AppBundle\Entity\Project'
));
}
}
However, when I try to post said JSON to the API, it responds that the title
property cannot be blank, which is good because that's the validation rule set for it. However, it IS set. I suddenly realized I have to send the JSON prefixed by the actual object's name to make this work:
{"project":{"title": "bla"}}
Which feels a little strange to be fair, it should be enough to just post the properties.
So, based on this information I simply have 2 questions:
($request->request->get($form->getName()))
, shouldn't $request
be enough?Edit 1: adding or removing the data_class
in the Default Options does not change the behaviour at all.
This is because of how Symfony Controller "createForm" helper method works. Reasoning behind it is that multiple forms could have same target URL. By prefixing with form name, Symfony can know which form was submitted.
This can be seen by looking at "createForm" method implementation:
public function createForm($type, $data = null, array $options = array())
{
return $this->container->get('form.factory')->create($type, $data, $options);
}
If you don't want this behavior, it's really easy to change it:
public function createProjectAction(Request $request)
{
$project = new Project();
$form = $this->get('form.factory')->createNamed(null, new ProjectType(), $project);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
return $project;
}
return View::create($form, 400);
}
So you're basically creating a "nameless" form. Since you're building an API, it's probably a good idea to pull this into a createNamelessForm($type, $data, $options)
helper method in your base controller so that you don't have to get Form Factory from container explicitly all the time and make it easier on the eyes.
Wrapper key is not generated by "data_class" option, but by "getName()" method on your form type.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With