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

How do you pass the parent entity to a form in Symfony?

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

简单的东西。至少,它应该是,但我无法让它工作。

如何在创建评论(子)时引用 post(父)? 我尝试手动将 post_id 传递给评论表单作为隐藏字段,但收到一个错误,抱怨 post 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');
}

非常感谢您的帮助!

您只需要传递实际的 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
}

这段代码对我有用:

CommentController.php

正如上面 flint 所建议的,您只需要传递实际的 Post 实体,而不仅仅是 id。那么如果你有这个错误 "Unable to guess how to get a Doctrine instance from the request information for parameter "post" 这是因为你需要在 new_comment 的路径中添加 post slug 路线。 ParamConverter 被隐式​​调用,它需要这个 slug {post} 与您用于 post[= 的名称相同33=]函数中的参数。

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

这样就不需要去掉两个表之间的Doctrine关系,手动设置ID了。

不要输入表单域, 例如

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

错误消息说明了一切:

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

如果您转到您的评论实体 (App\Entity\Comment),您会看到您的 class 将父 post 引用为 Post Class (App\Entity\Post) 而不是 "post_id"。

在您的物理数据库和实体 class 中执行 link 并在您的 [=38] 中添加一个 post_id 字段的是 ORM(本例中的原则) =].

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

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

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

其中 $post 是 class Post 的实例。