Symfony 4 - Две сущности в одной форме с использованием доктрины, одна сущность должна вставляться перед другой

Я не могу заставить текстовое поле отображаться внутри моей формы при объединении двух объектов. Пожалуйста, без javascript, я видел метод javascript с коллекциями.

Логика заключается в том, что пользователь должен добавить заголовок в форму, а затем добавить текст в текстовое поле. Когда пользователь отправляет сообщение, поток вводится с использованием заголовка, а идентификатор потока используется для добавления к нему сообщения (содержимого текстового поля).

Пример формы:

Symfony 4 - Две сущности в одной форме с использованием доктрины, одна сущность должна вставляться перед другой


Я считаю, что этого достаточно для вывода, если он правильно настроен с помощью двух классов типа.

{{ form_start(forum_thread_form) }}
   {{ form_widget(forum_thread_form) }}
{{ form_end(forum_thread_form) }}

Код:

Сущности

Thread.php

     /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Account", inversedBy = "forum_posts")
     * @ORM\JoinColumn(nullable=false)
     */
    private $account;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Category", inversedBy = "forum_threads")
     * @ORM\JoinColumn(nullable=false)
     */
    private $category;

    /**
     * @ORM\Column(type = "string", length=128, nullable=true)
     * @Assert\NotBlank()
     */
    private $title;

    /**
     * @ORM\OneToMany(targetEntity = "App\Entity\Post", mappedBy = "thread")
     */
    private $posts;

    public function __construct()
    {
        $this->posts = new ArrayCollection();
    }

    ## getters and setters.. some ommitted ##
        /**

     /*
     * @return mixed
     */
    public function getPosts()
    {
        return $this->posts;
    }

    /**
     * @param mixed $posts
     */
    public function setPosts($posts): void
    {
        $this->posts = $posts;
    }

Post.php

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type = "integer")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Account", inversedBy = "forum_posts")
     * @ORM\JoinColumn(nullable=false)
     */
    private $account;

    /**
     * @ORM\ManyToOne(targetEntity = "App\Entity\Thread", inversedBy = "posts")
     * @ORM\JoinColumn(nullable=true)
     */
    private $thread;

    /**
     * @ORM\Column(type = "text")
     * @Assert\NotBlank()
     */
    private $content;

 ## GETTERS AND SETTERS, some ommitted ##
 /**
 * @return mixed
 */
public function getThread()
{
    return $this->thread;
}

/**
 * @param mixed $thread
 */
public function setThread($thread): void
{
    $this->thread = $thread;
}

/**
 * @return mixed
 */
public function getContent()
{
    return $this->content;
}

/**
 * @param mixed $content
 */
public function setContent($content): void
{
    $this->content = $content;
}

PostType.php

public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('content', TextareaType::class)
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Post::class,
        ));
    }

ThreadType.php

public function __construct(){
        $this->posts = new ArrayCollection();
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('title', TextType::class);

        $builder->add('content', CollectionType::class, array(
            'entry_type' => PostType::class,
            'entry_options' => array('label' => false),
        ));
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => Thread::class,
        ));
    }

ForumController.php

$forum_thread = new Thread();
$forum_thread_form = $this->createForm(ThreadType::class,$forum_thread);

        $forum_thread_form->handleRequest($request);

        if ($forum_thread_form->isSubmitted() && $forum_thread_form->isValid()) {
            $forum_thread = $forum_thread_form->getData();

            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($forum_thread);
            $entityManager->flush();

        }

        $forum_thread_form = $forum_thread_form->createView();

        return $this->render('forum/threads.html.twig',compact('forum_thread_form'));

Не могли бы вы связать свой контроллер?

Shaithya Kannan 14.05.2018 11:50

@ShaithyaKannan добавил код контроллера.

Darius 14.05.2018 11:53
Стоит ли изучать 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 и хотите разрабатывать...
1
2
1 341
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Отредактируйте свою ветку

{{ form_start(forum_thread_form) }}
   {{ form_row(forum_thread_form.title) }}
   {%  for contentField in forum_thread_form.posts %}
          {{ form_row(contentField.content) }}
   {%  endfor %}
{{ form_end(forum_thread_form) }}

Это все еще не сработало, мне пришлось установить "mapped" в false в ThreadType, а затем сохранить сообщение отдельно в контроллере, не смог сделать это сразу. тогда вывод был простым, для оператора не требовалось.

Darius 17.05.2018 10:59

@Darius Значит ли это, что вы решили свою проблему?

Philippe-B- 19.05.2018 15:41

Пока нет, обязательные поля не проверяются. Так что найденный мной метод работает некорректно. Я попробую метод DTO, на который ответил tarl выше.

Darius 20.05.2018 09:35

Я бы просто использовал single formtype + DTO для создания этой формы, а после подтверждения submit + просто создал эти необходимые сущности из этого DTO и сохранил + сбросил их в базу данных.

Когда я использую этот метод и создаю форму в контроллере, я делаю $ this-> createForm (ThreadType :: class, $ forum_thread) или без $ forum_thread? Я предполагаю, что $ forum_thread больше не требуется, поскольку он не привязан к сущности.

Darius 20.05.2018 09:37
Ответ принят как подходящий

Сначала в ThreadType измените content на posts:

$builder->add('posts', CollectionType::class, array(
        'entry_type' => PostType::class,
        'entry_options' => array('label' => false),
    ));

Затем измените код в своем действии:

$forum_thread = new Thread();
$post = new Post();
$forum_thread->setPosts([$post]);
$forum_thread_form = $this->createForm(ThreadType::class, $forum_thread);

$forum_thread_form->handleRequest($request);

if ($forum_thread_form->isSubmitted() && $forum_thread_form->isValid()) {
    $forum_thread = $forum_thread_form->getData();

    $entityManager = $this->getDoctrine()->getManager();
    $entityManager->persist($post);
    $entityManager->persist($forum_thread);
    $entityManager->flush();

}

Это работает:

  • создав новый пост
  • добавление массива, содержащего только новую созданную публикацию
  • getPosts используется для заполнения поля "сообщения" CollectionType новым PostType.

Технически это правильный ответ, и он работает, в итоге я использовал гибрид этого и DTO.

Darius 23.05.2018 03:35

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