ManyToMany, duplicate entry, table empty - forms

Soo :
I have my two tables/entities texts and groups which are linked by a manytomany relationship.
I have a form where the users fill checkboxes to assign a text into one or several groups.
I have a problem though it's getting me this error
An exception occurred while executing 'INSERT INTO texte_groupe
(texte_id, groupe_id) VALUES (?, ?)' with params [2, 1]:
Here is the core of the problem ( i think?)
public function AcceptMediaAction($id) {
$em = $this->getDoctrine()->getManager();
$texte = new Texte();
$securityContext = $this->container->get('security.context');
$texte = $em->getRepository('EVeilleurDefuntBundle:Texte')->find($id);
$form = $this->createForm( new ChooseGroupeType($securityContext), $texte );
$request = $this->get('request');
$form->bind($request);
if ($request->getMethod() == 'POST') {
$groupes = $texte->getGroupes();
$statut = $texte->getStatut();
foreach ($groupes->toArray() as $groupe)
{
$texte->addGroupe($groupe);
}
$em->persist($groupe);
$em->flush();
return $this->redirect($this->generateUrl('e_veilleur_defunt_gerer_medias',
Groupe.php
/**
* #ORM\ManyToMany(targetEntity="EVeilleur\DefuntBundle\Entity\Texte",mappedBy="groupes")
*/
private $textes;
Texte.php
/**
* #ORM\ManyToMany(targetEntity="EVeilleur\DefuntBundle\Entity\Groupe",inversedBy="textes")
*/
private $groupes;
formtype
public function buildForm(FormBuilderInterface $builder, array
$options)
{
// $builder->add('statut','choice', array('choices'=> array('nonValide'=>'non Valide',
// 'Valilde'=>'suchValidation'),
// 'required'=>'true'
// )
// ) ; // , array("attr" => array("multiple" => "multiple", ))
$user = $this->securityContext->getToken()->getUser();
if (!$user) {
throw new \LogicException(
'This cannot be used without an authenticated user!'
);
}
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($user) {
$form = $event->getForm();
$formOptions = array(
'multiple' => true, //several choices
'expanded' => true, // activate checkbox instead of list
'by_reference' => false,
'required' => true|false,
'class' => 'EVeilleur\DefuntBundle\Entity\Groupe',
'query_builder' => function (EntityRepository $er) use ($user) {
// build a custom query
return $er->createQueryBuilder('u')->add('select', 'u')
->add('from', 'EVeilleurDefuntBundle:Groupe u');
// ->add('where', 'u.id = ?1')
// ->add('orderBy', 'u.name ASC');
},
);
// create the field, = $builder->add()
// field name, field type, data, options
$form->add('groupes', 'entity', $formOptions);
}
);
}
Thanks

Try with:
foreach ($groupes->toArray() as $groupe) {
if (!in_array($groupe, $texte->getGroupe()->toArray()) {
$texte->addGroupe($groupe);
}
}

Related

Dynamic generation for submitted forms: $event->getData() returns null

I'm trying to add a city to a User class that extends the BaseUser from FOSUserBundle, and i'm following the guide in this page:
http://symfony.com/doc/current/form/dynamic_form_modification.html#form-events-submitted-data
I've made a RegistrationType class, with the following code:
public function buildForm(FormBuilderInterface $builder, array $options)
{
/* i setted a name field just to check that this form builder is used then i try to create a user */
$builder->add('name');
$builder->add('provincia', EntityType::class, array(
'class' => 'AppBundle\Entity\State',
'placeholder' => '', #
));
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) {
$form = $event->getForm();
$data = $event->getData();
$state = $data->getState();
$cities = null === $state ? array() : $state->getCities();
$form->add('city', EntityType::class, array(
'class' => 'AppBundle\Entity\City',
'placeholder' => '',
'choices' => $cities,
));
}
);
//...
}
The thing is that when it throws me an error in $data->getState(), it tells me "Error: Call to a member function getState() on null".
What could be happening?
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('name');
$builder->add('state', EntityType::class, array(
'class' => 'AppBundle\Entity\State',
'mapped' => false,
'placeholder' => '', #
));
$formModifier = function (FormInterface $form, State $state= null) {
$cities = null === $state? array() : $state->getCities();
$form->add('city', EntityType::class, array(
'class' => 'AppBundle\Entity\City',
'placeholder' => '-Choose a state-',
'choices' => $cities,
));
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier) {
$data = $event->getData();
if($data === null || !method_exists($data, 'getState')) {
$formModifier($event->getForm(), null);
} else {
$formModifier($event->getForm(), $data->getProvincia());
}
}
);
$builder->get('state')->addEventListener(
FormEvents::POST_SUBMIT,
function (FormEvent $event) use ($formModifier) {
// It's important here to fetch $event->getForm()->getData(), as
// $event->getData() will get you the client data (that is, the ID)
$state = $event->getForm()->getData();
// since we've added the listener to the child, we'll have to pass on
// the parent to the callback functions!
$formModifier($event->getForm()->getParent(), $provincia);
}
);
}
public function getParent()
{
return 'FOS\UserBundle\Form\Type\RegistrationFormType';
}
public function getBlockPrefix()
{
return 'app_user_registration';
}
public function getName()
{
return $this->getBlockPrefix();
}
}
What really drives me mad is the fact that $event->getData(), which should bring something according to the official doc example, in my case comes null. I've managed to work around this registration form to work, but now i'm having the same problem with the profile edit form argggghhhhh

Symfony2 : Save image form field in session

I want to save the form data in session in case of an error occured then I can display valid form data in my form view.
I've got a file field for an image but I've got this error when I submit my form with an image : Serialization of 'Symfony\Component\HttpFoundation\File\UploadedFile' is not allowed
My Form Type :
class ContenuType extends AbstractType
{
private $session;
public function __construct($session)
{
$this->session = $session;
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$session = $this->session;
$formSession = $session->get('dataCreateContenu');
if (!$formSession) {
$formSession = new Contenu();
}
$builder
->add('description', 'textarea', array(
'label' => 'Description',
'data' => $formSession->getDescription(),
'attr' => array('maxlength' => 560),
)
)
->add('file', 'file', array(
'label' => 'Image',
'data' => $formSession->getImage(),
'required' => false,
)
)
;
}
}
My Form Controller :
/**
* New Contenu
*
* #Route("/", name="contenu_create")
* #Method("POST")
* #Template("MyOwnBundle:Contenu:new.html.twig")
*/
public function createAction(Request $request)
{
$entity = new Contenu();
$form = $this->createCreateForm($entity);
$form->handleRequest($request);
$session = $this->get('session');
$session->set('dataCreateContenu', $form->getData());
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$formAll = $form->all();
foreach ($formAll as $formField) {
if(empty($formField->getData())) {
$this->get('session')->getFlashBag()->add('error', 'Field « '.$formField->getConfig()->getOption("label").' » is empty.');
return $this->redirect($this->generateUrl('contenu_new'));
}
}
$image = $form->get('file')->getData();
if ($image) {
$entity->upload();// Upload
}
$em->persist($entity);
$em->flush();
$session->clear();
return $this->redirect($this->generateUrl('contenu_show', array('id' => $entity->getId())));
}
return array(
'entity' => $entity,
'form' => $form->createView(),
);
}
What can I do ?

validating dynamic forms in symfony2 returns "this value is not valid"

I have 3 entities: Country, State and City with the following relationships, and i have another entity named Location which have all of theme for setting user location,
i have a form too, for getting user's location data. which should be generated dynamically, because the entities are related to each other, and for example if the state changed, the cities must be changed too.
i used the code below in my listener for doing this:
/**
* #param FormFactoryInterface $factory
* #param EntityManager $om
*/
public function __construct($factory, $om)
{
$this->factory = $factory;
$this->om = $om;
}
public static function getSubscribedEvents()
{
return array(
FormEvents::PRE_BIND => 'preBind',
FormEvents::PRE_SET_DATA => 'preSetData',
);
}
/**
* #param event FormEvent
*/
public function preSetData(FormEvent $event)
{
$company = $event->getData();
if (null === $company)
{
return;
}
// company has country => edit action
if($company->getCountry()){
//retrieve location
$country = $company->getCountry();
$state = $company->getState();
$city = $company->getCity();
if(is_object($state) && is_object($city) && is_object($country))
{
$states = $country->getStates();
$cities = $state->getCities();
}
else
{
$cities = array();
$states = array();
}
}else{
// new location action
$states = array();
$cities = array();
}
$form = $event->getForm();
$this->customizeForm($form, $cities,$states);
}
public function preBind(FormEvent $event)
{
$dataForm = $event->getData();
$countryId = $dataForm['country'];
$stateId = $dataForm['state'];
$cityId = $dataForm['city'];
$country = $this->om
->getRepository('GMBundle:Country')
->find($countryId);
$state = $this->om
->getRepository('GMBundle:State')
->find($stateId);
$city = $this->om
->getRepository('GMBundle:City')
->find($cityId);
if(is_object($state) && is_object($city) && is_object($country))
{
$states = $country->getStates();
$cities = $state->getCities();
}
else
{
$cities = array();
$states = array();
}
$form = $event->getForm();
$this->customizeForm($form, $cities, $states);
}
protected function customizeForm($form, $cities, $states)
{
$form
->add($this->factory->createNamed('state', 'entity', null, array(
'choices' => $states,
'label' => 'state',
'required' => true,
'empty_value' => 'choose state',
'class' => 'GMBundle:State',
)))
->add($this->factory->createNamed('city', 'entity', null, array(
'choices' => $cities,
'label' => 'city',
'required' => true,
'empty_value' => 'choose city',
'class' => 'GMBundle:City',
)))
;
}
when i want to edit my form, i got the error This value is not valid.
it seems that symfony doesn't changed the data, for example if user had selected X as Stated and now wants to select Y for his state, symfony said the chosen city is not valid and must be selected from X's cities, which was his previous choice.
any idea how i can resolve it? or where i'm doing something wrong!?
-thanks

How to render a choice field in a template

I use Symfony2 and twig as template engine.
In my controller I have the following form:
$usr= $this->get('security.context')->getToken()->getUser();
$associatedmissions = array($usr->getMissions());
$form = $this->createFormBuilder($product)
->add('mission', 'choice', array(
'choices' => $associatedmission,
'multiple' => false,
'expanded' => true, ))
But when I call the page, appears an error:
Catchable Fatal Error: Object of class Doctrine\ORM\PersistentCollection could not be
converted to string in
C:\BitNami\wampstack-5.4.23-
0\frameworks\symfony\vendor\symfony\symfony\src\Symfony\Component\Translation\
IdentityTranslator.php line 65
In the profiler I can see the error:
CRITICAL - Uncaught PHP Exception Twig_Error_Runtime: "An exception has been thrown
during the rendering of a template ("") in "form_div_layout.html.twig" at line 99." at
C:\BitNami\wampstack-5.4.23-0\frameworks\symfony\app\cache\dev\classes.php line 4372
Context: {"exception":"Object(Twig_Error_Runtime)"}
What happened?
It's strange because with it works properly
->add('mission', 'entity')
-UPDATE--
Here my controller:
public function createAction(Request $request)
{
$product = new Product();
$usr= $this->get('security.context')->getToken()->getUser();
$associatedmissions = array($usr->getMissions());
$form = $this->createFormBuilder($product)
->add('name', 'text')
->add('mission', 'choice', array(
'choices' => $associatedmissions,
'multiple' => false,
'expanded' => false, ))
->add('save', 'submit')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->render('AcmeGroundStationBundle:Product:tasksuccess.html.twig', array('product' => $product));
}
return $this->render('AcmeGroundStationBundle:Product:formupload.html.twig', array(
'form' => $form->createView()
));
}
aYou have this in your controller:
$usr= $this->get('security.context')->getToken()->getUser();
$associatedmissions = array($usr->getMissions());
$usr->getMissions() is returning ArrayCollection (based on relations in your Entity). This way $associatedmissions is an array with one element - [1] = ArrayCollection of related Mission Objects.
In my opinion you must add to your User entity method:
public function getMissionsArray()
{
$missionArray = array();
foreach ($this->missions as $key => $val)
{
$missionArray[$key] = $val->__toString();
}
return $missionArray;
}
And use array as choices param in your createFormBuilder statement.
When you validate your Form you have to create Mission object for every selection before persist product.
$this->getDoctrine()
->getRepository('AcmeGroundStationBundle:Mission')
->find($product->mission);
EDIT
// User Entity
// add this function - will return array of ( id => mission.name, )
public function getMissionsArray()
{
$missionArray = array();
foreach ($this->missions as $key => $val)
{
// change this to whatever human readable getter
$missionArray[$key] = $val->__toString();
}
return $missionArray;
}
// Controller
public function createAction(Request $request)
{
$product = new Product();
$usr= $this->get('security.context')->getToken()->getUser();
$associatedmissions = $usr->getMissionsArray();
$form = $this->createFormBuilder($product)
->add('name', 'text')
->add('mission', 'choice', array(
'choices' => $associatedmissions,
'multiple' => false,
'expanded' => false, ))
->add('save', 'submit')
->getForm();
$form->handleRequest($request);
if ($form->isValid()) {
// save selected array item as a Mission object related to Product
$product->setMission($this->getDoctrine()
// check if Mission Entity is placed in good bundle ;)
->getRepository('AcmeGroundStationBundle:Mission')
->find($form->get('mission')->getData()));
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->render('AcmeGroundStationBundle:Product:tasksuccess.html.twig', array('product' => $product));
}
return $this->render('AcmeGroundStationBundle:Product:formupload.html.twig', array(
'form' => $form->createView()
));
}
Good Luck!
Try to use redirect. Is it work?
if ($form->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($product);
$em->flush();
return $this->redirect($this->generatePath('current_route_name'));
}
return $this->render('AcmeGroundStationBundle:Product:formupload.html.twig', array(
'form' => $form->createView()
));
Where current_route_name is replace by your route name of current page.

Symfony2 - Form validation with query builder - value never valid

I have two entities "meeting" and "Slot" with a one2many relation.
I have a form to update a meeting (just to change the time slot), i want to display only free slot so i've made a query_ builder. It works for the creation, but for the update, there is always a validation error (this value is not valid).
This is my code :
controller
public function editAction($id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('NfidBusinessMeetingBundle:Meeting')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Meeting entity.');
}
$editForm = $this->createForm(new UpdateMeetingType($entity->getUserA(),$entity->getUserB()), $entity);
if ($this->getRequest()->isMethod('POST')) {
$editForm->bind($this->getRequest());
// var_dump($editForm->getData() );
if ($editForm->isValid()) {
$entity->setDeleted(0);
$entity->setPending(1);
$entity->setValidated(0);
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('meeting_front'));
}
}
return $this->render('NfidBusinessMeetingBundle:MeetingFront:edit.html.twig', array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
));
}
form builder
public function __construct($userA = null, $userB = null)
{
$this->userA = $userA;
$this->userB = $userB;
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
// die(var_dump($options));
$users[] = $this->userA;
$users[] = $this->userB;
$builder
->add('slot', 'entity',
array(
'class' => 'NfidBusinessMeetingBundle:Slot',
'query_builder' => function(SlotRepository $cr) use ($users) {
return $cr->findAllFreeSlotByUsers($users);
}
)
);
}
Repository
public function findAllFreeSlotByUsers(array $users){
$subquery = $this->createQueryBuilder('query1');
$subquery->select('s')
->from('NfidBusinessMeetingBundle:Meeting', 'm')
->leftJoin('m.slot', 's')
->leftJoin('m.userA', 'uA')
->leftJoin('m.userB', 'uB')
->where('m.userA = :userA')
->orWhere('m.userA = :userB')
->orWhere('m.userB = :userA')
->orWhere('m.userB = :userB')
->andWhere('m.validated = 1');
$query = $this->createQueryBuilder('query');
$query->select('s2')
->from('NfidBusinessMeetingBundle:Slot', 's2')
->where($query->expr()->notIn('s2.id', $subquery->getDQL()))
->setParameters(array('userA' => $users[0]->getId(), 'userB' => $users[1]->getId()));
return $query;
}
Someone can help me ?
EDIT : If made this it works
public function buildForm(FormBuilderInterface $builder, array $options)
{
// die(var_dump($options));
$users[] = $this->userA;
$users[] = $this->userB;
$builder
->add('slot');
}
=========================== EDIT ====================================
I've try this
public function findAllFreeSlotByUsers(array $users){
$subquery = $this->createQueryBuilder('query1');
$subquery->select('s')
->from('NfidBusinessMeetingBundle:Meeting', 'm')
->leftJoin('m.slot', 's')
->leftJoin('m.userA', 'uA')
->leftJoin('m.userB', 'uB')
->where('m.userA = :userA')
->orWhere('m.userA = :userB')
->orWhere('m.userB = :userA')
->orWhere('m.userB = :userB')
->andWhere('m.validated = 1');
$query = $this->createQueryBuilder('query');
$query->select('s2')
->from('NfidBusinessMeetingBundle:Slot', 's2')
->where(
$query->expr()->orx(
$query->expr()->notIn('s2.id', $subquery->getDQL()),
$query->expr()->eq('s2.id', $users[2]->getId())
)
)
->setParameters(array('userA' => $users[0]->getId(), 'userB' => $users[1]->getId()));
return $query;
}
and
public function buildForm(FormBuilderInterface $builder, array $options)
{
// die(var_dump($options));
$users[] = $this->userA;
$users[] = $this->userB;
$users[] = $builder->getData();
if ($this->userConnected == User::TYPE_RESSOURCE ) {
$builder
->add('slot', 'entity',
array(
'class' => 'NfidBusinessMeetingBundle:Slot',
'query_builder' => function(SlotRepository $cr) use ($users) {
return $cr->findAllFreeSlotByUsers($users);
}
)
)
And it's always the same error
string 'slot:
ERROR: Cette valeur n'est pas valide.
UPDATED:
Insert this code and output the result:
editAction:
var_dump($entity->getSlot()->getId());
$editForm = $this->createForm(new UpdateMeetingType($entity->getUserA(),$entity->getUserB()), $entity);
buildForm:
'query_builder' => function(SlotRepository $cr) use ($users) {
$query = $cr->findAllFreeSlotByUsers($users);
$results = $query->getQuery()->getResult();
foreach ($results as $result) {
var_dump($result->getId());
}
die;
}
Try this:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$data = $builder->getData();
$users[] = $this->userA;
$users[] = $this->userB;
$builder
->add('slot', 'entity',
array(
'class' => 'NfidBusinessMeetingBundle:Slot',
'query_builder' => function(SlotRepository $cr) use ($users) {
return $cr->findAllFreeSlotByUsers($users, $data->getSlot());
}
)
);
}
SlotRepository: slot_id is the second parameters you pass from the entity type
$query = $this->createQueryBuilder('query');
$query->select('s2')
->from('NfidBusinessMeetingBundle:Slot', 's2')
->where(
$query->expr()->orx(
$query->expr()->notIn('s2.id', $subquery->getDQL()),
$query->expr()->eq('s2.id', $slot_id)
)
)
->setParameters(array('userA' => $users[0]->getId(), 'userB' => users[1]->getId()));
Of course, you may need to make some tests if the slot is null, etc.
What may be your issue:
Let's assume NEW meeting. This a the list of free slots:
Slot 1,
Slot 2,
Slot 3,
You select Slot 2. At edit, because it is used this is the list of free slots:
Slot 1,
Slot 3
Since Slot 2 is not on the list you get invalid choice.