Symfony: call form handleRequest but avoid entity persist - forms

I have an entity that models a search form and a form type, I use that form for searching purposes only and I don't want that entity to be modified in database, so, when I do this:
$formModelEntity = $em->getRepository('AppBundle:SearchForm')
->findOneBy(array('name' => 'the_model'));
$formModelForm = $this->createForm(new SearchFormType(), $formModelEntity, array('action' => $this->generateUrl('dosearch'), 'method' => 'POST'));
$formModelForm->handleRequest($request); //or ->submit($request);
if ($formModelForm->isValid())
{
$formInstanceEntity->setFieldsFromModel($formModelEntity);
$em->persist($formInstanceEntity);
$em->flush();
}
The $formModelEntity changes are persisted to database, I want to avoid this but still want to take advantage of handleRequest ability to update the entity with all POST values (for read only purposes).
Is this possible?

In symfony, you only have to persist a new entity. If you update an existing entity found by your entity manager and then flush, your entity will be updated in database even if you didn't persist it.
Edit : you can detach an entity from the entity manager before flushing it using this line of code :
$em->detach($formModelEntity);

the method handleRequest Does not save the changes. it only updates the object within your method.
public function newAction(Request $request)
{
// just setup a fresh $task object (remove the dummy data)
$task = new Task();
$form = $this->createFormBuilder($task)
->add('task', TextType::class)
->add('dueDate', DateType::class)
->add('save', SubmitType::class, array('label' => 'Create Task'))
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
// ... perform some action, such as saving the task to the database
return $this->redirectToRoute('task_success');
}
return $this->render('default/new.html.twig', array(
'form' => $form->createView(),
));
}
the following snippet exists at http://symfony.com/doc/current/book/forms.html
and as you can see the entity is not persisted.
You're are probably adding a persist/flush and that's what's causing the entities to be updated.

Related

Symfony 4: Embed form child Create New On Update

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

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

field array type in entity for form choice type field symfony

I would like to create a UserForm for create user in my system backend.
I use a entity with a 'role' field as type array
I want use a select choice field type Form with that entity field.
I use a transformer class system for convert data between Entity and form.
but I turn around in my head and nothing run correctly.
When I use options 'multiple' of choice type, my field display correctly but I don't want to display and select multiple value for this field.
I have Notice: Undefined offset: 0 error
or
I have ContextErrorException: Notice: Array to string conversion
Here few essential code :
UserForm class
$builder->add($builder->create('roles', 'choice', array(
'label' => 'I am:',
'mapped' => true,
'expanded' => false,
'multiple' => false,
'choices' => array(
'ROLE_NORMAL' => 'Standard',
'ROLE_VIP' => 'VIP',
)
))->addModelTransformer($transformer));
transformer Class
class StringToArrayTransformer implements DataTransformerInterface
{
public function transform($array)
{
return $array[0];
}
public function reverseTransform($string)
{
return array($string);
}
}
controller method
$user = new User(); //init entity
$form = $this->createForm(new UserForm(), $user);
$form->handleRequest($request);
if ($form->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($form);
$em->flush();
return $this->redirect($this->generateUrl('task_success'));
}
entity part
/**
* #ORM\Column(name="roles", type="array")
*/
protected $roles;
public function getRoles()
{
return $this->roles;
}
public function setRoles(array $roles)
{
$this->roles = $roles;
return $this;
}
My field roles entity must be a array for run correctly the security component Symfony
can you help me to understand why this field form refuse to display ?
I already readed others questions in same issue but there is anything that I don't understand because nothing help me to resolve my problem.
If you can help me with MY particular context...
Thank for support
because security symfony component integration
If you only need the "getRoles" method because of the interface you are implementing, it is simpler (and cleaner) to do the following:
Change the entities field again to role with type string
Rename your getter and setter to getRole() and setRole()
and add a getRoles method like this:
public function getRoles()
{
return array($this->role);
}
In your form type, change the field name to "role" and 'multiple' => false
Remove your model transformer
This should be the solution ;)

Symfony2 Doctrine2 Many To Many Form not Saving Entities

I am having some trouble with a many to many relationship. I have Users and Assets. I would like to be able to assign users to an asset on the asset page.
The code below displays a list of users when creating/editing an asset, however changes made to the user checkboxes do not save, while the rest of the data is persisted.
If I add an entry to users_assets through the mysql client, these changes are shown in the asset list.
User
class User extends BaseUser
{
/**
* #ORM\ManyToMany(targetEntity="Asset", inversedBy="users")
*/
private $assets;
}
Asset
class Asset
{
/**
* #ORM\ManyToMany(targetEntity="User", mappedBy="assets")
*/
private $users;
}
AssetType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$form = $builder
->add('users', null, array(
'expanded' => true,
'multiple' => true
))
->getForm();
return $form;
}
For some reason I had to switch the doctrine mappings to get this to work:
Asset:
/**
* #ORM\ManyToMany(targetEntity="Adaptive\UserBundle\Entity\User", inversedBy="assets")
* #ORM\JoinTable(name="user_assets")
*/
private $users;
User:
/**
* #ORM\ManyToMany(targetEntity="Splash\SiteBundle\Entity\Asset", mappedBy="users")
*/
private $assets;
Now when I save the asset it saves the users associated. I did not need to define builder->add as an entity or collection. I simply pass it null and it uses the mapping info to fill in the entity info:
AssetType:
->add('users', null, array('expanded' => "true", "multiple" => "true"))
Not exactly sure why I needed to have the inversedBy and JoinTable info on the Asset vs The User but it seems to be working now!
Thanks For The Suggestions!!!
Weird enough I faced the same problem in 2016 and still had hard time finding the solution. I will share it for future googlers:
The problem is that what symfony essentially does when you save the form is this:
$asset->getUsers()->add($user)
And because you're on the inverse side of the relation it won't persist your changes.
What you really need is to make so that it calls this:
$asset->addUser($user)
Where addUser() is defined the following way on the Asset entity:
public function addUser(User $user)
{
//add to the inverse side
$this->users->add($user);
//add on the owning side (only this is persisted)
$user->addAsset($this); //$user->assets->add($asset);
}
So in order to make symfony use that $asset->addUser() method, you should set
'by_reference' => false
on your users field for AssetType form.
More about this setting here http://symfony.com/doc/current/reference/forms/types/form.html#by-reference
Remember you also need to define removeUser() method in the same way (so that it removes entity from the owning relation)
Not exactly sure why I needed to have the inversedBy and
JoinTable info on the Asset vs The User but it
seems to be working now!
The reason why your changes has been ignored is that doctrine persists only changes by the owning side of a relation (like #Florian said).
This is the link to Doctrine's documentation where this behaviour is explained: http://docs.doctrine-project.org/en/latest/reference/unitofwork-associations.html
At first you should drop backslash prefix in annotations (see notice here).
And you need to use entity field type:
$builder->add('users', 'entity', array(
'class' => 'AdaptiveUserBundle:User',
'expanded' => true,
'multiple' => true,
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.username', 'ASC');
},
));
You need to use 'collection' field type in your form.
$builder->add('users', 'collection', array(
'type' => new UserType(),
'prototype' => true,
'allow_add' => true,
'allow_delete' => true
));
You need to create the UserType() form first obviously.
Here is all the info you will need, including code samples:
http://symfony.com/doc/current/cookbook/form/form_collections.html
http://symfony.com/doc/current/reference/forms/types/collection.html

Symfony 2 form + showing data from a relation

I am using Symfony 2 with doctrine. I currently have an entity called Worker and in the Worker entity there is a Many To One relationship with a User entity.
/**
* #ORM\ManyToOne(targetEntity="User")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
There are more entities like Worker as well such as Manager and such. I want to create a form that creates a Job entity. In the form I am trying to create a select option that selects a Worker, but the worker's name is stored in the user database. Is there any way to print the worker's name from the user database in the form options.
$builder->add('workers','entity', [
'label' => 'Workers:',
'property' => 't.user.firstName',
'empty_value' => 'Choose a Worker',
'class' => 'Company\CompanyBundle\Entity\Worker',
'query_builder' => function (\Company\CompanyBundle\Repository\WorkerRepository $repository) {
return $repository->createQueryBuilder('t')
->add('orderBy', 't.user.firstName ASC');
}
]);
Any ideas?
I think that it would be enoough to do something like this:
$builder->add('workers', 'entity', array(
'class' => 'Company\CompanyBundle\Entity\Worker',
) );
Besides, you should implement a "__toString()" method in your Worker entity where you would return whatever you want to show (in this case, the worker name), so your __toString method in the Worker entity would be something like this:
function __toString() {
return $this->getName();
}
It's the way I usually implement this kind of relations, I hope it helps!
If you prefer, you could do this other option:
$builder->add('workers', 'entity', array(
'class' => 'Company\CompanyBundle\Entity\Worker',
'property' => 'property_name'
));
If you defined the option "property" you don't need implement the "_toString()" in the entity class