Symfony: проблема с формой ManyToOne

У меня есть две сущности под названием Ticket и TicketUpdate. У каждого тикета может быть много TicketUpdate, но у каждого TicketUpdate может быть только 1 Ticket.

Далее у меня есть форма, которая показывает текущий билет, но также позволяет мне добавить 1 TicketUpdate и изменить атрибуты билета.

Это мой контроллер:

//TicketController.php

...

/**
 * @Route("/ticket/{id}", name = "app_ticket")
 */
public function ticket(Request $request, Ticket $ticket)
{
    $ticketUpdate = new TicketUpdate();
    $ticketUpdate->setTicket($ticket);

    $form = $this->createForm(TicketUpdateType::class, $ticketUpdate); //custom form type
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($ticketUpdate);
        $em->persist($ticket);
        $em->flush();
    }

    return $this->render('ticket/view.html.twig', ['ticket' => $ticket, 'form' => $form->createView()]);
}

...

Тип обновления билета:

//TicketUpdateType.php

...

class TicketUpdateType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder
            ->add('text', TextareaType::class, ['label' => 'update', 'required' => false, 'attr' => ['class' => 'textarea-sm'])
            ->add('ticket', TicketType::class, ['label' => false, 'by_reference' => false]) //custom Type for Tickets
            ->add('submit', SubmitType::class, ['label' => 'save']);
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults([
            'data_class' => TicketUpdate::class
        ]);
    }
}

...

Однако это решение работает для меня нет. Symfony всегда хочет создать запись новый Ticket вместо изменения старой.

Есть ли способ исправить это?

вы пробовали без $em->persist($ticket); ? Symfony должен автоматически обрабатывать это, когда вы делаете $em->persist($ticketUpdate);

Unex 22.07.2019 09:36

Я бы предположил, что ваш setTicket или что-то связанное делает что-то странное. Или Билет, выданный на маршрут, не является управляемым. Doctrine не будет создавать новую запись тикета, если объект уже находится под управлением.

Jakumi 22.07.2019 09:45

Symfony довольно странный в этом случае. Иногда он буквально ничего не делает. Он просто перезагружает форму с данными, которые я ввел, и иногда я получаю следующую ошибку: новый объект был найден через отношение «App\Entity\TicketUpdate#ticket», который не был настроен для каскадного сохранения операций для объекта: App\Entity\Ticket @000000000b6938470000000073fc59d8. Чтобы решить эту проблему: либо явно вызовите EntityManager#persist() для этого неизвестного объекта, либо настройте каскадное сохранение этого .... Когда я добавлю каскадное, он также создаст запись новый вместо изменения старой.

Syllz 22.07.2019 09:46

Я почти уверен, что Ticket управляется. По крайней мере, создание новых объектов Ticket, а также редактирование работает нормально (также с формами). Может быть, проблема в моем TicketUpdateType? Я добавлю это к моему вопросу, может быть, кто-то может заметить ошибку.

Syllz 22.07.2019 09:55
Стоит ли изучать 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 и хотите разрабатывать...
0
4
59
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Обновлять: Я изменил by_reference на истинный и удалил всю логику в моем TicketType, которая, казалось, вызывала проблему.

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

//TicketController.php

...

/**
 * @Route("/ticket/{id}", name = "app_ticket")
 */
public function ticket(Request $request, Ticket $ticket)
{
    $ticketUpdate = new TicketUpdate();
    $ticketUpdate->setTicket($ticket);

    $form = $this->createForm(TicketUpdateType::class, $ticketUpdate); //custom form type
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($ticketUpdate);
        //$em->persist($ticket); -> removed, will be automatically updated by symfony
        $em->flush();
    }

    return $this->render('ticket/view.html.twig', ['ticket' => $ticket, 'form' => $form->createView()]);
}

...

Знаете ли вы, магия с формами symfony, с помощью которой вы можете получить Entity (Ticket), как в вашем примере, я не знаю... но это будет работать:

/**
* @Route("/ticket/{ticketId}", name = "app_ticket", requirements = {"ticketId" = "\d+"})
*/
public function ticket(Request $request, int $ticketId = 0)
{
    $em = $this->getDoctrine()->getManager();

    $ticket = $em->getRepository(Ticket::class)
    ->findOneBy([
        'id' => $ticketId
    ]);

    if ($ticket instanceof Ticket === false)
    {
        die('Ticket dont exist with the requested ID.'); #Just return here some error message
    }

    $ticketUpdate = new TicketUpdate();

    //Because your setTicket() setter inside your TicketUpdate Entity
    //sure have nullable typehinted argument (?Ticket $ticket)
    //if this is a valid doctrine relationship
    //(but if i'm wrong, please show the touched parts of your TicketUpdate entity)
    $ticketUpdate->setTicket($ticket); #<-- here is an "old" Ticket $ticket

    $form = $this->createForm(TicketUpdateType::class, $ticketUpdate); //custom form type
    $form->handleRequest($request);

    if ($form->isSubmitted() && $form->isValid())
    {
        $em->persist($ticketUpdate);

        //I'm working a lot with doctrine relationships
        //In many time necessary using a setter in the both Entity
        $ticket->addTicketUpdate($ticketUpdate); #You know this setter! Change, if my tip wrong
        $em->persist($ticket);
        $em->flush();
    }

    return $this->render('ticket/view.html.twig', [
        //Now, this is an instance of the Ticket
        //not an int ID!
        //so if you need the ID, you can get in twig, like:
        //{{ ticket.id }}
        'ticket' => $ticket, #Or: $ticket->getId()
        'form' => $form->createView()
    ]);
}

Требования внутри @route означают, что метод будет работать только на страницах, где {ticketId} является числовым.

Спасибо за ваш удивительный ответ. К сожалению, это не работает для меня. Билетный объект не будет сохранен. Еще одна вещь, которую я заметил, это то, что моя форма иногда, похоже, не соответствует части if (форма действительна и отправлена). Это действительно сбивает с толку, так как я понятия не имею, что symfony делает в фоновом режиме.

Syllz 22.07.2019 10:42

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