Use the same entity form but two times in Symfony 2 - forms

I would like to use the same entity form but two times (to modify two differents properties of my entity). By example, I have a entity User, I create a form to modify the name and another to modify the first name on the same page (just an idiot example). If I submit the first form, it said me that I have extra fields (that is normal). I tried to change the action of the second form with setAction by example but i don't know how to retrieve the form in my controller action.
I started with this code :
$form = $this->createFormBuilder($user)
->add('name', TextareaType::class, array("required" => false))
->add('save', SubmitType::class, array('label' =>'Enregistrer'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$user = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return $this->redirectToRoute('myroute');
}
$form2 = $this->createFormBuilder($user)
->add('fname', TextareaType::class, array("required" => false))
->add('save', SubmitType::class, array('label' =>'Enregistrer'))
->getForm();

Related

Strange exception - Serialization of 'Symfony\Component\HttpFoundation\File\File' is not allowed

I have this exception, in a strange behavior that I can't understand. I'll try to explain.
I have a form, where I can add create a report. The use can upload multiple attached pdf and a text comment. The form have 2 submit button, 'save' and 'saveAndClose'.
class ReportType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('documentDatas', CollectionType::class, array(
'entry_type' => DocumentType::class,
'entry_options' => ['data_class' => 'AppBundle\Model\DocumentPdfData', 'add_class' => 'upload-pdf'],
'allow_add' => true,
'allow_delete' => true,
'label' => false
))
->add('comment', CKEditorType::class, array(
'config' => array('toolbar' => 'my_toolbar'),
'label' => false,
'required' => false,
'input_sync' => true
))
->add('save', SubmitType::class, array('attr' => array('class' => 'btn btn-success mr-2')))
->add('saveAndClose', SubmitType::class, array('label' => 'saveAndClose', 'attr' => array('class' => 'btn btn-success float-right')))
;
}
}
The Save only persist the form, the saveAndClose obviously close the report, so user can't modify it anymore.
The exception
Serialization of 'Symfony\Component\HttpFoundation\File\File' is not allowed
appear when an user upload an attached and saveAndClose the form. Only in this case, other case works well (also upload attached, push save, return the the form and saveAndClose).
This is my controller:
if ($form->isSubmitted() && $form->isValid()) {
if ($form->getClickedButton() && 'saveAndClose' === $form->getClickedButton()->getName()) {
$this->get(ConfirmReport::class)->confirm($report, $user);
$em->flush();
$report->modify($reportData, $user);
$em->persist($report->getReportParameters());
$em->persist($report);
$em->flush();
$this->addFlash('success', $this->get('translator')->trans('ReportConfirmed'));
return $this->redirectToRoute('practitioner_visit_detail_to_do');
}
if ($form->getClickedButton() && 'save' === $form->getClickedButton()->getName()) {
$report->modify($ReportData, $user);
$em->persist($report->getReportParameters());
$em->persist($report);
$em->flush();
$this->addFlash('success', $this->get('translator')->trans('ReportSaved'));
return $this->redirectToRoute('practitioner_visit_detail_to_do');
}
}
So, the only difference between 2 flux is the confimReport service. Inside this I put a bool parameter of report to true and make some operation on the DB, to remove some read and write permission of the user on this report. Nothing about the file uploaded or something else. So, i can't understand what cause the exception.
N.B.:
If i comment the confirmReport service all work well (dont know why);
I obtain the exception but the entity manager is flushed, so in my db I have saved the operation of the user (also the file uploaded).
So then what else could cause this?
Maybe the second flushing messes up with the code ? Can you try this :
if ($form->isSubmitted() && $form->isValid() && $form->getClickedButton()) {
if ('saveAndClose' === $form->getClickedButton()->getName()) {
$this->get(ConfirmReport::class)->confirm($report, $user);
$msg='ReportConfirmed';
}
if ('save' === $form->getClickedButton()->getName()) {
$msg = 'ReportSaved';
}
$report->modify($ReportData, $user);
$em->persist($report->getReportParameters());
$em->persist($report);
$em->flush();
$this->addFlash('success', $this->get('translator')->trans($msg));
return $this->redirectToRoute('practitioner_visit_detail_to_do');
}
Can you also show the content of the confirm() function ?
Thanks

Symfony Forms - Datatime Add +30minutes

When I set beginAt(DateTime) in Forms I would like set the same date in the "endAt" but +30 minutes. I have no clu how to do this :(
The first code is the part Form in my project and the second code is function "new Appointment" to add appointment.
$builder
->add('title', TextType::class, ['label'=>'Tytuł'])
->add('description', TextType::class, ['label'=>'Treść'])
->add('beginAt')
->add('endAt')
;
public function new(Request $request, $id, TokenStorageInterface $tokenStorage): Response
{
$currentUser = $tokenStorage->getToken()
->getUser();
$username = $currentUser->getUsername();
$appointment = new Appointments();
$appointment->setDoctor($id);
$appointment->setUsername($username);
$form = $this->createForm(AppointmentsType::class, $appointment);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($appointment);
$em->flush();
return $this->redirectToRoute('przychodnia_index');
}
return $this->render('appointments/new.html.twig', [
'appointment' => $appointment,
'form' => $form->createView(),
]);
}
Try to use Symfony Form Events to update endAt field on submit for example and use some ajax to submit your form dynamically. There is a great tutorial here (in French sorry) https://www.grafikart.fr/tutoriels/champs-imbriques-888

How to make a Symfony GET form redirect to route with parameter?

I want to create a form for searching a profile by username which redirect then to the profile page of the user. Btw, I use Symfony 3.2.
I reckon the natural way for doing this would be a GET action form. It would even allow a customer to change the url directly with the good username to see its profile.
Here is the code of my controller :
ProfileController.php
//...
/** #Route("/profil/search", name="profil_search") */
public function searchAction() {
$builder = $this->createFormBuilder();
$builder
->setAction($this->generateUrl('profil_show'))
->setMethod('GET')
->add('username', SearchType::class, array('label' => 'Username : '))
->add('submit', SubmitType::class, array('label' => 'Search'));
$form = $builder->getForm();
return $this->render('profils/profil_search.html.twig', [
'form' => $form->createView(),
]);
}
/** #Route("/profil/show/{username}", name="profil_show") */
public function showAction($username) {
$repository = $this->getDoctrine()->getRepository('AppBundle:User');
$searchedUser = $repository->findOneByUsername($username);
return $this->render('profils/profil_show.html.twig', [
'searchedUser' => $searchedUser,
]);
}
//...
This code will lead to the following error message :
Some mandatory parameters are missing ("username") to generate a URL for
route "profil_show".
I read the documentation thoroughly but couldn't guess, how can I pass the username variable to the profil_show route as a parameter ?
If my way of doing is not the good one, thanks for telling me in comments but I'd still like to know how to use GET forms.
EDIT :
Thanks to #MEmerson answer, I get it now. So for future noobs like me, here is how I did it :
/** #Route("/profil/search", name="profil_search") */
public function searchAction(Request $request) {
$data = array();
$builder = $this->createFormBuilder($data);
$builder
//->setAction($this->generateUrl('profil_show'))
//->setMethod('GET')
->add('username', SearchType::class, array('label' => 'Username : '))
->add('submit', SubmitType::class, array('label' => 'Search'));
$form = $builder->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
return $this->redirectToRoute('profil_show', array('username' => $data["username"]));
}
return $this->render('profils/profil_search.html.twig', [
'method' => __METHOD__,
'form' => $form->createView(),
'message' => $message,
]);
}
If you take a look at the error message it says that the problem is where you are trying to generate the URL for the path 'profil_show'.
Your controller annotations require that the URL be populated with a user name
/** #Route("/profil/show/{username}", name="profil_show") */
this means that Symfony is expecting http://yoursite.com/profil/show/username for the route. But if you want to pass it as a GET form posting it really should be expecting http://yoursite.com/profil/show?username
you can add a second route or change your existing route to be
/** #Route("/profil/show", name="profil_show_search") */
that should solve your problem.

Retrieve the previous object linked to a form in Symfony 2

I have a form to edit an address for an user (I pass an entity address to the form). When I modify the address and submit the form, I would like desactivate (with a setActive function) the entity that I passed (without new values) and create a new line with new values. Is it possible ?
Example :
$em = $this->getDoctrine()->getManager();
$client_adr = $em->getRepository('EcommerceBundle:ClientAdresse')->find($id_adr); // here it's the entity that i want disable
$form = $this->createFormBuilder($client_adr)
->add('prenom', TextType::class)
->add('nom', TextType::class)
->add('adresse', TextType::class)
->add('lieu_dit', TextType::class)
->add('complement', TextType::class)
->add('code_porte', TextType::class)
->add('cp', TextType::class)
->add('pays', TextType::class)
->add('save', SubmitType::class, array('label' => 'Modifier'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$adr = $form->getData(); // here it's the entity with new values
$em->persist($new_adr);
$em->flush();
}
In this example, if I modify the name of my entity, I want that my object "$client_adr" keep its previous values and be disabled (if i call setActive by example) and I want that my object $new_adr be saved on a new line in database with modified values.
Thanks
Simple. Right after finding your object but before setting in form, clone your object then set the id null. You may have to add a setId method in your entity class.
$client_adr = $em->getRepository('EcommerceBundle:ClientAdresse')->find($id_adr);
$clone_adr = clone $client_adr;
$clone_adr->setId(null);
$client_adr->setIsActive(false);
$form = $this->createFormBuilder($clone_adr) ...
....
$em->persist($client_adr); // save old, inactive
$em->persist($new_adr); // save new.
$em->flush();

How to set as a default value in a Symfony 2 form field the authentified username from the FOSUserBundle

i find this snippet useful indeed to put a default value in my form while creating it
$builder
->add('myfield', 'text', array(
'label' => 'Field',
'data' => 'Default value'))
;
what if i want to replace 'default value' with an authentified person from the FOSUser bundle? ( that return true to is_granted("IS_AUTHENTICATED_REMEMBERED"))
i can retrieve that name on a twig file with
{{ app.user.username }}
i have also done it in a controller method with
$username=$this->container->get('security.context')->getToken()->getUser()->getUsername()
but i can't manage to make this working in my form!
i am not sure i understand that container thing well ...neither how to transfer variables betweenn classes and controller...
something around this maybe??
->add('myfield', 'text', array(
'label' => 'Field',
'data' => FOS\UserBundle\Model::$this->getUsername()))
You can passe variable from your controller to your form :
in your controller :
$username=$this->container->get('security.context')->getToken()->getUser()->getUsername()
$form = $this->createForm(new MyFormType($username), $entity);
in your form :
protected $username;
public function __construct (array $username = null)
{
$this->username = $username ;
}
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('myfield', 'text', array(
'label' => 'Field',
'data' => $this->username))
}
Another way to set default values into a form is to set them on the underlying data object for the form, as in this example from the Symfony documentation on building a form:
public function newAction()
{
// create a task and give it some dummy data for this example
$task = new Task();
$task->setTask('Write a blog post');
$task->setDueDate(new \DateTime('tomorrow'));
$form = $this->createFormBuilder($task)
->add('task', 'text')
->add('dueDate', 'date')
->getForm();
return $this->render('AcmeTaskBundle:Default:new.html.twig', array(
'form' => $form->createView(),
));
}
In this example, the form's underlying data object is a Task and the values set on the task are the default values to be displayed in the form. The task object is not persistent. This approach works just as well with a form class and assuming the underlying object for your form is a User would look something like this:
$username = $this->container->get('security.context')->getToken()->getUser()->getUsername();
$user = new User();
$user->setUsername($username);
// could set any other default values on user here
$form = $this->createForm(new MyFormClass(), $user);
The disadvantage of this approach is if the form is used in many places requiring the same defaults the code would be repeated. This is not a situation I've come across so far - my User forms are re-used for create/edit but edit doesn't require the defaults.