In symfony 2.0, how to create a drop down list using one-to-one association in form? Can you guys put good example please?
I will try to answer your question the way I understand it. Let's say I have a Faculty object bound to a single University object. So in the form used to create or edit a faculty, I display a combo box of all the university in the database and the user choose one among them. There is one special Symfony field type that does exactly this: the entity type. Below is the code of the buildForm method that I use in my FacultyType object used to create the faculty form:
// Application\AcmeBundle\Form\Type\FacultyType
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('name');
$builder->add('university', 'entity', array(
// The class of the entity used as a combo box item
'class' => 'AcmeBundle:University',
// The property of the entity displaying the entity as text
'property' => 'name',
// The query builder used to populate the combo box, accepts
// a QueryBuilder object or a \Closure like below
'query_builder' => function(EntityRepository $repository) {
// This will return a query builder selecting all universities
return $repository->createQueryBuilder('u');
}
));
}
Note: There are other properties that can be set for the entity field type, I invite you to take a look at this page for more information on it.
Rendered, this will show a combo box with all the universities I have set in the database. When the user save the form, the university chose is assigned to the faculty object bound to the form via a setter. You could probably render a drop-down list instead of a combo box. If you need to select multiple entities, the 'multiple' option of the field type entity could be useful.
This being said, the example I showed is not a One-to-One relation but rather a Many-to-One for the Faculty object and a One-to-Many for the University object. A One-to-One relation would be something more like a relation where a University has a unique Address. In this case, a combo box wouldn't be useful since the university can only have one adress so a sub-form would be more appropriate. If it has many adresses, then it becomes a One-to-Many relation like the relation between the university and its faculties.
Not sure if this will answer your question correctly but I hope it will lead you to a final solution.
Regards,
Matt
You need to use the entity field type in Symfony2. A good example is found at http://symfony.com/doc/current/reference/forms/types/entity.html
Related
I am beginner in PHP and Symfony and I started recently on a project.
We have 2 entities which are related by doctrine Annotation ManyToMany with JoinTable
Example: entity and datatable Room, entity and datatable Person and datatable RoomPerson (entity does not exist and just exist in doctrine annotation JoinTable).
The entity Room has a property Collection of Persons.
With a formType it is rendered in page as a select html element multiple (so we can choose several persons)
FormType with preEvent to fill list of possible persons:
$allowedPersons = $this->em->getRepository(Person::class)->findBy(***);
$form
->add('personList', EntityType::class, [
'class' => Person::class,
'choices' => $allowedPersons ,
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Room::class,
New request is to order the list of Persons.
So I made changes described in some tutorials to change declare the Entity RoomPerson et remove annotations ManyToMany for ManyToOne and OneToMany. I added the property "Order" on RoomPerson.
I Added the methods AddRoomPerson and RemoveRoomPerson to make updates of the list by the mapping of my FormType.
So my entity "Room" now only contains a property Collection of RoomPerson.
But I don't know how to use it in my FormType because I always want to show the list of Persons.
I tried a lot of things without success.
example:
$allowedPersons = $this->em->getRepository(Person::class)->findBy(***);
$form
->add('roomPersonList', EntityType::class, [
'class' => RoomPerson::class,
'choices' => $allowedPersons ,
'choice_value' => function(?RoomPerson $roomPerson) {
return $roomPerson? $roomPerson->getPerson()->getIdPerson() : '';
},
'choice_label' => function(?RoomPerson $roomPerson) {
return $roomPerson? $roomPerson->getPerson()->getName() : '';
},
I get following error:
Argument 1 passed to App\Form\RoomPersonType::App\Form{closure}() must be an instance of App\Entity\RoomPerson or null, instance of App\Entity\Person given, called in ..\vendor\symfony\form\ChoiceList\ArrayChoiceList.php on line 200"
So please I need help to transform my list of RoomPerson in my formtype and to make an update of this list in page.
When you are creating a form, the ->adds will make a reference to different columns you have defined in your App\Entity.
So, if you want to add something to your form this way, it has to be represented, again, in App\Entity.
Now, what you want to do, AFAIU, is fill a Room with people (class Person), and keep a list of those in the room (RoomPerson), and also a list of where every person has been (that's why it is a ManyToMany).
If instead you are looking at only where a Person has been the last time or at the moment, then it is a OneToMany relation, cause a room would be able to hold a bunch of people but any person would only be able to be at one place at a time (obviously).
Now I will simply take for granted you want to achieve the ManyToMany case. You should have all the columns needed in both Room and Person.
Now, RoomPerson should simply have a connection of those two and it's own id. You can add more things but for the purpose of this example let's just suppose we just need it to be a simple relating table so... your tables would look like (as an example):
<-M:N->
Room: <-M-> RoomPerson <-N-> Person:
- id (pk) - id (pk) - id (pk)
- space - room_id (fk) - gender
- style - person_id (fk) - room_usage
- purpose - age
- etc etc... - etc etc...
M being M number of posible objects on one side, N being N number of posible objects on the other side.
Once you have a DB like this, you can simply create a Form where you pass a Room, with every row you need in it.
If what you want is to select a room and have all the people displayed, you can, on the controller-side, get via queries a list of all the people that have been in each room, send it to the form, and then, on your template-side, play with html and js to dinamically show the correct list in each room.
I would need a more precise description to know exactly what you are trying to accomplish.
Here are my tables:
Movie
id
name
year
description
Person
id
name
date_of_birth
Role
id
name
movie_id
person_id
So, Movie should contain, obviously, movies. Person consists of people (actors, directors or writers). Table Role connects with other 2 tables by having $movie and $person variable inside its class, with Many-to-One relationship for both of them, which in the end results in movie_id & person_id.
What I want to achieve is having a form, where I will be able to insert new movie, but also its relevant actors, director(s) & writer(s).
Final form result should contain these fields:
movie_name, movie_year, movie_description
dropdown with list of persons from DB (person.name)
dropdown with 3 possibilities - actor, director, writer (which would eventually be inserted to DB)
So, after filling out the first three inputs, user chooses a person from a dropdown list, and then, chooses appropriate role for chosen person. If I'm thinking right, I should be able to SELECT from Person (name) table , and to INSERT into Movie (name, year, descr.) & Role (name, movie_id, person_id) tables.
I'm aware that I should be using Form collections, but I don't understand how to use them, at least in this situation. I guess I should start by creating something like RoleModel class, but not sure whether I made a mistake before going into this, which makes this problem more complex than it should be.
My questions really is - how to make this work with Form collections?
I can provide any necessary code, if needed.
Symfony make it really easy, so first, you need to add bidirectional relation (One-to-many) between your person entity and your movie entity so you need to:
Add property called person to your movie entity:
Code:
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Person", inversedBy="movies")
*/
protected $person;
Add property called movies to your person entity:
Code:
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\Movie", mappedBy="person")
*/
protected $movies;
Now in your MovieType file (form configuration file) you can do it by:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('name')
->add('year')
->add('description', TextareaType::class)
->add('person', EntityType::class, array(
'class' => Person::class, //This existed usually in (AppBundle\Entity\Person)
'choice_label' => 'name'
));
}
This is a simple demonstration on how to use EntityType in Symfony.
Good luck.
You can solve this by embedding FormTypes, you can create a new one which is a composition of a PersonFormType and MovieFormType, and it would need an extra field for the role type (director, actor, etc)
Then, after submit, you can retrieve your objects something like this:
// SomeController's action
...
$data = $form->getData();
$person = $data['person'] // or whatever is the name of the field
You can find more information about embedding FormTypes in the docs: https://symfony.com/doc/cur...
I am working on a Symfony 2 based web app and struggling to create a many to many relationship between to entities:
Each Task entity should be assigned to any number of Categories. Of course each Category can be used by any number of Task entities. While a Task needs to know its Categories the Category class has no relationship back to the Tasks.
Following this tutorial I created:
class Task {
/**
* #ORM\Column(name="categories")
* #ORM\ManyToMany(targetEntity="MyBundle\Entity\Category")
*/
protected $categories;
public function __construct() {
$this->productVariations = new \Doctrine\Common\Collections\ArrayCollection();
...
}
}
Which results in the following SQL table:
CREATE TABLE task ... categories VARCHAR(255) NOT NULL, ...
A new Task is created use a form with the following type:
class TaskType extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->add('categories', EntityType::class, array(
'class' => 'MyBundle:Category',
'choice_label' => 'name',
'multiple' => true,
'expanded' => true,
))
...
}
}
Submitting the form and persiting the new Taskinstance result in a SQL row with the following content in the categoriescolumn:
Doctrine\Common\Collections\ArrayCollection#000000007448a17a0000000048941f2f
What does this mean? Storing the referenced Category entities as array is not normal form but of course valid (in fact I would prefer this solution over adding a relationship table since in practice the number of categories per task will be quite small, thus a third table would be more overhead).
However I would assume that the array stores the IDs of the referenced objects/rows in some form. How would it be possible to store any number of references in a VARCHAR(255) column?
While submitting and persisting creates a DB entry, the Category references are not stored correctly. When I try to re-read this entry, the categories property is empty.
You have redundant column definition. Try to simply remove following line:
* #ORM\Column(name="categories")
Then you need to update you database schema.
This line creates a varchar field in task table which shouldn't be there. Many to many relations are implemented via separate table.
If you want to store ids in a single field instead of separate table, then you will handle it on your own. That's because it won't be able to be a relation anymore. You loose possibility to create foreign key or doing any join queries. Also filtering records will be harder to achieve.
I think you're missing something here.
Like you said, a Task can be associated to many Category(ies) AND the Category class DOES NOT need a relational mapping to the Task class.
All you need in your Task class is a property to reference your Categories.
I think what you're looking for is this.
I have a problem with hydrating the objects in ZF2.
I have a form for saving either the organization-related info or person-related info into the database. The user makes the choice: save either organization or person. Just 1 form for all html inputs.
In ZF2, I created 2 fieldsets. In each fieldset class, I use setHydrator(new ClassMethods(false)) and setObject(new <objectForHydration>). The 2 fieldsets are included into the form with the following code:
$this->add([
'type' => 'Parties\Form\Fieldsets\RegisterOrganizationFieldset',
'options' => [
'use_as_base_fieldset' => true,
],
]);
$this->add([
'type' => 'Parties\Form\Fieldsets\RegisterPersonFieldset',
'options' => [
'use_as_base_fieldset' => true,
],
]);
I want RegisterOrganizationFieldset to hydrate OrganizationObject, and RegisterPersonFieldset to hydrate PersonObject.
I thought of hydrating both objects at the same time because this won't introduce conditionals into the form class. The problem is the hydration takes place just 1 object depending on which fieldset has use_as_base_fieldset = true. If both fieldsets have use_as_base_fieldset = true, the fieldset later in the code (RegisterPersonFieldset) hydrates only its respective object.
Could you tell how to hydrate both objects? Maybe how to hydrate objects in a better way?
EDIT:
As #jcropp pointed, I use Person and Organization as Parties that are independent entities sharing only Id property.
One way to hydrate two objects at the same time is to make them both the same object.
It is not clear from your question whether 1) a person who is registering is a member of a registering organization, or 2) "parties" are registering, and a party can be either an organization or a person. Here are some answers for both cases:
If persons are members of organizations in your data structure, a method for hydrating both at the same time is to treat the persons data as "collections" of the organization data elements. This method utilizes relationships between the fieldsets to create a single dataset in which both the organization data and the person data can be edited together. See the ZF2 Manual.
If your intent is to register individual parties, and a party can be either an organization or a person, a method for hydrating one or the other in the same form is to use table inheritance. In single table inheritance you would have a single table (and a single fieldset) for both types of parties, and a selection between the person or organization type would indicate whether data should be entered into the organization fields or the person fields of the table. In multiple table inheritance, you would create a party table that related to an organization table and to a person table; and organization and person fieldsets would extend the party fieldset.
I am new to symfony (2.1) and I have simple problem, I want to change the way that "entity Field Type" generates choice list in select tag in form.
In my categoryType.php, in buildForm method I have something like this:
$builder
->add('parent', 'entity', array(
'class' => 'TestAdvBundle:Category',
'property' => 'name',
'label' => 'label.parent',
))
;
This works fine, all Category entities which are persisted in db are present in select tag in generated form. But what I want to do is to slightly change this generated choice list. Actually, I want one "fake" choice in list which represents "root category" and I do not want object that I edit to be listed here (this field is a parent id, and it points to same object type as the edited object is, etc. this field is parent category of category that I edit, so practically I don't want to be able to select self as a parent category).
I guess that this "entity Field Type" uses findAll() repository method to fetch its results. So I made specific findAllForList() method where I return wanted array. But I can not find a way to tell "entity Field Type" to use my repository method instead of findAll().
You can use the Querybuilder option and the empty_field Method provided with the entity field type.
http://symfony.com/doc/master/reference/forms/types/entity.html#query-builder
The querybuilder is explained in the linked URL under "Using a Custom Query for the Entities"