How can I relation a foreign key with a form in symfony? - forms

Hi I'm trying to make a relation between two entities, a user creates proyectes, but in the create a project form I don't know how do it.
If I do this:
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder
->add('Nombre')
->add('Resumen')
->add('Creados')
;
}
I have the following error:
What can i do to make the form that make a relation and show the user how creates the proyect? It's my first time using stakoverflow, thank you!

you could use the EntityType for a to-one relationship like:
$builder->add('users', EntityType::class, [
'class' => User::class,
// uses the User.username property as the visible option string
'choice_label' => 'username',
]);
Have a look at the documentation, too. This will help you understand other form field types as well.
For a to-many relationship you can use Collection which is a bit more complicated.

Related

How to use different input types for one entity CollectionType - Symfony 3

in Symfony 3.2.4 and PHP 5.6.28
I'm making a Survey system in a dedicated Bundle.
I have 3 entities Question / Answer / Survey
SurveyType is based on 2 CollectionType : One contains questions, the other answers.
SurveyType :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add(
'question',
CollectionType::class,
array(
'entry_type' => QuestionType::class)
)
->add(
'answer',
CollectionType::class,
array(
'entry_type' => AnswerType::class,
)
);
Everything is working so far if I only need text or numbers as answer.
The problem is that I need different "Answer Input Type" : Checkbox, Range, Text ... for each question.
The "Answer Field Type" that I need is stored in DB table Question.
question.table
When generate my form in controller I can only have one input type.
$form = $this->createForm(SurveyType::class, $survey, array(
'question_type' => 'range'
));
For exemple all of my answers can only be Range or Text. I can't mix answer input type.
Only Range
Is there a way to say : "For question (1) I want my answer to be a string but question (2) I want a range" and they are all part of the same SurveyForm ?
You can build the form dynamically based on the answer type needed. See the docs page here. You'll have to add some logic in the event subscriber class to return an input of the correct type.

How to manage only one oneToMany entity in parent form

I have an Entity Criteria which can have several Entity Vote (associated).
I want to DISPLAY a list of criteria and to show only ONE Vote form in front of each Criteria (not zero, not many), to allow user to vote for each Criteria.
But, as I have a oneToMany association, in my CriteriaForm, I must have a CollectionType of Vote (I think ?). I tried to have only a VoteType :
$builder->add('votesCritere', VoteCritereType::class);
but I have an error :
The form's view data is expected to be an instance of class LabelBundle\Entity\VoteCritere, but is an instance of class Doctrine\ORM\PersistentCollection
So I think I must have a CollectionType. But, if I have a collection type, I start with ZERO form (because My Criteria does not contain any Vote yet).
I want to have only (and always) one Vote form in front of each criteria, to add a vote to the criteria (I don't want the number of forms reflects the number of votes)
How can I do that ?
Thanks for your help !
Let's think out loudly - in case you use entity bind form with collection type for votes, it'll allways show all of yours votes that would be bind to each criteria.
In this case I would recommend the array of forms based on criteria entity IDs.
Create Vote form type:
class VoteType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('answer', ChoiceType::class, array(
'choices' => array(
'Yes' => true,
'No' => false,
)
))
->add('note', TextareaType::class),
->add('criteriaId', HiddenType::class),
->add('vote', SubmitType::class);
...
...
}
In the controller - get traversable of criterias (e.g. method findAll() method of repository) and create array of named forms based on criteria entity IDs:
$ff = $this->get('form.factory');
foreach ($criterias as $criteria) {
$voteForms[] = $ff->createNamedBuilder(
'vote_'.$criteria->getId(),
new VoteType,
array(
'criteriaId' => $criteria->getId()
)
)
->getForm()
->createView();
}
return $this->render(someView, array("voteForms" => $forms));
And when the form is submitted then you can identify to which criteria the vote belongs by the hidden criteriaId field.
EDIT - Added: How to submit all forms with one button
'criteriaId' field and 'vote' submit in the VoteType is no longer needed - so:
class VoteType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('answer', ChoiceType::class, array(
'choices' => array(
'Yes' => true,
'No' => false,
)
))
->add('note', TextareaType::class);
...
...
}
And in the controller just create form with VoteTypes members:
$fb = $this->createFormBuilder();
foreach ($criterias as $criteria) {
$fb->add('vote-criteria-'.$criteria->getId(), VoteType::class);
}
$fb->add('submit', SubmitType::class);
$frm = $fb->getForm();
$frm->handleRequest($request);
if ($frm->isSubmitted() && $frm->isValid()) {
// all criteria vote data
$frm->getData();
...
}
return $this->render(someView, array('form' => $frm->createView()));

Creating a grid of forms in Symfony 2

I'm working on a page on which I would like to render an entity's instance as phpMyAdmin would do for instance.
More specifically, I would like to get a table in which columns are fields of the entity and rows are all the instances of this entity, and make all values (except id) editable, and save them to database.
My problem is I don't really know what is a good practice to do that and what is possible with Symfony (I'm quite new with this framework).
My first idea was to create a single form but it seems difficult to
combine several instances in a single form.
I also considered to create a form per row, but this means every line would have its own "submit" field, and it would be impossible to save changes in more than one row at once.
In Symfony's doc I've seen a topic about form collections but I don't know if this is something I can use, since the instances of my entity are completely independant.
Well, I think I'm not the first wanting to do that, but I was unable to find any way to do it, maybe am I missing something ?
Any advice is welcomed, thanks !
Doing "à là symfony" you could create a Base Form, for example AllRowsType that has a field of Type collection, and each one of the rows is of Type RowType:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('rows', 'collection', array(
'type' => new RowType(),
'allow_add' => false,
'allow_delete' => false,
'by_reference' => false
));
}
Then your RowType will be a normal form for your entity.
class RowType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name', 'text');
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\Bundle\DemoBundle\Entity\Row',
));
} }
The validations can be on your RowType like a normal form, but if you have problems, you can set cascade_validation => true on the default options of your AllRowsType.
To iterate each RowType in twig you can do:
{% for row in form.rows%} {{ form_row(row.name) }} {% endfor %}
On twig in order to get the ID of each row entity you can do:
{{ row.vars.value.id }}
On Controller, you can do $allrowsForm->get('rows')->getData() and you have an ArrayCollection of Row Entities and do whatever you want.
You can read http://symfony.com/doc/current/cookbook/form/form_collections.html for how to handle a collection of forms.

A set of fields for one property entity in Symfony 2

My Product entity has the following structure:
private $id;
private $title;
/**
* #ManyToOne(targetEntity="Category")
* #JoinColumn(name="cat_id", referencedColumnName="id")
*/
private $category;
Category have nested structure. And each level of nesting is shown in 5 separate fields:
In class form code, I solve it in this way:
$builder
->add('cat_1', 'entity', array(
...
'query_builder' => function() { return someSelectLogic1(); }
))
->add('cat_2', 'entity', array(
...
'query_builder' => function() { return someSelectLogic2(); }
))
->add('cat_3', 'entity', array(
...
'query_builder' => function() { return someSelectLogic3(); }
))
->add('cat_4', 'entity', array(
...
'query_builder' => function() { return someSelectLogic4(); }
))
->add('cat_5', 'entity', array(
...
'query_builder' => function() { return someSelectLogic5(); }
))
Now I need to know which field is filled in the last turn and pass the value of that field in the entity property.
In all that I do not like:
complex logic to determine which field with category was filled at the end
each of these fields is not tied to the entity 'mapped' => false
1) What the right way to organize code of my form?
2) And is there a way to bring these fields into a separate class which will deal with the logic of determining which category was chosen in the end?
I would suggest the following:
1) Create a new custom form field type and put all those entity in there.
This process is not much different from ordinary creation of form type. Just enclose those fields in it's own buildForm() and that should do the trick. Docs.
2) Mark all those entity fields with property "property_path => false".
Clearly you wont be storing these values inside your model.
3) Add two more fields: chosen and lastOne.
Now, this might be tricky: I would either set the chosen to text type (basically, generic type) or would use entity as well. If you go for entity you would need to include all possible answers from all entity fields. As for the lastOne set it to text as it will reflect which field (by name) was selected last.
Either way, those two fields will be invisible. Don't forget to set property_path to false for lastOne field.
4) Finally, add ValueTransformer (docs) which will contain logic to "see" which field was selected last.
Now, I dealt with it only once and don't understand it just quite yet, so your best bet would be trial and error with examples from official docs, unfortunately.
What basically you should do is to, within value-transformer, read the value of field lastOne. This will give you the name of field which was selected last. Then, using that value, read the actual last value selected. Last, set that value (object, if you've went for entity type, or it's ID otherwise) to chosen field.
That should basically do the thing.
As for the JS, I don't know if you're using any framework but I will assume jQuery. You will need to set lastOne field as your selecting items in your form.
$(function(){
$('#myform').find('select').on('change', function(){
var $this = $(this);
$this.closest('form').find('#__ID_OF_YOUR_LASTONE_FIELD').val($this.attr('name'));
});
});
I'm sorry I cannot provide you with code samples for PHP right now. It's a bit late here and will do my best to further update this answer tomorrow.

Symfony2 forms - filtering parent objects when adding a child object in OneToMany relation

I have two entities - Category and Article with OneToMany relation.
When I render the form for adding/editing Article object, I see all categories in an html select, but I want to see only a part of the categories (in future I would also like to add categories dinamically, according to different conditions).
How to override the query, made automatically by Doctrine, which retrieves the categories, in order to filter them?
Thanks in advance,
Nikolay
Passing query_builder parameter in your category field at your ArticleType, you can customize the query for retrieve category elements.
$form = $this->createFormBuilder()
->add('category', 'entity', array(
'class' => 'ArticleBundle:Category',
'query_builder' => function(EntityRepository $er) {
return $er->createQueryBuilder('c')
->orderBy('c.name', 'ASC');
//add more query elements here
},)
)
->getForm();
View more details here
You can do this by setting the query_builder option to a closure that accepts the repository a an argument and returns a query builder.