您如何将父实体传递给Symfony中的表单?

时间:2018-11-04 23:30:17

标签: php symfony symfony4

假设我有两个实体:postcomment。每个post可以有多个comments。现在,假设我有一个评论表。应该接受用户输入并将其存储在数据库中。

简单的东西。至少应该如此,但我无法使其正常工作。

在创建评论(子级)时如何参考帖子(父级)?我尝试将post_id手动传递给评论表单作为隐藏字段,但是收到了抱怨帖子ID是字符串的错误。

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 (在此处显示评论表单)

// 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');
}

非常感谢您的帮助!

4 个答案:

答案 0 :(得分:4)

您只需要传递实际的Post实体,而不仅仅是ID。试试这个:

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');
}

评论类型

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
     ]);
}

评论实体

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
}

答案 1 :(得分:1)

此代码对我有用:

CommentController.php

正如上面的flint所建议的,您只需要传递实际的Post实体,而不仅仅是id。然后,如果您遇到此错误template <typename MapLike, typename KeyLike> void do_stuff(const MapLike & map, const KeyLike & key) { auto range = map.equal_range(key); for (auto it = range.first; it != range.second; ++it) // blah } ,这是因为您需要在 new_comment 路线的路径中添加 post 条。 ParamConverter被隐式调用,它需要该段 {post} ,其名称与函数中用于 post 参数的名称相同。

"Unable to guess how to get a Doctrine instance from the request information for parameter "post"

PostController.php

/**
 * @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');
}

CommentType.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()
    ]);

 }

使用此方法,您无需删除两个表之间的Doctrine关系并手动设置ID。

答案 2 :(得分:0)

请勿输入表单字段, 例如

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())
    {
        comment->setPostId($post_id)
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->persist($comment);
        $entityManager->flush();
    }

    return $this->redirectToRoute('homepage');
}

答案 3 :(得分:0)

错误消息说明了一切:

Expected argument of type "App\Entity\Post or null", "string" given.

如果转到注释实体(App \ Entity \ Comment),您会看到您的类将父帖子称为Post类(App \ Entity \ Post),而不是“ post_id”。

由ORM(在本例中为原则)在您的物理数据库和Entity类中进行链接,并在表中添加post_id字段。

这是ORM(对象关系模型)的用途。您不应再将Post和Comment视为Sql表,而应视为类(OOP)。

因此,我想添加与someParent相关的评论,我应该这样做:

$comment = new Comment();
$comment->setPost($post);

$ post是Post类的实例。