I'm working on some simple script, but can't wrap my head around this problem. So here it is.
/**
* Booking
* @ORM\Table()
* @ORM\Entity(repositoryClass="Tons\BookingBundle\Entity\BookingRepository")
* @UniqueEntity(fields={"room", "since", "till"}, repositoryMethod="getInterferingRoomBookings")
* @Assert\Callback(methods={"isSinceLessThanTill"}, groups={"search","default"})
*/
class Booking
and repository Method
/**
* Get room state for a certain time period
*
* @param array $criteria
* @return array
*/
public function getInterferingRoomBookings(array $criteria)
{
/** @var $room Room */
$room = $criteria['room'];
$builder = $this->getQueryForRoomsBooked($criteria);
$builder->andWhere("ira.room = :room")->setParameter("room", $room);
return $builder->getQuery()->getArrayResult();
}
The problem is that this works on create methods like it should, but when updating existing entity - it violates this constrain.
I tried to add Id constrain, but when creating entities, id is null, so repository Method don't even starts. Also i tried to remove Entity and then recreate it. like
$em->remove($entity);
$em->flush();
//-----------
$em->persist($entity);
$em->flush();
but this also does not work.
Create Action
/**
* Creates a new Booking entity.
*
* @Route("/create", name="booking_create")
* @Method("POST")
* @Template("TonsBookingBundle:Booking:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Booking();
$form = $this->createForm(new BookingType(), $entity);
$form->bind($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$room = $entity->getRoom();
if($room->getLocked() && $room->getLockedBy()->getId() === $this->getUser()->getId())
{
$entity->setCreatedAt(new \DateTime());
$entity->setUpdatedAt(new \DateTime());
$entity->setManager($this->getUser());
$em->persist($entity);
$room->setLocked(false);
$room->setLockedBy(null);
$room->setLockedAt(null);
$em->persist($room);
$em->flush();
return $this->redirect($this->generateUrl('booking_show', array('id' => $entity->getId())));
}
else
{
$form->addError(new FormError("Номер в текущий момент не заблокирован или заблокирован другим менеджером"));
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
Update Action
/**
* Edits an existing Booking entity.
*
* @Route("/edit/{id}/save", name="booking_update")
* @Method("PUT")
* @Template("TonsBookingBundle:Booking:edit.html.twig")
*/
public function updateAction(Request $request, $id)
{
/** @var $em EntityManager */
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('TonsBookingBundle:Booking')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Booking entity.');
}
$editForm = $this->createForm(new BookingType(), $entity);
$editForm->bind($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('booking_edit', array('id' => $id)));
}
return array(
'entity' => $entity,
'form' => $editForm->createView(),
);
}
Short answer: You're not getting the form data into the entity, so you are working with a new entity that does not know its room has been set in the form.
Long answer: Getting the form data and putting it into the entity allows you to manipulate the data before update. See modified controller below. Key line is
$entity = form->getData();
Which then allows you to$room=$entity->getRoom();
Pass an additional identifier (maybe a
token
) to the unique check field (for exampleloginName
) (fields={"token", "loginName"}
), to the repositoryMethod. Theid
itself is not working, it is null on object creation and the repositoryMethod is not executed. I create thetoken
in the constructor Method. The token is needed to identify the entity on creation or update action.then in repository class you edit the WHERE DQL:
I got this! I changed annotation to this
Copy BookingType to BookingTypeCreate And added
To form defaults. So now parameters are different when passing entity to validation method. I think it's still a workaround method.