On update don't update an entity replace it - symfony

I have a Branch entity that has an Address entity, one address can be link to many other types of entities, what I want to do is when I edit the Address in the Branch entity instead of editing the address with the new data I want to create a new Address entity and attach it to the Branch, what is happening right now is that its editing the address, the problem with this is that I have other entities linked to that address.
This is my form:
class MBBranchType extends AbstractType{
protected $em;
function __construct(EntityManager $em){
$this->em = $em;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('branchName')
->add('branchCode')
->add('destiny', 'entity', array(
'class' => 'ATRBundle:Destiny',
'empty_value' => '-- Seleccione --',
'mapped' => true,
'query_builder' => function(EntityRepository $er){
return $er->createQueryBuilder('d')
->orderBy('d.destinyDesc', 'ASC');
}))
->add('startOperation', 'text')
->add('stopOperation', 'text', array('required' => ''))
->add('authorizationL1', 'checkbox', array('required' => ''))
->add('authorizationL2', 'checkbox', array('required' => ''))
->add('authorizationL3', 'checkbox', array('required' => ''))
->add('address', new AddressType($this->em, new Address()), array('required' => ''))
->add('active', 'checkbox', array('required' => ''));
$builder->get('startOperation')->addModelTransformer(new StringToDateTransformer());
$builder->get('stopOperation')->addModelTransformer(new StringToDateTransformer());
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MB2\ATRBundle\Entity\MBBranch'
));
}
/**
* #return string
*/
public function getName()
{
return 'mb2_atr_mb_branch';
}
}
This is my Action
public function editMBBranchAction()
{
$id = $this->request->query->get('id');
$entity = $this->em->getRepository('ATRBundle:MBBranch')->find($id);
$form = $this->createForm(new MBBranchType($this->getDoctrine()->getManager()), $entity);
$form->handleRequest($this->request);
if ($form->isValid()) {
if($entity instanceof MBBranch){
$addressEntity = $this->em->getRepository('ATRBundle:Address')->findOneBy(
array('street'=>(string)$entity->getAddress()->getStreet()
, 'exteriorNum' => $entity->getAddress()->getExteriorNum();
, 'interiorNum' => $entity->getAddress()->getInteriorNum();
, 'settlment' => $entity->getAddress()->getSettlment()
)
);
if($addressEntity instanceof \MB2\ATRBundle\Entity\Address){
$entity->setAddress($addressEntity);
}else{
$otherAddress = new Address();
$otherAddress->setStreet($entity->getAddress()->getStreet());
$otherAddress->setExteriorNum($entity->getAddress()->getExteriorNum());
$otherAddress->setInteriorNum($entity->getAddress()->getInteriorNum());
$otherAddress->setSettlment($entity->getAddress()->getSettlment());
$entity->setAddress($otherAddress);
}
$this->em->flush();
}
return $this->redirect($this->generateUrl('admin', array('action' => 'list', 'entity' => $this->entity['name'])));
}
return $this->render($this->entity['templates']['edit'], array(
'form' => $form->createView(),
'entity' => $entity,
));
}
As you can see it checks if the new Address entity exist, if it does exist it sets it on the $entity->setAddress($addressEntity);, If it does not exist it created a new Address() and sets the values, This does work, it created a new Address and saves it on the table, but for some reason it also updateing the old Address entity.

I found the solution
I added a $this->em->detach($entity->getAddress()); before attaching a new Address, please see example.
public function editMBBranchAction()
{
$id = $this->request->query->get('id');
$entity = $this->em->getRepository('ATRBundle:MBBranch')->find($id);
$form = $this->createForm(new MBBranchType($this->getDoctrine()->getManager()), $entity);
$form->handleRequest($this->request);
if ($form->isValid()) {
if($entity instanceof MBBranch){
$this->em->detach($entity->getAddress());
$addressEntity = $this->em->getRepository('ATRBundle:Address')->findOneBy(
array('street'=>(string)$entity->getAddress()->getStreet()
, 'exteriorNum' => $entity->getAddress()->getExteriorNum();
, 'interiorNum' => $entity->getAddress()->getInteriorNum();
, 'settlment' => $entity->getAddress()->getSettlment()
)
);
if($addressEntity instanceof \MB2\ATRBundle\Entity\Address){
$entity->setAddress($addressEntity);
}else{
$otherAddress = new Address();
$otherAddress->setStreet($entity->getAddress()->getStreet());
$otherAddress->setExteriorNum($entity->getAddress()->getExteriorNum());
$otherAddress->setInteriorNum($entity->getAddress()->getInteriorNum());
$otherAddress->setSettlment($entity->getAddress()->getSettlment());
$entity->setAddress($otherAddress);
}
$this->em->flush();
}
return $this->redirect($this->generateUrl('admin', array('action' => 'list', 'entity' => $this->entity['name'])));
}
return $this->render($this->entity['templates']['edit'], array(
'form' => $form->createView(),
'entity' => $entity,
));
}

Related

How to set a value for entity field in a form? Symfony2

I have 3 tables realated, inProducto, inProveedor and InProveedorProducto, here my relashionship:
inProveedorProducto:
class InProveedorProducto
{
/**
* #ORM\ManyToOne(targetEntity="InProducto", inversedBy="InProveedorProducto")
* #ORM\JoinColumn(name="id_producto", referencedColumnName="id_producto")
*/
protected $producto;
/**
* #ORM\ManyToOne(targetEntity="InProveedor", inversedBy="InProveedorProducto")
* #ORM\JoinColumn(name="id_proveedor", referencedColumnName="id")
*/
protected $proveedor;
InProveedor:
class InProveedor
{
/**
* #ORM\OneToMany(targetEntity="InProveedorProducto", mappedBy="InProveedor", cascade={"persist"})
*/
protected $proveedorProducto;
public function __construct()
{
$this->proveedorProducto = new ArrayCollection();
}
And InProducto:
class InProducto
{
/**
* #ORM\OneToMany(targetEntity="InProveedorProducto", mappedBy="InProducto", cascade={"persist"})
*/
protected $producto;
public function __construct()
{
$this->producto = new ArrayCollection();
}
My problem is that I have to open a new Form for inProveedorProducto, but idProveedor field should be automatic from prior selection of user.
My controller:
public function newAction()
{
$entity = new InProveedorProducto();
$form = $this->createCreateForm($entity);
$form->get('idProveedor')->setData(1);
return $this->render('NivalInventarioBundle:InProveedorProducto:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
When I open de form, the first field which is idProveedor appears filled out with the number 1.
THen we select the idProducto and put the price, but when try to create:
Error:
An exception occurred while executing 'INSERT INTO in_proveedor_producto (id_proveedor, id_producto, precio_compra) VALUES (?, ?, ?)' with params [null, 21, 1]:
It seems like idProveedor is comming NULL.
My inProveedorProducto type:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('idProveedor')
->add('producto', 'entity', array(
'class' => 'NivalInventarioBundle:InProducto',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.nombre', 'ASC');
},
'choice_label' => 'nombre',
'by_reference' => true,
'expanded' => false,
'placeholder' => 'Seleccione una opciĆ³n',
'mapped' => true,
'multiple' => false
))
->add('precioCompra')
;
Please help me.
Regards,
Operate with a model, not with a form data.
public function newAction()
{
$entity = new InProveedorProducto();
$entity->setProveedor($this->get('doctrine')->getRepository('NivalInventarioBundle:InProveedor')->find(1));
$form = $this->createCreateForm($entity);
return $this->render('NivalInventarioBundle:InProveedorProducto:new.html.twig', array(
'entity' => $entity,
'form' => $form->createView(),
));
}
And then just
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('proveedor')
->add('producto')
->add('precioCompra')
;

symfony2 + EntityType + queryBuilder and default top value/entry

I have an entity (Category) where the user can choice a parent (always Category) for the new/edit action where the link is the vocabolaryId field.
This is my CategoryType.
class CategoryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$vocId = $options['data']->getVocabularyId();
$builder
->add('name')
->add('vocabularyId',HiddenType::class,[
'data' => $vocId,
])
->add('description')
->add('weight',null,[
'label' => 'Posizione'
])
;
$builder->add('parent',EntityType::class,array(
'class' => 'AppBundle:Category',
'query_builder' => function (EntityRepository $er) use ($vocId) {
return $er->createQueryBuilder('c')
->where('c.vocabularyId = ?1')
->orderBy('c.name')
->setParameter(1,$vocId);
}
));
}
To get the list of all category that have the same vocabularyId I use the "query_builder" parameter.
When I submit the form to symfony without choice a parent (or with an empty table) it replies me with : " This value is not valid." (for the parent field).
How can I set a "null" parent ? I mean a category that have no parent.
EDIT:I have added "'required' => false," like say by Stephan Vierkant, but now I have another error: "Warning: spl_object_hash() expects parameter 1 to be object, string given"
this is my controller's newAction function:
/**
* Creates a new Category entity.
*
* #Route("/new", name="admin_category_new")
* #Method({"GET", "POST"})
*/
public function newAction(Request $request, $vocId)
{
$category = new Category($vocId);
$form = $this->createForm('AppBundle\Form\CategoryType', $category);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
dump($category);
exit();
$em->persist($category);
$em->flush();
return $this->redirectToRoute('admin_category_show', array('vocId' => $vocId, 'id' => $category->getId()));
}
return $this->render('category/new.html.twig', array(
'category' => $category,
'form' => $form->createView(),
'vocId' => $vocId
));
}
Set required (docs) to false:
$builder->add('parent',EntityType::class,array(
'class' => 'AppBundle:Category',
'required' => false,
'query_builder' => function (EntityRepository $er) use ($vocId) {
return $er->createQueryBuilder('c')
->where('c.vocabularyId = ?1')
->orderBy('c.name')
->setParameter(1,$vocId);
}
));
You can set a placeholder (docs) if you don't want an empty option.

Controller - No access in class - Entity

I got this error message, but I don't really understand why.
Neither the property "categories" nor one of the methods "addCategory()"/"removeCategory()", "setCategories()", "categories()", "__set()" or "__call()" exist and have public access in class "Checkout\Bundle\ItemBundle\Entity\Item".
The thing is, in my entity "Item" I really have all of this stuff:
/**
* #ORM\ManyToMany(targetEntity="Checkout\Bundle\ItemBundle\Entity\Category", mappedBy="items")
**/
private $categories;
and
/**
* Add categories
*
* #param Category $categories
* #return Item
*/
public function addCategory(Category $categories)
{
$this->categories[] = $categories;
return $this;
}
/**
* Remove categories
*
* #param Category $categories
*/
public function removeCategory(Category $categories)
{
$this->categories->removeElement($categories);
}
/**
* Get categories
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}
Okay, okay - and what is in my Controller?
/**
* Creates a new Item entity.
*
* #Route("/create", name="item_create")
* #param Request $request
* #return \Symfony\Component\HttpFoundation\Response
*/
public function createAction(Request $request)
{
$entity = new Item();
$currentUser = $this->getUser();
$form = $this->createFormBuilder($entity)
->add('name', null, array(
'label' => 'Item Name',
'required' => true,
))
->add('categories', 'entity', array(
'label' => 'Select a Category',
'required' => false,
'class' => 'CheckoutItemBundle:Category',
'property' => 'name',
'query_builder' => function (EntityRepository $er) use ($currentUser) {
return $er->createQueryBuilder('c')
->where('c.user = :user')
->setParameter('user', $currentUser);
},
))
->add('submit', 'submit', array('label' => 'Speichern'))
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
}
return $this->render(
'CheckoutItemBundle:Item:create.html.twig',
array(
'entity' => 'entity',
'form' => $form->createView()
)
);
}
So, the big question is, why he say that he didn't find it, when it is obviously there. Any idea? Thank you in advance!
->add('categories', 'entity', array(
'label' => 'Select a Category',
'required' => false,
'class' => 'CheckoutItemBundle:Category',
'property' => 'name',
'multiple' => true,
'query_builder' => function (EntityRepository $er) use ($currentUser) {
return $er->createQueryBuilder('c')
->where('c.user = :user')
->setParameter('user', $currentUser);
},
))
You have a Many-To-Many relation, but your form expects a Many-To-One. To fix this behavior need to set multiple to true.

Symfony 2 - Gedmo Uploadable error durng edition

I have everything configured as in documentation and everything works perfect if I upload all files.
But when I want change only other elements in form without changing photo i have received following error message:
You must pass an instance of FileInfoInterface or a valid array for entity of class
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('CmUserBundle:User')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find User entity.');
}
$deleteForm = $this->createDeleteForm($id);
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
$container = $this->container;
if ($editForm->isValid()) {
$uploadableManager = $this->get('stof_doctrine_extensions.uploadable.manager');
$uploadableManager->markEntityToUpload($entity, $entity->getPath());
$em->flush();
return $this->redirect($this->generateUrl('user_edit', array('id' => $id)));
}
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
Form clas:
<?php
namespace AppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class UserType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('email', null, array('attr' => array('class' => 'form-control')))
->add('username', null, array('attr' => array('class' => 'form-control')))
->add('path', 'file', array(
'data_class' => null
))
->add('firstName', null, array('attr' => array('class' => 'form-control')))
->add('lastName', null, array('attr' => array('class' => 'form-control')))
->add('localization', null, array('attr' => array('class' => 'form-control')))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'CmUserBundle\Entity\User',
));
}
/**
* #return string
*/
public function getName()
{
return 'appbundle_user';
}
}
How to prevent from update entity by empty input fields? during editForm->handleRequest($request);
Any ideas?
Try $form->submit($request->request->all(), false) instead of $form->handleRequest($request). This will prevent from clearing entity's properties which are not present in incoming POST data.

Showing name and saving id in symfony dropdown

I want to show the 'name' of my departments as a dropdown to my users and when they choose one, save its 'id' into the database. How can i do that? Below is my code. Currentlt its showing id and saving id.
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('adress')
->add('city')
->add('area')
->add('departments', 'entity', array(
'empty_value' => '',
'class' => 'YdyaHospitalBundle:Department',
'query_builder' => function($repository) { return $repository->createQueryBuilder('t')->orderBy('t.id', 'ASC'); },
'property' => 'id',
'multiple' =>false,
'expanded' =>true,
))
;
}
Update
My controller action:
/**
* Creates a new Hospitals entity.
*
* #Route("/", name="hospitals_create")
* #Method("POST")
* #Template("YdyaHospitalBundle:Hospitals:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Hospitals();
$form = $this->createForm(new HospitalsType(), $entity);
$form->bind($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('hospitals_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
/**
* Displays a form to create a new Hospitals entity.
*
* #Route("/new", name="hospitals_new")
* #Method("GET")
* #Template()
*/
public function newAction()
{
$entity = new Hospitals();
$form = $this->createForm(new HospitalsType(), $entity);
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
You can either implement a __toString() for your entity, or specify the property to display with:
->add('departments', 'entity', array(
'empty_value' => '',
'class' => 'YdyaHospitalBundle:Department',
'query_builder' => function($repository) { return $repository->createQueryBuilder('t')->orderBy('t.id', 'ASC'); },
// 'property' => 'id', --> Remove this
'multiple' => false,
'expanded' => true,
'property' => 'name' // Property used to display the entity
))
In your Controller you'll still be able to save your entity or the id of your entity to the db.
See documentation: http://symfony.com/doc/current/reference/forms/types/entity.html#property

Resources