I'm using symfony4 and In my project I have and entity Bill and it offer two packs:
1) First pack, user can generate just one bill in PDF after filling out a form and saving data in database and it has its own price.
2) Second pack, user can generate Three bills in PDF after filling out a form and saving data in database and this has its own price also.
The first pack is simple and it works fine , I have created BillType and an action in the controller and everything is well.
public function newBillFirstPack(Request $request)
{
$entity = new Bill();
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(BillType::class, $entity);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$em->persist($entity);
$em->flush();
//...............
}
}
return $this->render('frontOffice/bill/new_first_pack.html.twig', array(
'form' => $form->createView()
));
}
The problem is with the second pack , I'd like to know how can I create three bills from one form. I tried to create 3 FormType
- FirstBillType and a twig to render its view.
- SecondtBillType and a twig to render its view.
- ThirdBillType and a twig to render its view also.
And in the controller I created three forms.
I didn't test it yet but even it works I don't like it , I fell it's not a clean solution. Imagine if a day I want to edit an attribute in the formType, so I must edit it in three formsType and three html.twig views, same thing if I want to remove or add an attribute in the forms.
I have see in the documentation "How to Embed a Collection of Forms", but that example is how to embed one attribute many times.
Any good solution ?
If I understand what you need. New action can handle this and depending on your needs form can run different action.
public function newBillThirdPack(Request $request)
{
$entity = new Bill();
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(BillType::class, $entity);
$form->handleRequest($request);
if ($form->isSubmitted()) {
if ($form->isValid()) {
$em->persist($entity);
$em->persist(clone $entity);
$em->persist(clone $entity);
$em->flush();
//...............
}
}
return $this->render('frontOffice/bill/new_third_pack.html.twig', array(
'form' => $form->createView()
));
}
Related
This is what I've done so far:
I have a Patient(parent entity) and a File(child entity) each Patient is created with two files when the patient is edited I could edit the two files.
What's needed :
Instead of editing the same files I want that each time The patient is updated the form gets populated with the latest (based on the creation date) files but when submitting it should create new files and keep the old ones in the database
Could someone give me some suggestions and references?
Thanks
//Patient controller Edit Function
public function edit(Request $request, Patient $patient): Response
{
$types=$this->getListData('types');
$form = $this->createForm(PatientType::class, $patient,array(
'types' => $types,
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('patient_show', [
'id' => $patient->getId(),
]);
}
return $this->render($brand.'/edit.html.twig', [
'patient' => $patient,
'form' => $form->createView(),
]);
}
Referencing this question: JMS Serializer DateTime not deserializing?, I have narrowed this down to the folowing:
I have got a controller with a put action using a Request Body Listener:
/**
* #ParamConverter("client", converter="fos_rest.request_body")
*/
public function putClientAction($id, Client $client)
{
$logger = $this->get('logger');
$logger->info(serialize((array) $client));
$logger->info("ID: " . $id);
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('SomeBundle:Client')->find($id);
$logger->info(serialize($entity));
$form = $this->get('form.factory')->createNamed('', new \SomeBundle\Form\ClientType(), $entity);
$form->submit((array) $client, false);
$logger->info(serialize($entity));
$em->persist($entity);
$em->flush();
return $this->get('fos_rest.view_handler')->handle($this->view(null, Codes::HTTP_OK));
}
My question concerns the $form->submit() call, or rather, how would I go about and actually submit the incoming $client entity? I have tried submitting the object, or an (array) representation of it, with the $clearmissing flag set to false to avoid null values being passed in, but an UPDATE never happens.
To be sure, the logged entity representations look fine, it's just that $entity never gets filled with $clients values.
Got any hints on what I'm doing wrong?
Edit
This is what a PUT request looks like:
{
"shortname":"...",
"officialname":"...",
"shortinfo":"..."
...
}
Edit 2
I've narrowed it down (again) to a problem with the DateTime data type:
...
$logger->info("REQUEST" . print_r($request->request->all(), true));
$form = $this->get('form.factory')->createNamed('', new Type(), $entity);
$form->submit($request, false);
$logger->info($form->getData()->getUpdatedAt()->format('Y-m-d\TH:i:sP'));
The $request object contains an updated DateTime, but it is never passed to the form (the second log shows the original date). The form Type:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('updatedAt', 'datetime', array('format' => 'Y-m-d\TH:i:sP'))
}
I guess this is a problem with Symfony Forms and DateTime objects, then?
The problem is how you submit your data. You should use less complex way.
Here is example:
public function putPostAction(Post $post, Request $request)
{
$em = $this->getDoctrine()->getManager();
$form = $this->createForm('content_post',$post);
$form->submit($request);
if($form->isValid()){
$em->persist($form->getData());
$em->flush();
return $post;
}
return $form;
}
You don't need to query client in your code because controller will automatically convert it for you.
Also you should use Request object, it will contain all data that you've submitted.
$form->submit($request) has a key part here.
$form will return all your validations errors.
My FOSRestConfig
fos_rest:
param_fetcher_listener: true
routing_loader:
default_format: json
view:
view_response_listener: force
When I persist an entity I would like to add a button to the form. Is that possible. I read a lot about modifying the entity but this is not what I want to do, I just want to add a button.
if($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
.... what do I write here to add my button ? is it even here or the type ?
Thank you
}
I found a solution which is what it is but it is possible in fact. The formView has to be created before checking if the form has been submitted or is valid
$form_builder->add('button', 'boutons', array('attr' => array('boutons' => $buttons))); //boutons is a type field I created and I have to give an array of buttons I want to add)
$form = $form_builder->getForm();
$form->handleRequest($request);
$form_view = $form->createView();
if($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$entity = $form->getData();
$em->persist($entity);
if($form_view->offsetExists('button')) {
$form_view->children['button']->vars['attr']['boutons'][] = $button_send_validation; (// I add my new button to the array of buttons)
}
}
Hope it can help someone..
In Symfony 2.7, I use anchors on my index page. The page also contains a form that allows me to filter the elements displayed.
If I navigate within the page using the anchors, an anchor appears in the URL.
Then, if I click on the form's submit button, filters are applied and page refreshed with new content.
Problem is the anchor in the URL doesn't disappear during the process, and after refresh, the page scrolls down to the last anchor I visited.
How can I reset the URL after form's submission?
Here's my action code:
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$dailyPlanning = $em
->getRepository('AppBundle:Planning')
->findOneBy(array('day' => (new \DateTime)));
//....//
$filter = new Filter($param, $param2);
$form = $this->createForm(new FilterType(), $filter);
$form->handleRequest($request);
if ($form->isValid()) {
$dailyPlanning->applyFilter($filter);
}
return $this->render('AppBundle:Workflow:index.html.twig', array(
'planning' => $dailyPlanning,
'form' => $form->createView(),
'filterHidden' => $filter->allChecked(),
));
}
Can anyone please show me a specific example of a Symfony2 form entity update? The book only shows how to create a new entity. I need an example of how to update an existing entity where I initially pass the id of the entity on the query string.
I'm having trouble understanding how to access the form again in the code that checks for a post without re-creating the form.
And if I do recreate the form, it means I have to also query for the entity again, which doesn't seem to make much sense.
Here is what I currently have but it doesn't work because it overwrites the entity when the form gets posted.
public function updateAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$testimonial = $em->getRepository('MyBundle:Testimonial')->find($id);
$form = $this->createForm(new TestimonialType(), $testimonial);
$request = $this->get('request');
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
echo $testimonial->getName();
if ($form->isValid()) {
// perform some action, such as save the object to the database
//$testimonial = $form->getData();
echo 'testimonial: ';
echo var_dump($testimonial);
$em->persist($testimonial);
$em->flush();
return $this->redirect($this->generateUrl('MyBundle_list_testimonials'));
}
}
return $this->render('MyBundle:Testimonial:update.html.twig', array(
'form' => $form->createView()
));
}
Working now. Had to tweak a few things:
public function updateAction($id)
{
$request = $this->get('request');
if (is_null($id)) {
$postData = $request->get('testimonial');
$id = $postData['id'];
}
$em = $this->getDoctrine()->getEntityManager();
$testimonial = $em->getRepository('MyBundle:Testimonial')->find($id);
$form = $this->createForm(new TestimonialType(), $testimonial);
if ($request->getMethod() == 'POST') {
$form->bindRequest($request);
if ($form->isValid()) {
// perform some action, such as save the object to the database
$em->flush();
return $this->redirect($this->generateUrl('MyBundle_list_testimonials'));
}
}
return $this->render('MyBundle:Testimonial:update.html.twig', array(
'form' => $form->createView()
));
}
This is actually a native function of Symfony 2 :
You can generate automatically a CRUD controller from the command line (via doctrine:generate:crud) and the reuse the generated code.
Documentation here :
http://symfony.com/doc/current/bundles/SensioGeneratorBundle/commands/generate_doctrine_crud.html
A quick look at the auto-generated CRUD code by the Symfony's command generate:doctrine:crudshows the following source code for the edit action
/**
* Displays a form to edit an existing product entity.
*
* #Route("/{id}/edit", name="product_edit")
* #Method({"GET", "POST"})
*/
public function editAction(Request $request, Product $product)
{
$editForm = $this->createForm('AppBundle\Form\ProductType', $product);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('product_edit', array('id' => $product->getId()));
}
return $this->render('product/edit.html.twig', array(
'product' => $product,
'edit_form' => $editForm->createView(),
));
}
Note that a Doctrine entity is passed to the action instead of an id (string or integer). This will make an implicit parameter conversion and saves you from manually fetching the corresponding entity with the given id.
It is mentioned as best practice in the Symfony's documentation