Suppose I have two entities: a post
and a comment
. Each post
can have many comments
. Now, suppose I have a comment form. It is supposed to take user input and store it in the database.
Simple stuff. At least, it should be, but I can't get it to work.
How do I refer to the post (parent) when creating the comment (child)? I tried manually passing the post_id
to the comment form as a hidden field, but received an error complaining about how the post ID is a string.
Expected argument of type "App\Entity\Post or null", "string" given.
CommentType.php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$post_id = $options['post_id'];
$builder->add('content', TextareaType::class, [
'constraints' => [
new Assert\NotBlank(['message' => 'Your comment cannot be blank.']),
new Assert\Length([
'min' => 10,
'minMessage' => 'Your comment must be at least {{ limit }} characters long.',
]),
],
])->add('post', HiddenType::class, ['data' => $post_id]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Comment::class,
'post_id' => NULL,
]);
}
PostController.php (this is where the comment form appears)
// Generate the comment form.
$comment = new Comment();
$form = $this->createForm(CommentType::class, $comment, [
'action' => $this->generateUrl('new_comment'),
'post_id' => $post_id,
]);
CommentController.php
/**
* @param Request $request
* @Route("/comment/new", name="new_comment")
* @return
*/
public function new(Request $request, UserInterface $user)
{
// 1) Build the form
$comment = new Comment();
$form = $this->createForm(CommentType::class, $comment);
// 2) Handle the submit (will only happen on POST)
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// 3) Save the comment!
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($comment);
$entityManager->flush();
}
return $this->redirectToRoute('homepage');
}
Thank you very much for your help!
You just need to pass the actual Post
entity, not just the id. Try this:
CommentController.php
public function new(Request $request, UserInterface $user, Post $post)
{
// 1) Build the form
$comment = new Comment();
$comment->setPost($post); //where $post is instance of App\Entity\Post
$form = $this->createForm(CommentType::class, $comment);
// 2) Handle the submit (will only happen on POST)
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// 3) Save the comment!
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($comment);
$entityManager->flush();
}
return $this->redirectToRoute('homepage');
}
CommentType
public function buildForm(FormBuilderInterface $builder, array $options)
{
//don't need to set the $post here
$builder->add('content', TextareaType::class, [
'constraints' => [
new Assert\NotBlank(['message' => 'Your comment cannot be blank.']),
new Assert\Length([
'min' => 10,
'minMessage' => 'Your comment must be at least {{ limit }} characters long.',
]),
],
]);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Comment::class
//don't need the default here either
]);
}
Comment Entity
class Comment
{
/**
* @ORM\ManyToOne(targetEntity="App\Entity\Post")
*/
private $post;
//other vars
public function setPost(\App\Entity\Post $post): void
{
$this->post = $post;
}
public function getPost(): \App\Entity\Post
{
return $this->post;
}
//other functions
}
This code works for me:
CommentController.php
As suggested by flint above, you just need to pass the actual Post entity, not just the id. Then if you have this error "Unable to guess how to get a Doctrine instance from the request information for parameter "post"
this is because you need to add the post slug in the path of the new_comment route. The ParamConverter is called implicitly and it need this slug {post} with the same name as the name you used for the post parameter in the function.
/**
* @param Request $request
* @return \Symfony\Component\HttpFoundation\RedirectResponse
* @Route("/comment/new/{post}", name="new_comment")
*/
public function new(Request $request, Post $post)
{
$comment = new Comment();
$comment->setPost($post); //where $post is instance of App\Entity\Post
$form = $this->createForm(CommentType::class, $comment);
// 2) Handle the submit (will only happen on POST)
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
// 3) Save the comment!
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($comment);
$entityManager->flush();
}
return $this->redirectToRoute('homepage');
}
PostController.php
/**
* @Route("/post/{id}", name="get_post")
*/
public function getPostAction(Post $post)
{
// Generate the comment form.
$comment = new Comment();
$form = $this->createForm(CommentType::class, $comment, [
'action' => $this->generateUrl('new_comment', ['post' => $post->getId()]),
]);
return $this->render('listeArticles.html.twig', [
'form' => $form->createView()
]);
}
CommentType.php
class CommentType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//don't need to set the $post here
$builder
->add('content', TextareaType::class, [
'constraints' => [
new Assert\NotBlank(['message' => 'Your comment cannot be blank.']),
new Assert\Length([
'min' => 10,
'minMessage' => 'Your comment must be at least {{ limit }} characters long.',
]),
],
])
->add('submit', SubmitType::class);
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Comment::class
]);
}
}
With this you don't need to remove the Doctrine relationship between the two tables and manually set an ID.
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