I have a entity with some data prefilled, and I want to display them on the form : here state would be ACTIVE and customerId = 1;
// Form file (ben.file.create)
protected function buildForm()
{
$this->formBuilder->add('name', 'text', ['label'=>'Nom du patient'])
->add('customerId', 'integer')
->add('state', 'choice', ['choices'=>['ACTIVE'=>'ACTIVE',
'DONE'=>'DONE', 'CANCELLED'=>'CANCELLED']]);
}
// in the controller
public function index()
{
$form = $this->createForm("ben-file-create");
$file = new BenFile();
$file->setCustomerId(1);
$file->setState('ACTIVE');
$form->getForm()->submit($file); // <--- Here the glue problem
return $this->render('create-file', array());
}
It looks like submit is not the right bind function. I would expect that the form is pre-filled accordingly, and after the POST request, I have an updated BenFile entity.
You can do easily in createForm method :
// in the controller
public function index(Request $request)
{
$file = new BenFile();
$file->setCustomerId(1);
$file->setState('ACTIVE');
$form = $this->createForm("ben-file-create", $file);
// handle submit
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
// flush entity
$fileNew = $form->getData();
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($fileNew );
$entityManager->flush();
}
return $this->render('create-file', array());
}
Related
I have a little problem. I have an object "persona" who has several collections.
I have a form who render all the collection and allow me to add and remove collections.
After that, I dump all the information and the object "persona" has all the collection I sent it when I submitted the form.
When I persist and flush the data, doctrine saves persona but not the collection
This are my configurations:
Entity persona
/**
* #ORM\OneToMany(targetEntity="PersonaDomicilio",mappedBy="idPersona",cascade={"persist"},orphanRemoval=true)
*/
private $domicilios;
public function __construct() {
$this->domicilios = new ArrayCollection();
}
public function getDomicilios() {
return $this->domicilios;
}
public function addDomicilio(PersonaDomicilio $persona_domicilio) {
$persona_domicilio->setIdPersona($this);
$this->domicilios[] = $persona_domicilio;
}
public function removeDomicilio(PersonaDomicilio $persona_domicilio) {
$this->domicilios->removeElement($persona_domicilio);
}
Entity PersonaDomicilio
/**
* #var \AppBundle\Entity\Persona
*
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Persona",inversedBy="domicilios")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="id_persona", referencedColumnName="id_persona")
* })
*/
private $idPersona;
The PersonaType
->add('domicilios', CollectionType::class, array(
'entry_type' => PersonaDomicilioType::class,
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'label' => false
))
The controller action
$em = $this->getDoctrine()->getManager();
$persona = new Persona();
$formulario = $this->createForm(
PersonaType::class,
$persona,
array('action' => $this->generateUrl('persona_create'),
'method' => 'POST')
);
$formulario->handleRequest($request);
$persona->setFisicaJuridica('F');
$em->persist($persona);
$em->flush();
I don´t wanna persist all the collection manually with a foreach, because the cascade persist would help to do that.
I have to say that I did several tests and I can´t understand why is not working.
Pd: "id_persona" is correctly setted to the collections too.
This is "normal". If you refer to this old symfony documentation (which is still valid), you also have to persist your PersonaDomicilio (see the paragraph Doctrine: Ensuring the database persistence).
Here is their example :
// src/Acme/TaskBundle/Controller/TaskController.php
use Doctrine\Common\Collections\ArrayCollection;
// ...
public function editAction($id, Request $request)
{
$em = $this->getDoctrine()->getManager();
$task = $em->getRepository('AcmeTaskBundle:Task')->find($id);
if (!$task) {
throw $this->createNotFoundException('No task found for id '.$id);
}
$originalTags = new ArrayCollection();
// Create an ArrayCollection of the current Tag objects in the database
foreach ($task->getTags() as $tag) {
$originalTags->add($tag);
}
$editForm = $this->createForm(new TaskType(), $task);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
// remove the relationship between the tag and the Task
foreach ($originalTags as $tag) {
if (false === $task->getTags()->contains($tag)) {
// remove the Task from the Tag
$tag->getTasks()->removeElement($task);
// if it was a many-to-one relationship, remove the relationship like this
// $tag->setTask(null);
$em->persist($tag);
// if you wanted to delete the Tag entirely, you can also do that
// $em->remove($tag);
}
}
$em->persist($task);
$em->flush();
// redirect back to some edit page
return $this->redirectToRoute('task_edit', array('id' => $id));
}
// render some form template
}
And here an example for your configuration (not tested)
<?php
// Create an ArrayCollection of the current domicilios objects in the database
$originalDomicilios = new ArrayCollection();
foreach ($persona->getDomicilios() as $domicilio) {
$originalDomicilios->add($domicilio);
}
// Check request
$form->handleRequest($request);
// Was the form submitted?
if ($form->isSubmitted() && $form->isValid()) {
try {
// Handle domicilios
foreach ($originalDomicilios as $domicilio) {
if (false === $persona->getDomicilios()->contains($domicilio)) {
// remove the persona from the domicilio (or remove it)
$domicilio->removePersona($persona);
// Persist domicilio
$em->persist($domicilio);
}
}
// Save new domicilios
foreach($persona->getDomicilios() as $domicilio){
if (false === $originalDomicilios->contains($domicilio)){
// Add persona
$domicilio->addPersona($persona);
// Persist domicilio
$em->persist($domicilio);
}
}
// Persist persona
$em->persist($persona);
// Save
$em->flush();
...
} catch (\Exception $e) {
}
}
I've put a registration form in a method so, that I can use it in different places.
My service registration controller looks like this:
public function loadRegisterForm()
{
$user = new User();
$form = $this->createForm(RegistrationType::class, $user);
$form->handleRequest($this->request);
$errors = "";
if ($form->isSubmitted())
{
if ($form->isValid())
{
$password = $this->get('security.password_encoder')
->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
$user->setIsActive(1);
$user->setLastname('none');
$user->setCountry('none');
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
}
else
{
$errors = $this->get('validator')->validate($form);
}
}
$parametersArray['form'] = $form;
$parametersArray['errors'] = $errors;
return $parametersArray;
}
services.yml looks like this:
register_form_service:
class: ImmoBundle\Controller\Security\RegistrationController
calls:
- [setContainer, ["#service_container"]]
And the main controller where I load the service controller:
private function indexAction()
{
/**
* Load register form
*/
$registerForm = $this->get('register_form_service');
$registerParameters = $registerForm->loadRegisterForm();
$registerParameters['form']->handleRequest($request);
return $this->render(
'ImmoBundle::Pages/mainPage.html.twig',
array(
'register_form' => $registerParameters['form']->createView(),
'errors' => $registerParameters['errors'],
)
);
}
The form itself is well rendered, so there is no problem. However nothing happens if I try to submit the form. I know that I should add the following line to the main controller
if ($registerParameters['form']->isSubmitted())
{
// add to db
}
But is there any way to do it only in a service controller?
You do not need a service definition to inject the container into your controller. If the controller extends Symfony\Bundle\FrameworkBundle\Controller\Controller all services are accesible via ->get(). Next to that, $form->isValid() already checks whether the form is submitted.
Why is your action private? It should be public, and it need to get the Request object as it's first parameter:
public function indexAction(Request $request)
{
$user = new User();
$form = $this->createForm(RegistrationType::class, $user);
$form->handleRequest($request);
if ($form->isValid()) {
// Do something here
}
}
See http://symfony.com/doc/current/book/forms.html#handling-form-submissions
I can't submit my form to database when I validate I have nothing in my table in phpMyAdmin. Here is the code in the controller. I want to submit a form which contains an upload type.
<?php
// src/AppBundle/Controller/ProductController.php
namespace Upload\FileBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Upload\FileBundle\Entity\Product;
use Upload\FileBundle\Form\ProductType;
use Symfony\Component\Form\FormView;
class ProductController extends Controller
{
/**
* #Route("/product/new", name="app_product_new")
*/
public function newAction(Request $request)
{
$product = new Product();
$form = $this->createForm(new ProductType(), $product);
$form->handleRequest($request);
if ($form->isValid()) {
// $file stores the uploaded PDF file
/** #var Symfony\Component\HttpFoundation\File\UploadedFile $file */
$file = $product->getBrochure();
// Generate a unique name for the file before saving it
$fileName = md5(uniqid()).'.'.$file->guessExtension();
// Move the file to the directory where brochures are stored
$brochuresDir = $this->container->getParameter('kernel.root_dir').'/../web/uploads/brochures';
$file->move($brochuresDir, $fileName);
// Update the 'brochure' property to store the PDF file name
// instead of its contents
$product->setBrochure($fileName);
// ... persist the $product variable or any other work
return $this->redirect($this->generateUrl('app_product_list'));
}
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->redirect($this->generateUrl('upload_file_success'));
}
return $this->render('UploadFileBundle:Product:new.html.twig', array(
'form' => $form->createView(),
));
}
}
Your logic is wrong.
Try this code:
<?php
// src/AppBundle/Controller/ProductController.php
namespace Upload\FileBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Upload\FileBundle\Entity\Product;
use Upload\FileBundle\Form\ProductType;
use Symfony\Component\Form\FormView;
class ProductController extends Controller
{
/**
* #Route("/product/new", name="app_product_new")
*/
public function newAction(Request $request)
{
$product = new Product();
$form = $this->createForm(new ProductType(), $product);
if ($request->isMethod(Request::POST))
{
$form->handleRequest($request);
if ($form->isValid()) {
// $file stores the uploaded PDF file
$file = $product->getBrochure();
/* #var Symfony\Component\HttpFoundation\File\UploadedFile $file */
// Generate a unique name for the file before saving it
$fileName = md5(uniqid()).'.'.$file->guessExtension();
// Move the file to the directory where brochures are stored
$brochuresDir = $this->container->getParameter('kernel.root_dir').'/../web/uploads/brochures';
$file->move($brochuresDir, $fileName);
// Update the 'brochure' property to store the PDF file name
// instead of its contents
$product->setBrochure($fileName);
// ... persist the $product variable or any other work
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->redirect($this->generateUrl('app_product_list'));
}
}
return $this->render('UploadFileBundle:Product:new.html.twig', array(
'form' => $form->createView(),
));
}
}
I also recommend using VichUploaderBundle
https://github.com/dustin10/VichUploaderBundle/blob/master/Resources/doc/index.md
Because your logic is wrong. You check form in first if and redirect code to list page. But your code can not work second if ever.
I want to separate form validation logic:
public function contactAction()
{
$form = $this->createForm(new ContactType());
$request = $this->get('request');
if ($request->isMethod('POST')) {
$form->submit($request);
if ($form->isValid()) {
$mailer = $this->get('mailer');
// .. setup a message and send it
return $this->redirect($this->generateUrl('_demo'));
}
}
return array('form' => $form->createView());
}
I want to translate into 2 separate actions:
public function contactAction()
{
$form = $this->createForm(new ContactType());
return array('form' => $form->createView());
}
public function contactSendAction()
{
$form = $this->createForm(new ContactType());
$request = $this->get('request');
if ($request->isMethod('POST')) {
$form->submit($request);
if ($form->isValid()) {
$mailer = $this->get('mailer');
// .. setup a message and send it using
return $this->redirect($this->generateUrl('_demo'));
}
}
// errors found - go back
return $this->redirect($this->generateUrl('contact'));
}
The problem is that when errors exist in the form - after form validation and redirect the do NOT showed in the contactAction. (probably they already will be forgotten after redirection - errors context will be lost)
If you check out how the code generated by the CRUD generator handles this you will see that a failed form validation does not return a redirect but instead uses the same view as the GET method. So in your example you would just:
return $this->render("YourBundle:Contact:contact.html.twig", array('form' => $form->createView()))
rather than return the redirect. This means you do not lose the form errors as you do in a redirect. Something else the CRUD generator adds is the Method requirement which means you could specify that the ContactSendAction requires the POST method and thus not need the extra if($request->isMethod('POST')){ statement.
You can also just return an array if you specify the template elsewhere, for example you could use the #Template annotation and then just
return array('form' => $form->createView())
This seems to work for me in Symfony 2.8:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class MyController extends Controller {
public function templateAction()
{
$form = $this->createForm(new MyFormType(), $myBoundInstance);
if ($session->has('previousRequest')) {
$form = $this->createForm(new MyFormType());
$form->handleRequest($session->get('previousRequest'));
$session->remove('previousRequest');
}
return array(
'form' => $form->createView(),
);
}
public function processingAction(Request $request)
{
$form = $this->createForm(new MyFormType(), $myBoundInstance);
$form->handleRequest($request);
if ($form->isValid()) {
// do some stuff
// ...
return redirectToNextPage();
}
$session->set('previousRequest', $request);
// handle errors
// ...
return redirectToPreviousPage();
}
}
Please note that redirectToNextPage and redirectToPreviousPage, as well as MyFormType, are pseudo code. You would have to replace these bits with your own logic.
I want to update the single entity field using ajax. Basically I don't have form, Simply I am triggering ajax by clicking link passing id and value. But I have mutiple file fields in entity form. So while I update the entity PrePersist and PostPersist functions are triggering for file upload. I don't want to do this on this update.
My Controller Action
public function ajaxupdateAction(Request $request){
$data = $request->query->get('data');
$id = $data['id'];
$em = $this->getDoctrine()->getManager();
$entry = $em->getRepository('RootContestBundle:Entry')->find($id);
if (!$entry) {
throw $this->createNotFoundException('Unable to find Entry entity.');
}
$form = $this->createFormBuilder(array('id' => $id,'is_liked'=>true))
->add('id', 'hidden')
->add('is_liked','hidden')
->getForm();
$entry->setIsLiked(true);
$form->bind($this->getRequest());
$em->persist($entry);
$em->flush();
return new JsonResponse(array('reverse'=>'dislike'));
}
What I am doing wrong, How can I solve this !
Here you got an documentation about the form event subscribers:
http://symfony.com/doc/2.0/cookbook/form/dynamic_form_generation.html
Use the postBind event.
Then check if the form isValid()
If it is valid call your service responsible for file upload.
Here is how I did this:
public function postBind(FormEvent $event)
{
$data = $event->getData();
$form = $event->getForm();
$file = $form->get('upload')->getData();
if($file && $form->isValid())
{
$result = $this->upload->uploadFile($file);
$data->setUpload($result);
}
$event->setData($data);
}
My method has the upload service injected by DI and assigned to variable $this->upload.