symfony2 don't validate file upload on update - symfony

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.

Related

Bind an object to a Symfony form

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());
}

How to load 'isSubmitted()-method' (defined in service controller) into the main controller?

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

SF2 services and doctrine

Welcome,
I created a few projects in sf2 (2.4-2.8). The code was different quality...
I read few articles. Now I try to minimize the code in the controller. I use Repository, Services etc. When I use with the services, don't injects doctrine, forwards object. In the controller initializes forms, objects, services, check validation forms and returns values to template. But I have functionalities which I must generate query in the loop or I need many query, which can not be combined into one.
My structure folder: Controller, Services, Repository, Entity, Form, Resources.
How can I reconcile all this? Minimum controller, functionalities in the services and Repository to Entity.
Example ugly code controller:
/**
* #Route("/add", name="controller_admin_page_add")
* #Template()
* #param Request $request
*/
public function addAction(Request $request) {
$page = new Page;
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new FormPage, $page);
$form->handleRequest($request);
if ($request->isMethod("POST") && $form->isValid()) {
$links = $em->createQuery("...")->getResult();
foreach($link as links){
if(...){
$checkLink = $em->createQuery("...")->getResult();
...
}
.....
}
$em->persist($page);
$em->flush();
return $this->redirectToRoute('controller_admin_page_index');
}
return array(
'form' => $form->createView()
);
}
Example nicer code:
/** ...
*/
public function addAction(Request $request) {
$page = new Page;
$em = $this->getDoctrine()->getManager();
$form = $this->createForm(new FormPage, $page);
$form->handleRequest($request);
if ($request->isMethod("POST") && $form->isValid()) {
$generateUrl = $this->container->get('Url');
$generateUrl->checkLink($page);
$generateUrl->getUrl();
$em->persist($page);
$em->flush();
return $this->redirectToRoute('controller_admin_page_index');
}
return array(
'form' => $form->createView()
);
}
Here is problem.
The functionality takes over Services. In the "clean architecture", I should pass an object/objects to the Services. But I must send query in loop.
In my opinion I need 2 types classes helper in project.
1). Gets the object /objects by setters and returns the processed data. Class doesn't have access to the doctrine.
2) Gets arguments, created query and returns the processed data. Class have access to the doctrine.
In the project I have Repository, they only return the objects.
I have a problem with the class name, directory name, and using it.
Can someone please help?

Symfony2 update row from array

I want update row setting new values from array, now Iset one by one aribute:
$em = $this->getDoctrine()->getManager();
$company = $em->getRepository('CatalogWebBundle:ComCompany')
->findOneBy(
array('cmpCode' => $id)
);
$company->setCmpName($_POST['name']);
$company->setCmpCode($_POST['code']);
$em->flush();
Maybe exist solution to set all atributes from array, some like this ?
$company = $_POST;
Consider using Symfony Form and use like this:
<?php
$request = $this->getRequest(); // or inject Request to the action method like myAction(Request $request)
$em = $this->getDoctrine()->getManager();
$company = $em->getRepository('CatalogWebBundle:ComCompany')
->findOneBy(
array('cmpCode' => $id)
);
$form = $this->createForm('formName', $company);
$form->handleRequest($request);
if($form->isValid()) {
// if you want, you can get entity here,
// but passing an entity in 2nd param of createForm
// provides automatic binding data
$data = $form->getData();
$em->flush();
// do some action after submitting form...
return $this->redirect($this->generateUrl('companies'));
}
Read more about creating forms:
http://symfony.com/doc/current/book/forms.html
And about regitering forms as services for futher use named form in createForm('NAME_HERE', $bindObjectHere):
http://symfony.com/doc/current/book/forms.html#defining-your-forms-as-services

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