symfony controllerAction persist several times alike object - symfony

In my controller there is a rather classic action "create" based on Doctrine CRUD generation.
But when I execute this action by clicking the "create" form button several times the same object is created as many times as I clicked.
This is a major problem because my class "Operation" is quite large and takes a long time to record. The user is very tempted to click several times.
/**
* Creates a new Operation entity.
*
* #Route("/", name="operation_create")
* #Method("POST")
* #Template("MyApplicationBundle:Operation:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Operation();
$form = $this->createForm(new OperationType(), $entity, array(
'em' => $this->getDoctrine()->getManager(),
));
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity->setdateCreation(new \DateTime())
->setUser($this->get('security.context')->getToken()->getUser());
$em->persist($entity);
$em->flush();
$this->get('session')->getFlashBag()->add('success', 'OK');
return $this->redirect($this->generateUrl('operation_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
If anyone can help me it would be really nice.

After click on create button you must disabled or remove them with JavaScript, and user can't click second time at it.
If you use jQuery:
<input type="submit" onclick="jQuery(this).attr('disabled', 'disabled')">

Related

Automatically set related entity id in one to many relationship Symfony

I have a many to one related entities and everytime I create a new comment which is related to Project, I want to automatically save the realted project_id.
comment
id
comment
manyToOne
project:
targetEntity: Project
cascade: { }
mappedBy: null
inversedBy: comments
joinColumn:
name: project_id
referencedColumnName: id
orphanRemoval: false
project
id
projectName
oneToMany:
comments:
targetEntity: Comment
mappedBy: project
When using Annotation, this can be done easily using the ParamConverter, but in this case I am using Yaml format.I am using the Symfony nice Crud command to automatically generate forms and templates as well as the controllers.
I tried in controller this way
public function createAction(Request $request, Project $project)//Project
{
$entity = new Comment();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
// $entity->setProject($projectName->getProject());
$entity->setProject($project);
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('comment_show', array('id' => $entity->getId())));
}
Then in form,
{{ form(form) }}
The problem with this is it will generate a form with a dropdown with hundreds of project_id in comment project_id field
Then when submitted
Unable to guess how to get a Doctrine instance from the request information.
I am thinking of writing a jquery autocomplete to solve this but if there is more shortcut way of doing this, like the annotation Paramconverter, I am glad to use it
How would you do it so that the related project_id will be automatically saved?
Update
This is exactly the code when running Symfony2 nice crud command in console
<?php
namespace EdgeWeb\Project\EmployeeBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use EdgeWeb\Project\EmployeeBundle\Entity\Comment;
use EdgeWeb\Project\EmployeeBundle\Form\CommentType;
/**
* Comment controller.
*
*/
class CommentController extends Controller
{
/**
* Lists all Comment entities.
*
*/
public function indexAction()
{
$em = $this->getDoctrine()->getManager();
$entities = $em->getRepository('EmployeeBundle:Comment')->findAll();
return $this->render('EmployeeBundle:Comment:index.html.twig', array(
'entities' => $entities,
));
}
/**
* Creates a new Comment entity.
*
*/
public function createAction(Request $request)
{
$entity = new Comment();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('comment_show', array('id' => $entity->getId())));
}
return $this->render('EmployeeBundle:Comment:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Creates a form to create a Comment entity.
*
* #param Comment $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createCreateForm(Comment $entity)
{
$form = $this->createForm(new CommentType(), $entity, array(
'action' => $this->generateUrl('comment_create'),
'method' => 'POST',
));
$form->add('submit', 'submit', array('label' => 'Create'));
return $form;
}
/**
* Displays a form to create a new Comment entity.
*
*/
public function newAction()
{
$entity = new Comment();
$form = $this->createCreateForm($entity);
return $this->render('EmployeeBundle:Comment:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
/**
* Finds and displays a Comment entity.
*
*/
public function showAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('EmployeeBundle:Comment')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Comment entity.');
}
$deleteForm = $this->createDeleteForm($id);
return $this->render('EmployeeBundle:Comment:show.html.twig', array(
'entity' => $entity,
'delete_form' => $deleteForm->createView(),
));
}
/**
* Displays a form to edit an existing Comment entity.
*
*/
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('EmployeeBundle:Comment')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Comment entity.');
}
$editForm = $this->createEditForm($entity);
$deleteForm = $this->createDeleteForm($id);
return $this->render('EmployeeBundle:Comment:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Creates a form to edit a Comment entity.
*
* #param Comment $entity The entity
*
* #return \Symfony\Component\Form\Form The form
*/
private function createEditForm(Comment $entity)
{
$form = $this->createForm(new CommentType(), $entity, array(
'action' => $this->generateUrl('comment_update', array('id' => $entity->getId())),
'method' => 'PUT',
));
$form->add('submit', 'submit', array('label' => 'Update'));
return $form;
}
/**
* Edits an existing Comment entity.
*
*/
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('EmployeeBundle:Comment')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Comment entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('comment_edit', array('id' => $id)));
}
return $this->render('EmployeeBundle:Comment:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
/**
* Deletes a Comment entity.
*
*/
public function deleteAction(Request $request, $id)
{
$form = $this->createDeleteForm($id);
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('EmployeeBundle:Comment')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Comment entity.');
}
$em->remove($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('comment'));
}
/**
* Creates a form to delete a Comment entity by id.
*
* #param mixed $id The entity id
*
* #return \Symfony\Component\Form\Form The form
*/
private function createDeleteForm($id)
{
return $this->createFormBuilder()
->setAction($this->generateUrl('comment_delete', array('id' => $id)))
->setMethod('DELETE')
->add('submit', 'submit', array('label' => 'Delete'))
->getForm()
;
}
}
Then in FormType
$builder
->add('comment')
->add('createdby')
->add('updatedby')
->add('datecreated')
->add('dateupdated')
->add('project')//related entity
;
I see at least 3 questions in your question...
For the error :
Unable to guess how to get a Doctrine instance from the request
information,
I don't know why it's happening, but it doesn't seem related directly to the relationship question... Maybe try to suppress fields 'createdby', 'updatedby', 'datecreated', 'dateupdated'from the form builder, as they are not in your mapping yaml file (or maybe you just didn't show them) - whatever, you should probably not display them in the form, but complete these fields in the controller or via prePersist actions, as the user doesn't have to know about them.
Then for the problem that the project field of the form displays a dropdown with project ids : you can specify in the form builder which property of the comment entity you want to display, via the choice_label option, like this :
$builder
->add('comment')
->add('project', 'entity', array(
'class' => 'YourBundle:Project',
'choice_label' => 'projectName',
));
This way, you still will have a dropdown, but with project names displayed instead of ids. The 'entity' file field type has many other options, see the documentation.
For your last question, which is you would like to have a text field with autocomplete instead of a dropdown, you can manage it with a data transformer + a JS autocompleter. See this answer for more information.

can't update entity Symfony2

Trying to update my entity, unfortunately didnt use Doctrines generate CRUD feature (have to change stuff I didnt write).
I am finally getting data into my form, but it just won't save the changes (also, it doesn't create a new entity as one might suspect).
When I click 'save', I always return to the page where I have my form to edit the entity.
Checked if method is POST, it is.
if ($form->get('save')->isClicked()) {
doesn't seem to do anything, how can that be?
Here's the rest of my action:
/**
* Updates.
*
* #Route("/offerweekchange/{offerid}", name="offerweekchange")
* #Template("")
*/
public function offerweekchangeAction(Request $request, $offerid)
{
$request = $this->get('request');
if ($offerid) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AlexanderBuerkleShopBundle:Promotion')->findOneBy(array('id' => $offerid));
$form = $this->createForm(new OfferWeekChangeType(), $entity);
# \Doctrine\Common\Util\Debug::dump($request->getMethod());
if ($form->get('save')->isClicked()) {
if ($request->getMethod() == 'POST') {
$form->bind($request);
if ($form->isValid()) {
$em->flush();
return $this->redirect($this->generateUrl('offerweeklist'));
}
}
}
return $this->render('AlexanderBuerkleShopBundle:OfferWeekList:offerweekchange.html.twig',
array('form' => $form->createView(), 'offerid' => $offerid, 'entity' => $entity));
}
}
Any help would be greatly appreciated.
First, here is a working sample of your code:
public function offerweekchangeAction(Request $request, $offerid)
{
if ($offerid) {
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AlexanderBuerkleShopBundle:Promotion')->findOneBy(array('id' => $offerid));
$form = $this->createForm(new OfferWeekChangeType(), $entity);
$form->handleRequest($request);
# \Doctrine\Common\Util\Debug::dump($request->getMethod());
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('offerweeklist'));
}
return $this->render('AlexanderBuerkleShopBundle:OfferWeekList:offerweekchange.html.twig',
array('form' => $form->createView(), 'offerid' => $offerid, 'entity' => $entity));
}
}
Secondly, you have several mistakes here, so let's analyse them one by one:
1:
if ($offerid) {
your code does nothing on the else branch.
2:
$request = $this->get('request');
you already have the request parameter injected into the action. This line is redundant.
3:
$form->bind($request);
This is deprecated since 2.3. Use $form->handleRequest($request) instead.
4:
$em->flush();
You are flushing the entity manager, but nothing is persisted, so nothing will happen. you have to persist the entity first with $em->persist($entity)
5:
if ($request->getMethod() == 'POST') {
The method $form->isValid() checks for this also, so checking for post is redundant.
That's it. Hope it helped.
The most likely issue here is with the AbstractType which define your form OfferWeekChangeType).
In order to map the form data on the entity you need to set the 'data_class'.
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(
array(
'data_class' => ' Acme\StoreBundle\Entity\Product',
)
);
}
then inside your controller you need to invoke :
$form->handleRequest($request);
This will bind the request to your form.
Only when you invoke:
$form->isValid()
The data from the form (if valid) will be mapped on the entity.
$em->persist($entity);
in this case is superflus because Doctrine UnityOfWork already 'knows' the entity from when you got it from the repository. Just invoke
$em->flush($entity);
As a side note remember that flushing only the needed entity is preferable (when possible) the flush the entire UnityOfWork in order to avoid unexpected behaviours.
Regards.

Symfony2 add current user to form input data

I've got a standard FOS user that's got a ManyToOne entity relationship with a blog entity.
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="blog")
* #ORM\JoinColumn(name="user", referencedColumnName="id")
*/
private $user;
I've used the app/console generate:doctrine:crud command to generate a basic crud system.
When I create a new blog entity I want to insert the logged in user that performed the action. By default Symfony generates CRUD code that allows the user to select which user is connected to the entity.
$builder
->add('name')
->add('address')
->add('facebook')
->add('twitter')
->add('user')
;
In the controller I can access the logged in user using security.context:
$user = $this->get('security.context')->getToken()->getUser();
Whats the best course of action to change this?
Okay! solved my own question (if I'm doing it wrong please feel free to correct me, and I'll accept a better answer). This one does appear to work well however!
The user can be added in the controller after the $form->isValid() check is performed. Here's my controller function for example.
public function createAction(Request $request)
{
$entity = new Blog();
$form = $this->createForm(new BlogType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$entity->setUser($this->get('security.context')->getToken()->getUser());
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('blog_show', array('id' => $entity->getId())));
}
return $this->render('ExampleBundle:Blog:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
The user needs to be removed from the form builder for this to work.

symfony doctrine update from form

I'm stuck since this morning with the update of an entity.
Don't know what I'm missing, pretty sure this is a newbie mistake.
I'm just trying to update something via a form.
The controller:
public function editAction($pid, $plid, Request $request)
{
$plan = new Plan();
$form = $this->createForm(new PlanType(), $plan);
$plan = $this->getDoctrine()->getRepository('QArthFrameworkBundle:Plan')->findOneByPlid($plid);
$project = $this->getDoctrine()->getRepository('QArthFrameworkBundle:Project')->findOneByPid($pid);
$form->handleRequest($request);
if ($request->getMethod() == 'POST') {
$em = $this->getDoctrine()->getManager();
$em->flush();
return $this->redirect($this->generateUrl('qarth_framework_plan_edit', array('pid' => $pid, 'plid' => $plid)));
}
return $this->render('QArthFrameworkBundle:Pages:plan_edit.html.twig', array(
'plan' => $plan,
'project' => $project,
'form' => $form->createView(),
));
}
The form:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('description', 'textarea');
}
The Entity : http://pastebin.com/bTqKehyQ
With the profiler I can see that my post parameters are well posted
plan {"name":"fsggsfgsf","description":"gsfgsfgsf","_token":"7d089aca0203c60fe1e617488e532ac966101440"}
But I can't see any trace of an update query or something else.
If you have an idea, it will be great!
Many thanks,
Ben
Need to pass the queried plan to the form.
public function editAction($pid, $plid, Request $request)
{
$plan = $this->getDoctrine()->getRepository('QArthFrameworkBundle:Plan')->findOneByPlid($plid);
$project = $this->getDoctrine()->getRepository('QArthFrameworkBundle:Project')->findOneByPid($pid);
// Create a new one if not found
if (!$plan) $plan = new Plan();
// Build your form using queried or new plan
$form = $this->createForm(new PlanType(), $plan);
$form->handleRequest($request);
// Checks for POST as well as validity
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($plan); // To handle new plans, no impact for existting plans
$em->flush();
// Rest is the same

Symfony2 - Establish one form parameter from outside so cannot be modified by the users

I have a CRUD for one of my entities in Symfony2. In order to create a new entry, I have two controller functions:
public function newAction($id) {
$entity = new Clientes();
// Get the reference to the Login entity using its ID
$em = $this->getDoctrine()->getManager();
$ref_login = $em->getReference('LoginBundle:Login', $id);
// Put the retrieved reference to the entity
$entity->setLogin($ref_login);
$form = $this->createForm(new ClientesType(), $entity);
return $this
->render('MovinivelBundle:Persona/Clientes:new.html.twig',
array('entity' => $entity,
'form' => $form->createView(),));
}
public function createAction(Request $request) {
$entity = new Clientes();
$form = $this->createForm(new ClientesType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('clientes'));
}
return $this
->render('MovinivelBundle:Persona/Clientes:new.html.twig',
array('entity' => $entity,
'form' => $form->createView(),));
}
In the previous code I added the $id input parameter to the newAction() function because I want it to be established from outside, because each of this Clientes is additional info of Login and has to be linked.
In the ClientesType form I have the following:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('login')
->add('direccion')
->add('localidad')
->add('provincia')
->add('telefono')
;
}
So far it works. In my form, the login parameter is chosen depending on the $id value. But the thing is that I want the login parameter to be fixed once the form is created, so the user cannot modify it from the form, but only calling the newAction($id) function with the appropiate value.
The thing is that if I delete the ->add('login') line in the FormType, it doesn't work anymore. It comes to my mind two options:
Hide somehow the 'login' in the form, but keeping it working, although I don't know how, or
pass to the createAction the $id parameter along with the $request one as input parameters, but I cannot figure out how do it either.
Any thoughts on this?
I think you are looking for a hidden field type:
public function buildForm(...)
{
$builder
->add('login', 'hidden')
// ...
;
}
Ok, I came out with the solution. All I was looking for is actually the following:
<div style="display:none">
{{ form_rest(form) }}
</div>
Typing this at the end of the template after having shown explicitly any other form field avoids any user to modify the fields I don't want to, while it still sends the info using the $POST method.

Resources