Symfony3: Proper way of persisting multiple objects from the same form - php

I have a Field class and a FieldType class associated to it and I want to create a interface where the user can edit the FieldType of all the Fields at once.
So I did the following:
protected function createUpdateForm() {
$fieldList = $this->getDoctrine()->getRepository('AppBundle:Field')->findAll();
$fieldTypeList = $this->getDoctrine()->getRepository('AppBundle:FieldType')->findAll();
$form = $this->createFormBuilder();
foreach ($fieldList as $field){
$form->add($field->getDescription(), ChoiceType::class,
['choices' => $fieldTypeList,
'choice_label' => 'getDescription',
'multiple'=>false, 'expanded'=>true,
'data' => $field->getFieldType()]);
}
$form->add('action', SubmitType::class, ['label' => 'Update']);
$form->add('cancel', SubmitType::class, ['label' => 'Cancel']);
return $form->getForm();
}
It takes all the Fields from the database and creates a Radio group with the FieldTypes as the image shows (just the end of the form):
So for each Field the user can select the type and update the values.
This is how I am updating the form, and that is what I do not like:
foreach ($form->getData() as $fieldType){
$field = array_shift($fieldList);
$field->setFieldType($fieldType);
$em = $this->getDoctrine()->getManager();
$em->flush();
}
It works, but everything look like a bodge, I do not like this. I'm starting with Symfony so I'm not sure, but there should be a better way to create the kind of form I need and persist it. I was trying to create a ColletionType, but it is not working out.
Does anybody know a better way to do this?
I have a more complex case that will use a similar logic so I'm trying to figure this out.

Not sure if I understood you completely, but if I did, this calls for an CollectionType as far as I can see it. Plus, if you set the underlying type to be EntityType you simplify the things even more.
I think something like this should work:
$fieldList = $this->getDoctrine()->getRepository('AppBundle:Field')->findAll();
$form = $this->createFormBuilder(['fields' => $fieldList])
->add('fields', CollectionType::class, [
'entry_type' => EntityType::class,
'entry_options' => [
'class' => 'AppBundle:FieldType',
'expanded' => true,
'choice_label' => 'description'
]
])
->add('action', SubmitType::class, ['label' => 'Update'])
->add('cancel', SubmitType::class, ['label' => 'Cancel'])
->getForm();
Update:
{{ form_label(form.fields) }}
{% for f in form.fields %}
{{ form_row(f, {'label': f.vars.value.description}) }}
{% endfor %}
Just bare in mind that I currently don't have dev env which I could use to check for typos, but it should work :)
Hope this helps a bit...

Related

How to get form data with session in Symfony Form

I've been looking for a solution for hours. I'am working with Symfony 3.2.
I'am using Symfony Forms in order to display a data-table (with different filter chosen in the form) with Ajax => No submit button.
I can access to different result of data-table to view more information.
What i want is that when i leave the detail page by clicking on a button and come back on the research page, that i could keep in history all filters that i have chosen.
i wanted use session but actually, it seems has 0 impact. Below is some codes.
Controller:
public function indexAction(Request $request)
{
$form = $this->createSearchForm();
$request->getSession()->set('form_data', $form->getData());
$form->handleRequest($request);
$form->setData($request->getSession()->get('form_data'));
$this->datatable($form->getData());
return $this->render('backend/jobOffer/index.html.twig', [
'form' => $form->createView()
]);
}
FormType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('publicationState', ChoiceType::class, [
'label' => 'backend.job_offer.publication_state',
'required' => false,
'choices' => JobOffer::getPublicationStateChoices(),
'choice_translation_domain' => 'choices',
])
->add('job', Select2EntityType::class, [
'label' => 'backend.job',
'required' => false,
'class' => 'AppBundle:Job',
'text_property' => 'label',
'remote_route' => 'job_autocomplete',
])
->add('ids', HiddenType::class, [
'required' => false,
])
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'csrf_protection' => false,
'method' => 'GET',
]);
}
I have a problem, there is a EntityType (or Select2EntityType) field named "job" in my form builder and i can't get the content of this field in my session. This field shows a autocomplete data-list after typing 2 letters, and we can choose one of job.
and also, when i refresh the page, i lose all filters, but i am supposed to store them in session ?
Thanks in advance for your help,
Yes you can use $form->getData() but to do that you need to do this according to the doc here with using if ($form->isSubmitted() && $form->isValid()) { among others.

How to solve Symfony error Variable "expanded" does not exist?

Currently, I develop an app with PHP Symfony Framework. I've got a problem with Form Builder (I think).
I have two entities. Question and Choice.
Question and Choice are OneToMany Relationship Entity. One Question has many Choice.
Another two entities, Video and Category, the relationship is just the same with Question and Choice.
I create scaffolding crud for those entity with php bin/console make:crud.
Then I add the relationship symfony like in this guide from Symfony.
The logic is, I must select the Category first to create new Video. Same with the Choice, I must select the Question first to create new Choice data.
My problem appear when I open the Choice Create Form [/choice/new]. It says
Variable "expanded" does not exist.
Then the error details show on this lines
return $this->render('choice/new.html.twig', [
'choice' => $choice,
'form' => $form->createView(), // The highlighted error appear on this line
]);
But, It just happen in the Question-Choice, My Category-Video relationship is just fine. I tried to make Question-Choice as same as Category-Video (I changed the name of the entity for sure), I triple check it, but the error on Choice Create Form still occur.
This is my App\Form\ChoiceType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('content')
->add('letter')
->add('image')
->add('question', EntityType::class, [
'class' => Question::class,
'choice_label' => 'content'
])
;
}
Notice the add('question')
and this is my App\Form\VideoType buildForm method
<?php
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title')
->add('url', FileType::class, [
'label' => 'Video File',
'required' => false,
])
->add('thumbnail', FileType::class, [
'required' => false,
])
->add('description')
->add('category', EntityType::class, [
'class' => Category::class,
'choice_label' => 'name'
])
;
}
Notice the add('category')
So, anyone know what is happening?
I renamed App\Form\ChoiceType to App\Form\TheChoiceType, make some adjusment for class name changing on the controller. Everything is work!
I don't believe this! The solution is to rename the form type.

Symfony CollectionType field with one default field

I need your advice with CollectionType field.
I've made my collection type field using this: Symfony CollectionType Field
Everything works fine. Even dynamic adding field with JQuery works properly.
But there is an issue.
I can't find out how to add one field each time the collection field renders. Right now after my page loads, my collection field is empty. However, I want the first field from the collection after every page load.
How to achieve this? Should I use Javascript or kind of form event? Any tips for finding a right chapter in documentation or code snippets will be very welcome.
This way worked for me.
// 3 default values for empty form
$configArr = [[], [], []];
if ($builder->getData()) {
$configArr = $builder->getData()->getColumns();
}
$builder->add('columns', CollectionType::class, [
'entry_type' => ColumnType::class,
'prototype' => true,
'allow_add' => true,
'allow_delete' => true,
'data' => $configArr,
'mapped' => false,
]);
I think I remember hitting this and I ended up creating data with an empty child on first load.
I'm unable to test this however I think the following should work depending on your form specifics.
public function someAction()
{
$data = [];
$data['collection_name'][] = ['text' => ''];
$form = $this->createForm(SomeType::class, $data);
return $this->templating->renderResponse('template.twig.html', [
'form' => $form,
]);
}
Adding 'required' => false, to the collection's form config should prevent empty items being persisted.
You may also investigate the configureOptions method on the form Type class:
public function configureOptions(OptionsResolver $resolver)
{
$data = [];
$data['collection_name'][] = ['text' => ''];
$resolver->setDefaults(array(
'empty_data' => $data,
));
}
This simply worked for me.
public function buildForm(FormBuilderInterface $builder, array $options) {
$data = $builder->getData(); // data passed to the form
$builder->add('textFields', CollectionType::class, [
'entry_type' => TextType::class,
'data' => $data ? $data->getTextFields() : ['']
]);
}

put data form database into checkbox symfony 3

I started learn symfony 3. For the first project i chose a simple totodlist.
So now i have possibility to create and save the user in my database. Next I can create a task for them.
I want to create a checkbox where can i choose a users to perform a task.
So i need put data from my user database to checkbox form ($temp_users varbiable). I don't know how to do it.
Can anybody show me how to do it.
below is my code:
public function createAction(Request $request)
{
$todo = new Todo;
$users = $this->getDoctrine()
->getRepository('AppBundle:User')
->findAll();
$temp_users = array();
foreach($users as $user) {
$temp_users[$user->getUsername()] = $user->getId();
}
$form = $this->createFormBuilder($todo)
->add('name', TextType::class, array('attr' => array('class' => 'form- control', 'style' => 'margin-bottom:15px')))
->add('wykona', CheckboxType::class, array('label' => $temp_users, 'required' => false,))
I'm not sure what you mean by checkbox - are you wanting to select one, or many users? I'm going to assume you want to select just one for simplicity's sake (you can adapt this to your liking)
You don't need to get all the users like you're trying to do, something like this should work (untested)
$form = $this->createFormBuilder($todo)
->add('user', EntityType::class, array(
'label' => 'Name',
'class' => AppBundle\Entity\User::class,
'choice_label' => 'name', //if you have a variable 'name' in your User entity, otherwise you will need a __toString method in the User entity
));
Try this code inside your createAction.
ADD this into your code
$form = $this->createFormBuilder($todo)
->add('users', EntityType::class, array(
'class' => 'AppBundle:User',
'query_builder' => function (EntityRepository $er) {
return $er->createQueryBuilder('u')
->orderBy('u.name', 'ASC')
},
'choice_label' => 'name',
'multiple' => true,
'expanded' => true,
));
Also you don't need the following code anymore inside createAction.
REMOVE Below code from your code
$users = $this->getDoctrine()
->getRepository('AppBundle:User')
->findAll();
$temp_users = array();
foreach($users as $user) {
$temp_users[$user->getUsername()] = $user->getId();

Symfony submitted form data is NULL

In Symfony I am building a form with four possible choices as radio buttons. When the user submits the form with a choice, I am taking the submitted form data (the user choice) and display it in twig. The problem is that sometimes the submitted form data is null even if the user selected a radio, and sometimes the selected choice is passed and displayed in twig. Also sometimes after reciving null in twig and refreshing the page the data is shown, but this doesn't always happen. Why this inconsistency? How can I solve this? Thanks
public function playAction(Request $request){
$data = $this->getDbQuestion();
$questionData = $data[0];
$questionID = $questionData->getId();
dump($questionData);
$answerData = $data[1];
dump($answerData);
$form = $this->createFormBuilder($answerData)
->add('answers', EntityType::class, array(
'class' => 'QuizBundle:Answer',
'query_builder' => function (EntityRepository $er) use ($questionID) {
return $er->createQueryBuilder('a')
->where('a.question = :qID')
->setParameter('qID', $questionID);
},
'multiple'=>false,
'expanded'=>true,
'error_bubbling' => true,
'choice_label' => 'answer',
))
->add('Submit',SubmitType::class, array('label' => 'Send Answer'))
->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$formData = $form->get('answers')->getData();
$errors = $form->getErrors();
return $this->render('QuizViews/correctAnswer.html.twig', array('ss' => $formData, 'errors' => $errors ));
}
return $this->render('QuizViews/playQuiz.html.twig', array('form' => $form->createView(),'question' => $questionData));
}
Dumping the submitted form data in twig
<a href="/quiz/question">
<input type="button" value="Start Quiz" />
</a>
<br>
FormData Correct {{ dump(ss) }}
Form Errors {{ dump(errors) }}
Adding $form->isValid()I get this in twig when the answer is not submitted.
Glad you got further.
I believe that the "$formData" is coming back as an answer object, and all you have to do in twig is call something like:
{{ ss.getAnswer }}
Where getAnswer is a method for the Entity Answer (I don't remember your code). The form data correct you show above looks exactly like a dump of an "object". Remember you need to think in terms of objects.
Let me know if that doesn't work.
Edit #2.
Try this change:
->add('answers', EntityType::class, array(
'class' => 'QuizBundle:Answer',
'query_builder' => function (EntityRepository $er) use ($questionID) {
return $er->createQueryBuilder('a')
->where('a.question = :qID')
->setParameter('qID', $questionID);
},
'multiple'=>false,
'expanded'=>true,
'choice_value' => 'answer',
'choice_label' => 'answer',
))
Where I've added 'choice_value' => 'answer', in this case 'answer' should be the answer value stored in the Answer Entity.
Edit #3.
This is weird. I'm not sure why it's not working.
You shouldn't need to pass in the $answerData into the builder. Try leaving it blank, and let's change it to a drop-down list (default):
$form = $this->createFormBuilder()
->add('answers', EntityType::class, array(
'class' => 'QuizBundle:Answer',
'label' => 'Select an Answer',
'choice_value' => 'answer',
'choice_label' => 'answer',
))
If that doesn't work, something else is definitely wrong, possibly your Entities. This returns the Entity value in the db for me.
Did you tryed to check if your form was valid?
if($form->isSubmitted() && $form->isValid()) {
Also, set and display form errors may help a lot, to check what is wrong, and which part of your form isn't correct.

Categories