I am trying to submit a JSON through a complex form. I can't figure out what I am missing. The "normal" form is functioning. I am able to get serialized data with groups.
Class TaskBoard
class TaskBoard
{
/**
* @var integer $id id
*
* @ORM\Id()
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @var \DateTime $createdTime createdTime
*
* @ORM\Column(type="datetime")
* @Assert\DateTime()
*/
private $createdTime;
/**
* @var \DateTime $lastUpdatedTime lastUpdatedTime
*
* @ORM\Column(type="datetime", nullable=true)
* @Assert\DateTime()
*/
private $lastUpdatedTime;
/**
* @var string $name name
*
* @ORM\Column(type="string", length=20)
* @Assert\Type("string")
* @Assert\NotBlank()
* @Assert\Length(
* min = 2,
* max = 20,
* minMessage = "The name must be at least {{ limit }} characters long",
* maxMessage = "The name cannot be longer than {{ limit }} characters"
* )
*/
private $name;
/**
* @var App\Entity\User $user user
*
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="taskboards", cascade={"persist"})
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* @var string $description description
*
* @ORM\Column(type="text", nullable=true)
* @Assert\Type("string")
*/
private $description;
/**
* @var App\Entity\Status $status status
*
* @ORM\ManyToOne(targetEntity="App\Entity\Status", inversedBy="taskboards", cascade={"persist"})
* @ORM\JoinColumn(name="status_id", referencedColumnName="id", nullable=false)
*/
private $status;
/**
* @var boolean $completed completed
*
* @ORM\Column(type="boolean")
*/
private $completed;
/**
* @var \DateTime $deadLine deadLine
*
* @ORM\Column(type="date", nullable=true)
* @Assert\DateTime()
* @Assert\GreaterThanOrEqual("today")
*/
private $deadLine;
Class Status
class Status
{
/**
* @ORM\Id()
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\Column(type="string", length=20)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity="App\Entity\TaskBoard", mappedBy="status", cascade={"persist"})
*/
public $taskboards;
Class User
class User extends BaseUser
{
/**
* @ORM\Id()
* @ORM\GeneratedValue(strategy="AUTO")
* @ORM\Column(type="integer")
*/
protected $id;
/**
* @ORM\OneToMany(targetEntity="App\Entity\TaskBoard", mappedBy="user", cascade={"persist"})
*/
public $taskboards;
Form
class TaskBoardType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', TextType::class)
->add('user', EntityType::class, array(
'class' => User::class,
'choice_label' => 'username',
)
)
->add('description', TextareaType::class, array(
'required' => false
))
->add('status', EntityType::class, array(
'class' => Status::class,
'choice_label' => 'name',
)
)
->add('deadLine', DateTimeType::class)
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => TaskBoard::class,
'csrf_protection' => false,
]);
}
Controller
class TaskBoardAPIController extends AbstractController {
public function postTaskBoard(Request $request) {
$form = $this->createForm(TaskBoardType::class, new TaskBoard());
$data = json_decode(
$request->getContent(), true
);
var_dump($data);
$form->submit($data);
if (!$form->isValid()) {
return new JsonResponse(
[
'status' => 'error',
'errors' => $form->getErrors(),
'form' => $form,
], JsonResponse::HTTP_BAD_REQUEST
);
}
$this->entityManager->persist($form->getData());
$this->entityManager->flush();
return new JsonResponse(
[
'status' => 'ok',
], JsonResponse::HTTP_CREATED
);
}
JSON sent
{
"name": "XXX",
"user": {
"id": 1,
"username": "BFA"
},
"description": "XXXXXXXXXXXXXXX",
"status": {
"id": 1,
"name": "To Do"
},
"completed": false
}
The form is not valid and blank in the JsonResponse.
I based myself on : https://codereviewvideos.com/course/beginners-guide-back-end-json-api-front-end-2018/video/symfony-4-json-api-form-submission and Deserialize an entity with a relationship with Symfony Serializer Component
Thanks for your help.
Your forgot to handle and get form submission. Note that you will need to get request data using something like
$form = $this->createFormBuilder($task)
... add fields
->getForm();
$form->handleRequest($request); // handling request
if ($form->isSubmitted() && $form->isValid()) {
// $form->getData() holds the submitted values
// but, the original `$task` variable has also been updated
$task = $form->getData();
// ... perform some action, such as saving the task to the database
// for example, if Task is a Doctrine entity, save it!
// $entityManager = $this->getDoctrine()->getManager();
// $entityManager->persist($task);
// $entityManager->flush();
return $this->redirectToRoute('...');
}
for more, see Handling Form Submissions
What was wrong was the JSON input.
The form does this :
class TaskBoardType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('name', TextType::class)
->add('user', EntityType::class, array(
'class' => User::class,
'choice_label' => 'username',
)
)
->add('description', TextareaType::class, array(
'required' => false
))
->add('status', EntityType::class, array(
'class' => Status::class,
'choice_label' => 'name',
)
)
->add('deadLine', DateTimeType::class)
;
}
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults([
'data_class' => TaskBoard::class,
'csrf_protection' => false,
]);
}
When checking the code generated from the form, this is the result :
<div>
<label for="task_board_user" class="required">User</label>
<select id="task_board_user" name="task_board[user]">
<option value="1">XXX</option>
<option value="2">XXX</option>
</select>
</div>
Thus the form is expecting directly an INT/ID.
By changing the JSON as follow it goes through validation :
{
"name": "XXXO",
"user": 1,
"description": "XXXXXXXXXXXXXXX",
"status": 1
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.