This seems simple but I can't get it right:
There are three entities: Fruit, Vegetable and Snack. Snack has the fields id, time and food. Food is a reference to either one fruit or one vegetable. So it is basically a many-to-one/one-to-many relationship as one snack will always only hold one food. But there is more than one target entity.
How would I map this in Doctrine2?
A simple solution I would have used before knowing Doctrine2 would be to use two fields: food_type and food_id. But how can I make a connection from food type to the correct entity? I thought about an array of JoinColumns but can't find a way to connect the correct entity. I also had a look at mapped superclasses because there is a DiscriminatorColumn, but it also seems to be the wrong approach. If I get it right the superclass can't be an entity itself - so I cannot create a food entity.
Any help is appreciated. I'm sure I am missing something simple here.
You can create a (abstract) mapped superclass called Food, which can hold some basic information for Fruit and Vegetable.
The keyword for your question is inheritance mapping, this is the documentation for it: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/inheritance-mapping.html#inheritance-mapping
Then you could reference this mapped superclass in your entity relationship.
Related
My database diagram corresponds to:
Each table has his own Symfony Entity class. My app view shows:
I need to associate a Discount Entity to multiple entities: Sneaker, Tshirt, Trouser or even more entities.
First solution:
Create N:N tables between discounts and the others. The problem is that I could need create new tables to apply discount and then I would have to create more N:N tables. So I discard this solution.
Second solution:
Create a generic table with to_entity and to_entity_id fields that let me map discount to to_entity entity destination (Sneaker, Tshirt, Trouser or other):
How can I implement second solution in Symfony ? Or is there another solution possible ?
Thanks.
Polymorphism with Doctrine is not easy at all.
Try to solve it through mapped superclasses and/or inheritance. Your first solution could be simplified by using single-table inheritance. You should change the discriminator map for every new "discountable" entity.
Investigate on Dynamic mapping through loadClassMetadata event. You can create OneToMany relationships for every entity implementing a custom interface (i.e. DiscountableInterface).
I'm struggling for hours about this one...
I have a Buddy object (Entity) which holds (should hold) a Preference object. Inside this object I have several collections of sub-objects. For simplicity I'll just explain it with one single sub-object. Let's call it University. It's also an entity of its own.
Currently, Buddy and Preference have a One-to-One association with Buddy having a database column preference_id and Preference just an id and nothing else.
Preference and University have a Many-to-Many association, mapped by Doctrine with a buddy_preferences_universities table with preference_id and univeristy_id columns.
My goal is to establish an association between Buddy and University keeping the described class hierarchy but without the need of a useless preferences table, i.e. I still want to be able to issue $unis = $buddy->getPreference()->getUniversities and $unis being a University[] collection.
So, is it possible to "skip" the Preference entity and map the associations directly with the buddy_id?
Here's an image of the tables created by Doctrine's schema-tool:
If necessary I can also post the classes and/or XML mapping files.
Thank you!
Can you not make your buddy_preferences table like this:
id: char(36)
university_id: char(36)
country_id: char(36)
interest_id: char(36)
Like that you can drop your 3 join tables.
Now you can do $buddy->getPreference()->getUniversity();
How about remove the Preference entity of your model, then link with a Many2Many relation the Buddy and the University entities.
If you really need to keep the $buddy->getPreference()->getUniversities() function call to get all the Universities linked with a Buddy object, instead of $buddy->getUniversities()(which sound more logical in my mind, but however..), you can add a function in the Buddy class like this :
public function getUniversities()
{
return $this->universities;
}
// Now you'll be able to call $buddy->getPreference()->getUniversities()
public function getPreference()
{
return $this;
}
Althought it's a solution for your needs, I don't really think it's a good solution.
Why the $buddy->getPreference() is so important if you don't need a Preference object ?
I am still trying to understand polymorphic associations in Doctrine2.
As I understand it, basic polymorphic associations work by using inheritance. If, for example, I had tables/classes OWNER, CAT and DOG, then the way to enable $owner->pet to point at either the CAT or the DOG table, would be to have them each extend a fourth class, PET, which is known as a mapped superclass. Then $owner->pet could return either a CAT or a DOG depending on what had been assigned, and Doctrine2 would be able to distinguish them.
That's simple enough. But what if I want to have two polymorphic associations which can point at the same object? For example, lets say that I have a table of ADMIRALS, each of which could command a FLEET or a PLANET. Let's also say that I have a table of SECTORS, each of which could contain a PLANET or a MOON.
Let's assume that I want $admiral->command to reference both PLANETS and FLEETS, and that I want $sector->contents to reference both PLANETS and MOONS. PLANET can't extend both command and contents as mapped superclasses. Is there a different way to make this work?
you can try ResolveTargetEntityListener see
you can point admiral's command property to an Interface, which is implemented by both PLANETS
and FLEETS
the same is with sector's contents
Is it possible to have a CTI in Doctrine 2 that does not shared the autoincrement? For example, i have a Pet entity and two sub-classes, Cat and Dog. However, if i create two dogs and one cat, the next ID for BOTH entities will be 4. I wanted Dog and Cat to have it's own autoincrement.
I don't see how would this work, regardless of doctrine.
What if you don't know which entity to expect and have only the id?
For example get the Pet with id 4?
You can't query by base class, which IMHO breaks the purpose of inheritance.
With CTI you get separate tables, but still it is just plain inheritance, CTI is just a object-relational mapping shema.
From the object model perspective having two entities of same type with the same id just doesn't make sense.
So you can either stick with what you have, or get rid of the inheritance completely and manage Cat and Dog as two independent entities. I would suggest you stick with the first option.
Also, with CTI there is no autoincrement on Cat and Dog, only on Pet. Child tables just copy the ID from parent, regardless how the ID was generated.
I'm writing constructors for my classes in a Doctrine2 application, let's say Fruits, Apple, Bananas.
Fruits is the parent class, where Apples and Bananas inherit from Fruits using single table inheritance on field type.
On the Doctrine2 documentation page, there is an example provided for single table inheritance. If we are always discriminating using Single Table Inheritance, should the base class Fruits be abstract because the discriminator field must always be set? If so, should the constructor for Fruits also be protected to prevent this behavior?
As there are no methods in your parent class "Fruits" that you need to redeclare I don't think there is an explicit need for it to be declared as abstract.
Also you may find a use case where you may want an instance of "Fruit" to be persisted (undetermined as to what type of fruit it is). Marking the parent as abstract will prevent you from being able to do this.
Maybe fruit is a bad example. But the Person example they have in the documentation is better. Employees will inherit Person definitions. But I may also want to persist just an instance of Person, undetermined of type. Hence the "person" = "Person" in the #DiscriminatorMap.
http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/inheritance-mapping.html#single-table-inheritance