Как передать родительский объект в форму в Symfony?

Предположим, у меня есть две сущности: post и comment. Каждый post может иметь несколько comments. Теперь предположим, что у меня есть форма для комментариев. Предполагается, что пользовательский ввод будет сохранен в базе данных.

Все просто. По крайней мере, так должно быть, но я не могу заставить его работать.

Как я могу ссылаться на сообщение (родительский) при создании комментария (дочернего)? Я попытался вручную передать 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.

Ben 05.11.2018 00:39
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
8
1
1 115
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Вам просто нужно передать фактическую сущность Post, а не только идентификатор. Попробуй это:

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

Комментарий

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
}

Спасибо за помощь. Однако это не работает. $post_id не определен в CommentType, и если я определяю его как Post, а не как идентификатор (string / int), я получаю ошибку преобразования типа.

Nathanael 12.11.2018 19:23

Кроме того, у меня нет PostInterface, если за кулисами не происходит чего-то, чего я не понимаю.

Nathanael 12.11.2018 19:31

Использование интерфейса - лучшая практика, но вам не обязательно, вы можете напечатать сущность. Я изменил свой ответ, чтобы также показать класс комментариев. Подробнее здесь: symfony.com/doc/current/doctrine/associations.html

flint 12.11.2018 20:42

Спасибо, но мой комментарий уже настроен таким образом. Проблема заключается (я полагаю) в этой строке: ->add('post', HiddenType::class, ['data' => $post_id]);. $ post_id не существует.

Nathanael 18.11.2018 18:03

Тебе эта строчка не нужна, я исправил ответ. Вы устанавливаете сообщение с помощью $ comment-> setPost ($ post);

flint 19.11.2018 13:00

Спасибо за всю твою помощь. Однако это еще не работает. Я получаю эту ошибку: "Unable to guess how to get a Doctrine instance from the request information for parameter "post". Если я удалю параметр $ post и вместо этого вручную создаю объект Post, я получаю вместо этого эту ошибку: A new entity was found through the relationship 'App\Entity\Comment#post' that was not configured to cascade persist operations for entity [...].

Nathanael 22.11.2018 02:12

На этом этапе я могу просто удалить связь Doctrine между двумя таблицами и вручную установить идентификатор. Я бы предпочел научиться делать это правильно.

Nathanael 22.11.2018 02:12
Ответ принят как подходящий

Этот код работает для меня:

CommentController.php

Как было предложено флинтом выше, вам просто нужно передать фактическую сущность Post, а не только идентификатор. Тогда, если у вас есть эта ошибка "Unable to guess how to get a Doctrine instance from the request information for parameter "post", это связано с тем, что вам нужно добавить слаг Почта в путь маршрута new_comment. ParamConverter вызывается неявно, и ему нужен этот слаг {Почта} с тем же именем, что и имя, которое вы использовали для параметра Почта в функции.

/**
 * @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 между двумя таблицами и вручную устанавливать идентификатор.

Не помещайте в поле формы, Например

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.

Если вы перейдете к своему комментарию Entity (App \ Entity \ Comment), вы увидите, что ваш класс ссылается на родительский пост как на Post Class (App \ Entity \ Post), а не как на «post_id».

Именно ORM (в данном случае доктрина) устанавливает связь в вашей физической базе данных и ваших классах Entity и добавляет поле post_id в вашу таблицу.

Это то, для чего нужна ORM (объектная реляционная модель). Вы должны больше рассматривать сообщения и комментарии не как таблицы Sql, а как классы (ООП).

Таким образом, я хочу добавить комментарий, связанный с someParent, я должен сделать что-то вроде:

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

Где $ post - это экземпляр класса Post.

Другие вопросы по теме