У меня есть две сущности под названием 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 вместо изменения старой.
Есть ли способ исправить это?
Я бы предположил, что ваш setTicket или что-то связанное делает что-то странное. Или Билет, выданный на маршрут, не является управляемым. Doctrine не будет создавать новую запись тикета, если объект уже находится под управлением.
Symfony довольно странный в этом случае. Иногда он буквально ничего не делает. Он просто перезагружает форму с данными, которые я ввел, и иногда я получаю следующую ошибку: новый объект был найден через отношение «App\Entity\TicketUpdate#ticket», который не был настроен для каскадного сохранения операций для объекта: App\Entity\Ticket @000000000b6938470000000073fc59d8. Чтобы решить эту проблему: либо явно вызовите EntityManager#persist() для этого неизвестного объекта, либо настройте каскадное сохранение этого .... Когда я добавлю каскадное, он также создаст запись новый вместо изменения старой.
Я почти уверен, что Ticket управляется. По крайней мере, создание новых объектов Ticket, а также редактирование работает нормально (также с формами). Может быть, проблема в моем TicketUpdateType? Я добавлю это к моему вопросу, может быть, кто-то может заметить ошибку.






Обновлять: Я изменил 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 делает в фоновом режиме.
вы пробовали без $em->persist($ticket); ? Symfony должен автоматически обрабатывать это, когда вы делаете $em->persist($ticketUpdate);