Symfony2 - Form validation with query builder - value never valid - forms

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.

Related

Symfony 2.8 - Set default value with data from session and propel

I use Propel in a project & I try to set default value my form which uses a ModelType input and I need to set a default value stored in session in this form and where this session is not null for the stored value used in this functionnality.
This is my form :
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Fcl\VitrinellisBundle\Model\ProfileVariety',
'name' => 'profile_variety_search',
'locales' => ['fr'],
'session' => null
));
}
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', ModelType::class, array(
'class' => 'Fcl\VitrinellisBundle\Model\ProfileVariety',
'query' => ProfileVarietyQuery::create()->orderById(),
'property' => 'name',
'label' => 'Profil recherché',
'expanded' => false,
'multiple' => false,
'required' => false,
'placeholder' => '- Filtrer par profil -',
'attr' => array(
'onchange' => 'submit()',
'class' => 'col s3'
)
))
;
}
This is my treatment :
public function listAction(Request $request = null)
{
$pModelManager = $this->get('fcl_vitrinellis.p_model_manager');
$profileVarietyManager = $this->get('fcl_vitrinellis.profile_variety_manager');
$session = $request->getSession();
$profileVariety = new ProfileVariety();
$models = null;
$form = $this->createForm(ProfileVarietySearchType::class, $profileVariety);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (null != $form['name']->getData()) {
$models = $pModelManager->getWebsiteByModel($form['name']->getData()->getName());
$session->set('profileVarietySearch', $form['name']->getData()->getName());
} else {
$models = $pModelManager->getList();
}
} else {
if ($session->has('profileVarietySearch') && null != $session->get('profileVarietySearch')) {
$models = $pModelManager->getWebsiteByModel($session->get('profileVarietySearch'));
} else {
$models = $pModelManager->getList();
}
}
return $this->render('console\p_model_list.html.twig', array(
'objArray' => $models,
'form' => $form->createView()
));
}
I have try to set default data with 'data' option and with PRE_SET_DATA event in the form but I had satisfactory result.
In an EntityType the incoming default 'data' must be an object of the right type. I would first try to see if we have incoming form data.
public function buildForm(FormBuilderInterface $builder, array $options)
{
// Check form data
$formDataEntity = $builder->getData();
// Check if it has the field filled in
if ($formDataEntity && $formDataEntity->getName()) {
$objToSet = $formDataEntity->getName();
} else {
$objToSet = $options['incomingDefaultObject'];
)
$builder
->add('name', ModelType::class, array(
class => 'Fcl\VitrinellisBundle\Model\ProfileVariety',
data => $objToSet,
...
And then for the resolver
/**
* #param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'incomingDefaultObject' => null,
));
}
And you call the form with the default opion in the controller
$form = $this->createForm(YourType::class, $yourObject, array('incomingDefaultObject' => $nameObject));
Warning: if a user decides to leave the field empty this code will always set the default.
I have an other solution.
Create new Model which his name is ProfileVarietySearch, like this :
class ProfileVarietySearch
{
/** #var null|ProfileVariety $profileVariety */
private $profileVariety;
/**
* #return bool
*/
public function is_empty()
{
return is_null($this->profileVariety);
}
/**
* #return null|ProfileVariety
*/
public function getProfileVariety()
{
return $this->profileVariety;
}
/**
* #param $profileVariety
*
* #return ProfileVarietySearch
*/
public function setProfileVariety($profileVariety): self
{
$this->profileVariety = $profileVariety;
return $this;
}
}
In the controller, write this :
public function listAction(Request $request = null)
{
$pModelManager = $this->get('fcl_vitrinellis.p_model_manager');
$profileVarietyManager = $this->get('fcl_vitrinellis.profile_variety_manager');
$session = $request->getSession();
$profileVarietySearch = new ProfileVarietySearch();
$models = null;
if ($session->has('profileVarietySearch') && null != $session->get('profileVarietySearch')) {
$profileVarietySearch->setProfileVariety(
$profileVarietyManager->getByName($session->get('profileVarietySearch'))->getData()[0]
);
}
$form = $this->createForm(ProfileVarietySearchType::class, $profileVarietySearch);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
if (null != $form->getData()->getProfileVariety()) {
$models = $pModelManager->getWebsiteByModel($form->getData()->getProfileVariety()->getName());
$session->set('profileVarietySearch', $form->getData()->getProfileVariety()->getName());
} else {
$session->set('profileVarietySearch', null);
$models = $pModelManager->getList();
}
} else {
if ($session->has('profileVarietySearch') && null != $session->get('profileVarietySearch')) {
$models = $pModelManager->getWebsiteByModel($session->get('profileVarietySearch'));
} else {
$models = $pModelManager->getList();
}
}
return $this->render($this->view_list, array(
'objArray' => $models,
'form' => $form->createView()
));
}
In the ProfileVarietySearchType, write this :
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Fcl\VitrinellisBundle\Form\Model\ProfileVarietySearch',
'name' => 'profile_variety_search'
));
}
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('profileVariety', ModelType::class, array(
'class' => 'Fcl\VitrinellisBundle\Model\ProfileVariety',
'query' => ProfileVarietyQuery::create()->orderById(),
'property' => 'name',
'label' => 'Profil recherché',
'expanded' => false,
'multiple' => false,
'required' => false,
'placeholder' => '- Filtrer par profil -',
'attr' => array(
'onchange' => 'submit()',
'class' => 'col s3'
)
));
}

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 ?

ManyToMany, duplicate entry, table empty

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

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