I am using Symfony3.4 and have the following relationship in the database between House and Type entities:
house
+----------------------------------------------+
| id | title | description |
+----------------------------------------------+
| 1 | some title 1 | some description 1 |
+----------------------------------------------+
| 2 | some title 2 | some description 2 |
+----------------------------------------------+
type
+----------------+
| id | name |
+----------------+
| 1 | shortstay |
+----------------+
| 2 | rent |
+----------------+
| 4 | sell |
+----------------+
house_types
+-----------------------------------+
| id | house_id | type_id | price |
+-----------------------------------+
| 1 | 1 | 2 | 1000 |
+-----------------------------------+
| 2 | 1 | 3 | 1000000 |
+-----------------------------------+
| 3 | 2 | 1 | 100 |
+-----------------------------------+
| 4 | 2 | 3 | 200000 |
+-----------------------------------+
Here are my entities:
House entity
class House extends EntityBase
{
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\HouseHasTypes", mappedBy="houses", cascade={"persist","remove"})
*/
protected $hasTypes;
Type entity
class Type extends EntityBase
{
/**
* #ORM\OneToMany(targetEntity="AppBundle\Entity\HouseHasTypes", mappedBy="types", cascade={"persist","remove"})
*/
protected $hasHouses;
HouseHasTypes entity
class HouseHasTypes extends EntityBase
{
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\House", cascade={"persist"}, fetch="EAGER")
* #ORM\JoinColumn(name="house_id", referencedColumnName="id", nullable=true)
*/
protected $houses;
/**
* #ORM\ManyToOne(targetEntity="AppBundle\Entity\Type", cascade={"persist","remove"}, fetch="EAGER" )
* #ORM\JoinColumn(name="type_id", referencedColumnName="id",nullable=true)
*/
protected $types;
/**
* #var int
*
* #ORM\Column(name="price", type="integer")
*/
protected $price;
I did not quite get the difference between ManyToOne and OneToOne relationship. Which one should mine be?
Also, what would be the easiest way to handle inserting new data into the 2 entities (House and HouseHasTypes). Right now I can render the checkboxes for each row in type table as follows:
$builder
...
->add('hasTypes', EntityType::class, array(
'required' => true,
'class' => Type::class,
'expanded' => true,
'multiple' => true,
))
And the in the controller I am planning to make a foreach(){} for each of the checked Types and setHouse() and setPrice() there. Is there any other more efficient way to do this?
How can I render as many textboxes as there are the abovementioned EntityType checkboxes to define a price for each Type selected? I am currently hardcoding three html input text elements and hiding them with javascript based on checked checkboxes. If I make a custom form, how can I tell it to render 3 text inputs (since there're 3 rows in the entity table)
Sorry for asking so many questions. Any help would be much appreciated
Your database model seems correct.
To define you the OneToMany, ManyToOne and OneToOne relationship, I made you little examples:
Imagine we have two entities: USER and ORDER.
OneToMany:
An user can do 0, 1 or many orders right ? It means that One user can be linked To 0, 1 or Many orders.
USER(id:1) --> ORDER(id:1)
--> ORDER(id:3)
--> ORDER(id:8)
ManyToOne:
An order can be done by one and only one user right ? It means that Many orders can be linked To One user.
ORDER(id:1) --> USER(id:1)
ORDER(id:3) --> USER(id:1)
ORDER(id:8) --> USER(id:1)
OneToOne:
Now imagine we have two others entities: USER and EMAIL.
An user can have one and only one email address and an email address can have one an only one user right ? It means that One user can be linked To One email address and One email address can be linked To One user.
USER(id:1) --> EMAIL(id:6)
USER(id:3) --> EMAIL(id:7)
USER(id:8) --> EMAIL(id:1)
Hope I was clear.
For your others questions, Symfony will automatically insert data on form submit if you have correctly defined your getter and setter in entities no needs to do a foreach
Related
I have an entity called Item which has a ManyToMany connection with a JoinTable to an entity called Tags
This is working well. The problem is, that I need the tags in the exact order as they are chosen, not sorted by tag id, as I get them now when I call getTags() on the Item class. Is there a way to do that?
Use the join table to define that order.
Item_id | Tags_id | Order
--------+---------+------
1 | 1 | 2
1 | 2 | 1 <-- order for tags of item 1
1 | 3 | 3
-------+---------+------
2 | 42 | 1
2 | 1 | 2 <-- order for tags of item 2
-------+---------+------
3 | 3 | 1 <-- order for tags of item 3
... And the entities equivalent :
You are going from
//MToM : Many To Many
//OToM : One To Many
//MToO : Many To One
[Item] -MToM-> [Tags]
[Tags] -MToM-> [Item]
To
[Item] -OToM-> [ItemTags] -MToO-> [Tags]
[Tags] -OToM-> [ItemTags] -MToO-> [Item]
And, in your entities classes :
class Item
{
// some properties ...
/**
* #OneToMany(targetEntity="ItemTags", mappedBy="Item")
*/
private $ItemTags; //array
//more properties, and get/set
}
class Tags
{
// some properties ...
/**
* #OneToMany(targetEntity="ItemTags", mappedBy="Tags")
*/
private $ItemTags; //array
//more properties, and get/set
}
class ItemTags
{
/**
* #ManyToOne(targetEntity="Item", inversedBy="ItemTags")
* #JoinColumn(name="Item_id", referencedColumnName="id")
* ^-----^-------------------------^^---- Make sure to use the same than in your table !
*/
private $Item; // single Item
/**
* #ManyToOne(targetEntity="Tags", inversedBy="ItemTags")
* #JoinColumn(name="Tags_id", referencedColumnName="id")
* ^-----^-------------------------^^---- Make sure to use the same than in your table !
*/
private $Tags; // single Tags
private $Order;
// get/set and stuff
}
I'm having problems to define an association mapping and I don't know what to do to solve.
I want build a relation Many to Many between two objects but not only for one field.
One table refers to persons and the other to image, the target of this relation is represent when a person has been tagged by other person for this image
I need something like this:
| Tagged | Tagger | Photo |
| person_id_1 | person_id_2 | image_id_1 |
| person_id_3 | person_id_2 | image_id_1 |
| person_id_2 | person_id_4 | image_id_2 |
I try it using many to many relations like this:
/**
* #ORM\ManyToMany(targetEntity="Media")
* #ORM\JoinTable(name="persons_tagged",
* joinColumns={
* #ORM\JoinColumn(name="user_tagged", referencedColumnName="id"),
* #ORM\JoinColumn(name="user_tagger", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="media_id",referencedColumnName="id")
* }
* )
**/
private $employeeTagged;
When I try to update the schema by console, the table in DB it is created but without foreign keys because an exception of foreign key definition is threw and I have to create the foreign keys manually.
Someone has had a similar problem or a way to solve it? thanks
Create a new entity which has link to image, link to tagger (user), link to tagged (user).
You might also want to add created datetime, updated datetime, portion of image this person is in, description/text, etc.
I've been trying to solved this issue about the Doctrine configuration I have set with three Entities in Symfony2 (v2.3.9)
Let's assume my application's goal is to manage the enrollment of certain people to different training courses. And I do want to split these courses in different groups: A, B and C.
So, my entities are:
Enrollment
Course
Group
The enrollment of a certain person can be to more than one course, but he/she cannot enroll to the same Course in different groups. That means, having some sort of table which looks like this one:
----------------------------------------
| enrollment_id | course_id | group_id |
----------------------------------------
| 1 | 1 | 1 |
----------------------------------------
| 1 | 2 | 3 |
----------------------------------------
So far, I've been able to create a ManyToMany relationship between the Enrollment entity and the Course entity.
Enrollment.php
...
/**
*
* #ORM\ManyToMany(targetEntity="Course", inversedBy="enrollments")
* #ORM\JoinTable(name="enrollment_course",
* joinColumns={#ORM\JoinColumn(name="enrollment_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="course_id", referencedColumnName="id")}
* )
*
*/
protected $courses;
.....
And the Course entity looks like this in terms of relationship:
Course.php
....
/**
*
* #ORM\ManyToMany(targetEntity="Enrollment", mappedBy="courses")
*/
protected $enrollments;
....
That makes the configuration incomplete.
-----------------------------
| enrollment_id | course_id |
-----------------------------
| 1 | 1 |
-----------------------------
| 1 | 2 |
-----------------------------
Considering the fact that, in order to complete the enrollment, I need both informations the Course and the Group. How can I translate this into Doctrine annotation?
Do you have any clue?
Thank you so much for your help.
Dani.
You need a make an entity for the sole purpose of joining the fields.
/**
* #ORM\Entity
* #ORM\Table(name="base",uniqueConstraints={#ORM\UniqueConstraint(name="enrollment_course_group_idx", columns={"enrollment_id", "course_id", "group_id"})})
*/
class Base
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #ORM\ManyToOne(targetEntity="Enrollment")
* #ORM\JoinColumn(name="enrollment_id", referencedColumnName="id")
**/
private $enrollment;
/**
* #ORM\ManyToOne(targetEntity="course")
* #ORM\JoinColumn(name="course_id", referencedColumnName="id")
**/
private $course;
/**
* #ORM\ManyToOne(targetEntity="Group")
* #ORM\JoinColumn(name="group_id", referencedColumnName="id")
**/
private $group;
I have two tables in my database: user and media_contact. The media_contact table has a user_id, so, obviously, my intent is to be able to select media contacts based on a user.
The problem I'm having is that this fails:
// VNN/PressboxBundle/Entity/User.php
// $this in this case is a User object with id 26
$customContacts = $em->getRepository('VNNPressboxBundle:MediaContact')->findByUser($this);
This gives me nothing. $customContacts is empty. But:
mysql> select * from media_contact where user_id=26;
+-----+-------------+-----------------------+---------------+---------+
| id | name | email | media_area_id | user_id |
+-----+-------------+-----------------------+---------------+---------+
| 177 | Jason Swett | jason.swett#gmail.com | NULL | 26 |
| 183 | Sam | sam#sam.com | NULL | 26 |
+-----+-------------+-----------------------+---------------+---------+
2 rows in set (0.00 sec)
It should really be returning two objects. I really don't understand why this is happening.
Here are my annotations:
// User.php
/**
* #ORM\OneToMany(targetEntity="MediaContact", mappedBy="user")
*/
private $mediaContacts;
-
// MediaContact.php
/**
* #ORM\ManyToOne(targetEntity="User", inversedBy="mediaContacts")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
What could be going wrong?
You have to use $this->getId() instead of $this in order for it to work:
$customContacts = $em->getRepository('VNNPressboxBundle:MediaContact')->findByUser($this->getId());
I have a self referencing table as covered in the doctrine documentation (which is already in heavy use throughout the application and therefore changing to nested tree isn't a current option).
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/association-mapping.html#one-to-many-self-referencing
The table structure looks like this:
+----+----------+--------+
| id | parentID | Name |
+----+----------+--------+
| 1 | null | Name 1 |
| 2 | 1 | Name 2 |
| 3 | 1 | Name 3 |
| 4 | 2 | Name 4 |
| 5 | 1 | Name 5 |
--------------------------
Up until now in our forms we've been using the entire entities content our form, ie
$builder->add('hierarchyid', 'entity', array(
'class' => 'AcmeTestBundle:Hierarchies')
Which works fine, but now I want to be able to amend this to set points in the table, ie something like:
->add('hierarchyid', 'entity', array(
'class' => 'AcmeTestBundle:HierarchiesTest',
'query_builder' => function(HierarchiesTestRepository $repo)
{return $repo->findBy??????}
But I've hit a mental block how to complete this, any ideas?
One option I've considered is I already have code that builds an array collection of these entities, which is used elsewhere, but I'm unfamiliar with how I should go about implement a doctrine arraycollection in a form type.
private function createNodeArray($node)
{
$this->hierarchyArrayCollection->add($node);
foreach ($node->getChildren() as $hierarchy)
{
$this->createNodeArray($hierarchy);
}
}
query_builder option should return QueryBuilder object and I assume your findAllById() method returns actual data. You need to change that ;)
Other than that, you should probably add property option to indicate which field is to be displayed in list...
For anyone interested the solution I went with in the end was to generate an array and use choice field type rather than entity,such as this:
->add('hierarchyid', 'choice', array(
'choices' => $hierarchy)