After long time of lerking on these boards I have finally decided to make my first post. I have recently started to play around with Symfony (2.4, don't yell at me please :) ). Using doctrine's terminal commands I generated CRUD events. Now, that is great and all, except that you have to pass the ID in the url, for example: www.mydomain.com/account/16/. This will pre-fill the form with the data from a row that has id 16 in mysql. My question is, how do I manipulate the pre-made CRUD (only interested in the update) so that I don't have to pass the id to the url, but rather, it renders the form based on the id the logged in user has associated with their account?
Here is my code:
class AccountController extends Controller
{
/**
* Displays a form to edit an existing Event entity.
* #Route("/account/{id}", name="post_login_account_edit")
* #PreAuthorize("isFullyAuthenticated()")
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('UserBundle:User')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Event entity.');
}
$editForm = $this->createEditForm($entity);
return $this->render('UserBundle:Account:account.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView()
));
}
/**
* Creates a form to edit a Event entity.
*
* #param User $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createEditForm(User $entity)
{
$form = $this->createForm(new UserType(), $entity, array(
'action' => $this->generateUrl('post_login_account_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$form->add('submit', 'submit', array('label' => 'Update'));
return $form;
}
/**
* Edits an existing User entity.
* #Route("/account/{id}/update", name="post_login_account_update")
* #PreAuthorize("isFullyAuthenticated()")
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('UserBundle:User')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Event entity.');
}
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('post_login_account'));
}
return $this->render('UserBundle:Account:account.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView()
));
}
}
Simply get logged in user in controller:
$entity = $this->get('security.context')->getToken()->getUser();
Related
I am wondering if there is a way I can reduce my code without inheriting.
And what would be the best practice?
I am working with Symfony. I have old code and I need to do some forms.
Most of them are quite similar.
I have many controllers, and forms and only few differences among them.
Here is an example of a controller.
Only (NAMETOBECHANGED) changes among the controllers.
<?php
namespace Data\LiveBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;
use Data\LiveBundle\Entity\DataAPatient;
use Data\LiveBundle\Entity\DataDNaMETOBECHANGED;
/**
* DataDNaMETOBECHANGED controller.
*
*/
class DataDNaMETOBECHANGEDController extends Controller
{
/**
* Lists all DataDNaMETOBECHANGED entities.
*
*/
public function indexAction(Request $request, $limit, $offset)
{
$repo = $this->getDoctrine()->getManager()->getRepository('DataLiveBundle:DataDNaMETOBECHANGED');
$qb = $repo->getDefaultQuery();
return $this->renderIndex($repo, $qb, $limit, $offset, 'default');
}
/**
* Lists all DataDNaMETOBECHANGED entities sorted by a chosen column.
*
*/
public function indexSortAction(Request $request, $limit, $offset, $column){
$repo = $this->getDoctrine()->getManager()->getRepository('DataLiveBundle:DataDNaMETOBECHANGED');
$qb = $repo->getDefaultQueryOrdered($column);
return $this->renderIndex($repo, $qb, $limit, $offset, $column);
}
/**
* Renders the index page
*
*/
private function renderIndex($repo, $qb, $limit, $offset, $column)
{
//TODO: Add Access-Control
if (!$this->isAdmin()) {
throw new AccessDeniedException();
}
//model taken from Events
//$queryHelper = $this->get('general_commonbundle.util.queryhelper');
//$qb = $queryHelper->addProjectFilter($qb);
//if(!$this->isAdmin()){
//$qb = $queryHelper->addAccessControl($qb);
//}
$total = $repo->countQueryResults($qb);
$qb = $repo->addLimitToQuery($qb, $limit, $offset);
$paginationOptions = array(
'total' => $total,
'limit' => $limit,
'offset' => $offset
);
$entities = $repo->getResults($qb);
//TODO: lock dataset if 180 days passed.
$editable = array();
foreach($entities as $entity){
$this->isAdmin(); // TODO: owner check: $editable[$entity->getPKpPatientid()] = $this->isOwner($entity->getPKpPatientid())
}
// Disable softdelete filter, such that view can access all foreign keys.
// View needs to distinguish between still existent foreign keys and deleted ones.
$em = $this->getDoctrine()->getManager();
if (array_key_exists('softdeleteable', $em->getFilters()->getEnabledFilters())) {
$em->getFilters()->disable('softdeleteable');
}
return $this->render('DataLiveBundle:DataDNaMETOBECHANGED:index.html.twig', array(
'entities' => $entities,
'editable' => $editable,
'paginationOptions' => $paginationOptions,
'orderColumn' => $column,
'parentRoute' => $this->generateUrl('datadnaMeTOBECHANGED')
));
}
/**
* Finds and displays an DataDNaMETOBECHANGED entity.
*
*/
public function showAction($pKpPatientid)
{
if (!$this->isAdmin()) {
throw new AccessDeniedException();
}
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('DataLiveBundle:DataDNaMETOBECHANGED')->find($pKpPatientid);
if (!$entity) {
throw $this->createNotFoundException('Unable to find DataDNaMETOBECHANGED entity.');
}
// Access control
if($this->isAdmin() // || $this->isOwner($pKpPatientid)
) {
// allow access
}
else {
throw new AccessDeniedException();
}
// Disable softdelete filter, such that view can access all foreign keys.
// View needs to distinguish between still existent foreign keys and deleted ones.
if (array_key_exists('softdeleteable', $em->getFilters()->getEnabledFilters())) {
$em->getFilters()->disable('softdeleteable');
}
$editable = $this->isAdmin(); //$this->isOwner($entity->getPKpPatientid())
$print = $this->getRequest()->get('print') == '1';
return $this->render('DataLiveBundle:DataDNaMETOBECHANGED:show.html.twig', array(
'entity' => $entity,
'editable' => $editable,
'isPreview' => false,
'print' => $print,
));
}
/**
* Redirects to preview a new DataAPatient entity.
*
*/
public function newAction(Request $request)
{
if (!$this->isAdmin()) {
throw new AccessDeniedException();
}
$entity = new DataAPatient();
$em = $this->getDoctrine()->getManager();
$entity->setPDateOfBirth(new \DateTime('now'));
// $entity->setTimeStart(new \DateTime('now'));
// $entity->setTimeEnd(new \DateTime('now'));
$newForm = $this->createNewForm($entity);
$entity->setDatetimeCreated( new \DateTime('now') );
$entity->setDatetimeChanged (new \DateTime ('now'));
//TODO: set SNNID
$newForm->handleRequest($request);
if ($newForm->isValid()) {
if($newForm->get('submit')->isClicked()){//Save
$pKpPatientid = $this->storeNewDataAPatient($entity);
return $this->redirect($this->generateUrl('dataapatient_sendMessage', array("pKpPatientid" => $pKpPatientid)));
}
}
return $this->render('DataLiveBundle:DataDNaMETOBECHANGED:form.html.twig', array(
'entity' => $entity,
'form' => $newForm->createView(),
'isNew'=> true,
));
}
/**
* Creates a form to create a new DataAPatient entity.
*
* #param DataAPatient $entity The entity
*
* #return \Symfony\Component\Form\Form
*
*/
private function createNewForm(DataAPatient $entity)
{
$form = $this->createForm($this->get('data_livebundle.form.dataapatienttype'), $entity, array(
'action' => $this->generateUrl('dataapatient_new'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
/**
* Redirects to preview changes made to an existing DataDNaMETOBECHANGED entity.
*
*/
public function editAction(Request $request, $pKpPatientid)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('DataLiveBundle:DataDNaMETOBECHANGED')->find($pKpPatientid);
if (!$entity) {
throw $this->createNotFoundException('Unable to find DataDNaMETOBECHANGED entity.');
}
//Access control
if (!$this->isAdmin() //&& !$this->isOwner($pKpPatientid)
) {
throw new AccessDeniedException();
}
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
//Refresh Changed-Date
$entity->setDatetimeChanged( new \DateTime('now') );
//Set naMeTOBECHANGEDAgeRef in DataDNaMETOBECHANGED
$entity->getDNaMETOBECHANGED()->setNaMETOBECHANGEDAgeRef (round($entity->getDNaMETOBECHANGED()->getNaMETOBECHANGEDAgeCalc(),0));
if($editForm->get('submit')->isClicked()){//Save
$em->persist($entity);
//Store changes
$pKpPatientid = $this->storeEditedDataDNaMETOBECHANGED($entity);
//TODO: log changes in history
if($editForm->get('submit')->isClicked()){
return $this->redirect($this->generateUrl('datadnaMeTOBECHANGED_show', array('pKpPatientid' => $pKpPatientid)));
}
}
}
return $this->render('DataLiveBundle:DataDNaMETOBECHANGED:form.html.twig', array(
'entity' => $entity,
'form' => $editForm->createView(),
'isNew' => false,
));
}
/**
* Creates a form to edit a DataDNaMETOBECHANGED entity.
*
* #param DataDNaMETOBECHANGED $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createEditForm(DataDNaMETOBECHANGED $entity)
{
$form = $this->createForm($this->get('data_livebundle.form.datadnaMeTOBECHANGEDtype'), $entity, array(
'action' => $this->generateUrl('datadnaMeTOBECHANGED_edit', array('pKpPatientid' => $entity->getPKpPatientid())),
'method' => 'POST'
));
$form->add('submit', 'submit', array('label' => 'Save Changes'));
return $form;
}
/**
* Persists changes made to an existing DataDNaMETOBECHANGED entity to the database
*
*/
private function storeEditedDataDNaMETOBECHANGED($entity)
{
$em = $this->getDoctrine()->getManager();
$session = $this->getRequest()->getSession();
if (!$entity) {
throw $this->createNotFoundException('Unable to find DataDNaMETOBECHANGED entity.');
}
$pSnnid = $entity->getPSnnid();
$em->persist($entity);
$em->flush();
$session->getFlashBag()->add(
'notice',
'Your changes to the DataDNaMETOBECHANGED of ID: "'.$pSnnid. '" was saved!'
);
return $entity->getPKpPatientid();
}
/**
* Persists a new DataDNaMETOBECHANGED entity to the database
*
*/
private function storeNewDataDNaMETOBECHANGED($entity)
{
$em = $this->getDoctrine()->getManager();
$session = $this->getRequest()->getSession();
if (!$entity) {
throw $this->createNotFoundException('Unable to find DataDNaMETOBECHANGED entity.');
}
$pSnnid = $entity->getPSnnid();
$em->persist($entity);
$em->flush();
$session->getFlashBag()->add(
'notice', 'The new DataDNaMETOBECHANGED for "'.$pSnnid. '" was saved!'
);
return $entity->getPKpPatientid();
}
/**
* Removes hospital entity from the database by pKpPatientid
*
*/
public function deleteAction(Request $request, $pKpPatientid)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('DataLiveBundle:DataDNaMETOBECHANGED')->find($pKpPatientid);
if (!$entity) {
throw $this->createNotFoundException('Unable to find DataDNaMETOBECHANGED entity.');
}
//Access control
if (!$this->isAdmin()) {
throw new AccessDeniedException();
}
$pSnnid = $entity -> getPSnnid();
$em->remove($entity);
$em->flush();
$this->getRequest()->getSession()->getFlashBag()->add(
'notice',
'The DataDNaMETOBECHANGED for "'.$pSnnid.'" was deleted successfully!'
);
return $this->redirect($this->generateUrl('datadnaMeTOBECHANGED'));
}
/**
* Returns whether current user has role ROLE_ADMIN
*
* #return boolean
*/
private function isAdmin()
{
return $this->get('security.context')->isGranted('ROLE_ADMIN');
}
/**
* Returns whether current user has ID '$pKpPatientid'
*
* #param mixed $pKpPatientid The entity id which current user wants to edit
*
* #return boolean
*/
private function isOwner($pKpPatientid)
{
$em = $this->getDoctrine()->getManager();
// Disable softdeletable filter (only if it's not already inactive)
if (array_key_exists('softdeleteable', $em->getFilters()->getEnabledFilters())) {
$em->getFilters()->disable('softdeleteable');
}
$entity = $em->getRepository('DataLiveBundle:DataDNaMETOBECHANGED')->find($pKpPatientid);
$result = $entity->getFKOwner()->getPKpPatientid() == $this->get('security.context')->getToken()->getUser()->getPKpPatientid();
// Enable softdeletable filter before returning
$em->getFilters()->enable('softdeleteable');
return $result;
}
}
And for HTML, here is an example:
<div class='col-xs-4'>
<div class='col-xs-7'>{{ form_label(form.dFu2.fu2MdiRaw, 'Cognitive RAW score:', {'label_attr':{'style':'margin-top:3px'}})}}</div>
<div class='col-xs-2'>{{ form_widget(form.dFu2.fu2MdiRaw, {'attr':{'style':'width:50px'}})}}</div>
</div>
This kind of piece of code repeats itself a lot among the forms. And in each for most of the time only fu1, fu2, fu3, ... change.
Thank your for your advice!
I'm facing a problem like the one posted here but since I have not a UserFormType I don't know how to solve this. The idea is not to ask for password each time I (logged in as admin and with right permissions) will change a user profile field like email for example. This is my code:
public function editAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('UserBundle:User')->find($id);
/** #var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->container->get('fos_user.profile.form.factory');
$form = $formFactory->createForm();
$form->setData($user);
if ('POST' === $request->getMethod())
{
$form->handleRequest($request);
if ($form->isValid())
{
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->container->get('fos_user.user_manager');
$userManager->updateUser($user);
}
}
return array(
'form' => $form->createView(),
'id' => $user->getId()
);
}
Resuming, how do I avoid ask for password each time I want to update a user profile, any help?
So it looks like the problem stems from the fact you're letting FOSUserBundle do everything for you, which is fair enough but makes it harder to tweak behaviour. You can override various things to change how it works, but my own application doesn't use FOSUserBundle at all for managing users after they're registered, you can simply create your own simple form to do it, e.g.:
class UserType extends AbstractType{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('username', 'text')
->add('email', 'email')
->add('save', 'submit');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Your\Bundle\Entity\User',
));
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return 'user';
}
}
And then your controller would stay reasonably similar, except no separate Form Factory needed and use your UserType:
public function editAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$user = $em->getRepository('UserBundle:User')->find($id);
/** #var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
//Don't need this!
//$formFactory = $this->container->get('fos_user.profile.form.factory');
//$form = $formFactory->createForm();
//$form->setData($user);
$form = $this->createForm(new UserType(), $user);
if ('POST' === $request->getMethod())
{
$form->handleRequest($request);
if ($form->isValid())
{
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->container->get('fos_user.user_manager');
$userManager->updateUser($user);
}
}
return array(
'form' => $form->createView(),
'id' => $user->getId()
);
}
Not sure of the detail of your View etc, but you just need to render the Form and things should be golden!
Hope I haven't got the wrong end of the stick.
I have made a CRUD for my question object. An error occurred once I tested it.
It seems that the getId() is returning an empty string of some sort.
The default behavior of the autogenerated CRUD is to redirect the user to the view page after successfully creating the entity. But in this case, it returns an error
"Parameter "id" for route "question_show" must match "[^/]++" ("" given) to generate a corresponding URL."
Here is my controller code:
/**
* Creates a new Question entity.
*
* #Route("/ask", name="question_create")
* #Method("POST")
* #Template("VerySoftAskMeBundle:Question:ask.html.twig")
*/
public function createAction(Request $request) {
$entity = new Question();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('question_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
Here is the view action:
/**
* Finds and displays a Question entity.
*
* #Route("/{id}", name="question_show")
* #Method("GET")
* #Template()
*/
public function showAction($id) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('VerySoftAskMeBundle:Question')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Question entity.');
}
$deleteForm = $this->createDeleteForm($id);
return array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
);
}
/**
* Creates a form to create a Question entity.
*
* #param Question $entity The entity
*
* #return Form The form
*/
private function createCreateForm(Question $entity) {
$form = $this->createForm(new QuestionType(), $entity, array(
'action' => $this->generateUrl('question_create'),
'method' => 'POST',
'em' => $this->getDoctrine()->getEntityManager()
));
$form->add('submit', 'submit', array('label' => 'Ask'));
return $form;
}
How can I fix this?
It seems that your entity is not persisted in the database. Could you check it?
Also, it seems to be a typo in your code your wrote "$form = $this->createCreateForm($entity);", instead of $this->createForm
Otherwise I have used the code below (similar to yours) with no problem
/**
* #Route("/new", name="item_new")
* #Template()
*
* #return array
*/
public function newAction(Request $request)
{
$em = $this->get('doctrine.orm.entity_manager');
$item = new Item();
$form = $this->createForm(new ItemType(), $item, array(
'action' => $this->generateUrl('item_new'),
'method' => 'POST',
));
$form->handleRequest($request);
if ($form->isValid()) {
$em->persist($item);
$em->flush();
return $this->redirect($this->generateUrl('item_list'));
}
return array('form' => $form->createView());
}
Fixed it. I was inheriting a class named Post which has an $id variable. Turns out that I forgot to delete the $id variable in my Question class which is why Symfony gets confused on what id to return.
I have a strange problem. I'm working on a Symfony 2 based web app and I embedding a from collection to another one based on the Symfony Cookbook entry (This: http://symfony.com/doc/2.3/cookbook/form/form_collections.html ).
Recently I changed my bundle's mapping data to annotation from yaml.
The problem starts here. Persisting new elements works fine, but I can't remove anything.
I have a Page entity and an Image entity and they have a many to many relation. I embed and image upload form collection to the Page's form.
The old mapping was invalid, the new one is valid but doesn't work.
Here are my old and new mappings:
old yml:
page:
manyToMany:
images:
targetEntity: Image
inversedBy: page
cascade: [persist, remove]
orderBy:
image_order: DESC
no mapping on the image
New mapping:
Page:
/**
* #ORM\ManyToMany(targetEntity="Image", inversedBy="pages", cascade={"persist", "remove"})
* #ORM\JoinTable(name="page_image",
* joinColumns={#ORM\JoinColumn(name="page_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="image_id", referencedColumnName="id")}
* )
* #ORM\OrderBy({"image_order" = "DESC"})
*/
protected $images;
Image:
/**
* #ORM\ManyToMany(targetEntity="Page", mappedBy="images")
*/
protected $pages;
The action that handles the edit form submission:
/**
* Edits an existing Page entity.
*
* #Route("/{id}/update", name="page_update")
* #Method("post")
* #Template("AdamantiumBackendBundle:Page:edit.html.twig")
*/
public function updateAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AdamantiumBackendBundle:Page')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Page entity.');
}
$editForm = $this->createForm(new PageType(), $entity);
$deleteForm = $this->createDeleteForm($id);
$request = $this->getRequest();
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
apc_clear_cache('user');
return $this->redirect($this->generateUrl('page_edit', array('id' => $id)));
}
return $this->render('AdamantiumBackendBundle:Page:edit.html.twig',array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
The embeded collection from the Page form:
->add('images', 'collection', array('type' => new ImageType(),
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'options' => array('data_class' => 'Adamantium\BackendBundle\Entity\Image'),
))
I have the add and remove Images methods, I have getters and setters. (and as I said earlier everything worked fine with the invalid yml mapping)
So please tell me what am I missing or what do I do wrong.
Thanks!!
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(),
);
}
I got this!
I changed annotation to this
/**
* Booking
* #ORM\Table()
* #ORM\Entity(repositoryClass="Tons\BookingBundle\Entity\BookingRepository")
* #UniqueEntity(fields={"id","room", "since", "till"}, repositoryMethod="getInterferingRoomBookings")
* #UniqueEntity(fields={"room", "since", "till"}, repositoryMethod="getInterferingRoomBookings",groups={"create"})
* #Assert\Callback(methods={"isSinceLessThanTill"}, groups={"search","default"})
*/
class Booking
Copy BookingType to BookingTypeCreate And added
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Tons\BookingBundle\Entity\Booking',
'validation_groups' => array('create'),
));
}
To form defaults. So now parameters are different when passing entity to validation method.
I think it's still a workaround method.
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();
/**
* 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);
$entity = $form->getData(); // Lighthart's addition
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(),
);
}
Pass an additional identifier (maybe a token) to the unique check field (for example loginName) (fields={"token", "loginName"}), to the repositoryMethod. The id itself is not working, it is null on object creation and the repositoryMethod is not executed. I create the token in the constructor Method. The token is needed to identify the entity on creation or update action.
/**
* #ORM\Table(name="anbieterregistrierung")
* #ORM\Entity(repositoryClass="AnbieterRegistrierungRepository")
* #UniqueEntity(
* fields={"token", "loginName"},
* repositoryMethod="findUniqueEntity"
* )
*/
then in repository class you edit the WHERE DQL:
public function findUniqueEntity(array $parameter)
{
$loginName = $parameter['loginName'];
$token = $parameter['token'];
.
.
.
. . . WHERE anbieterregistrierung.loginName = :loginName AND anbieterregistrierung.token <> :token
.
.
.
}