ManyToMany on same table - symfony

I have a project in which I have a OneToMany relationship on the same database.
Currently it is designed like this:
/**
* #ORM\OneToMany(targetEntity="MyEntity", mappedBy="myCopiedItem")
*/
protected $mySource;
/**
* #ORM\ManyToOne(targetEntity="MyEntity", inversedBy="mySource")
* #ORM\JoinColumn(name="selected_myentity_copy_id", referencedColumnName="id")
*/
protected $myCopiedItem;
But now I have to make this relationship ManyToMany. So I did this:
/**
* #ORM\ManyToMany(targetEntity="MyEntity", mappedBy="myCopiedItem")
*/
protected $mySource;
/**
* #ORM\ManyToMany(targetEntity="MyEntity", inversedBy="mySource")
* #ORM\JoinTable(name="entity_has_copy")
*/
protected $myCopiedItem;
but the "entity_has_copy" table that symfony created has only 1 item (myentity_id) and I want to have 2 fields "myentity_id" & "selected_myentity_copy_id" which are both actualy id's from my "myentity" table...
What do I have to modify in order to have both id's in my generated table?
I'm sure I've missed something, but I cannot figure out WHAT :(
Note: Entity / table names were renamed for privacy

Solved this!
I had to add the relationship inside the definition...
So this is the correct definition for the JoinTable part:
/**
* #ORM\ManyToMany(targetEntity="MyEntity", inversedBy="mySource")
* #ORM\JoinTable(name="entity_has_copy",
* joinColumns={#ORM\JoinColumn(name="entity_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="entity_copy_id", referencedColumnName="id")}
* )
*/
protected $myCopiedItem;
Hope this will help others that are having same issue...
If you want to read more about how associations between entities are mapped with Doctrine, here's a good URL!

Related

Symfony2, Sonata : Customize title of collection

I've been able to translate most of the titles but i still have some non-friendly titles on collections (Table of relation)
Aire\AppBundle\Entity\ProjectSupported:000000002d1a645a000000015441bb1f
How could i custom them?
At best it could be the name of the related object ($investor->getName() and $project->getName() for exemple), at worst just a string.
In that case i'm using en entity with 2 relations
/**
* Owning Side
*
* #ORM\ManyToOne(targetEntity="Investor", inversedBy="supportedProject")
* #ORM\JoinColumn(name="investor_id", referencedColumnName="id")
**/
private $investor;
/**
* Owning Side
*
* #ORM\ManyToOne(targetEntity="Project", inversedBy="supportedProject")
* #ORM\JoinColumn(name="project_id", referencedColumnName="id")
**/
private $project;
Any hints or solutions?
Sonata is using the __toString method for text representation of objects.

Many to Many, One to Many or Many to One

I am trying to get my head around Doctrine 2 ORM relationships, I thought I had the hang of it but after reading a few symfony cookbook entries, I suspect I am actually a little confused.
I currently have a system where a template can contain multiple modules (including more than one of each type) and multiple templates can use the same module.
I thought that this would warrant a ManyToMany relationship and indeed looking at my table, it seems to work quite well.
However I realised as I was writing the database query that I needed the modules to load in a certain order, which means my join table needs to have a third 'order_by' column. I've read that a true join table is only ever two columns.
Hence the confusion. What should I set this up as in my entities?
Like #Kris said - You'll go for One to Many towards middle entity. If you go for Many to Many instead then you won't have class file for middle table which is an issue in the most cases.
M-N assumption: ONE Student studies in MANY Courses and ONE COURSE can have MANY Students.
Both of the examples below give you this ERD in database but you want to go for ONE to MANY version.
MANY to MANY:
This will create StudentCourse entity in database but as you see no actual class file for you to deal with.
class Student
{
protected $id;
protected $name;
/**
* #ORM\ManyToMany(targetEntity="Course")
* #ORM\JoinTable(
* name="StudentCourse",
* joinColumns={#ORM\JoinColumn(name="studentId", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="courseId", referencedColumnName="id")}
* )
*/
private $course;
}
class Course
{
protected $id;
protected $name;
}
ONE TO MANY:
This will create StudentCourse entity in database and as you see there is an actual class file for you to deal with when coding e.g. persist() etc.
class Student
{
protected $id;
protected $name;
/**
* #ORM\OneToMany(targetEntity="StudentCourse", mappedBy="studentMap",
* cascade={"persist", "remove"})
*/
protected $studentInverse;
}
class StudentCourse
{
protected $id;
/**
* #ORM\ManyToOne(targetEntity="Course", inversedBy="courseInverse")
* #ORM\JoinColumn(name="course", referencedColumnName="id",
* nullable=false, onDelete="CASCADE")
*/
protected $courseMap;
/**
* #ORM\ManyToOne(targetEntity="Student", inversedBy="studentInverse")
* #ORM\JoinColumn(name="student", referencedColumnName="id",
* nullable=false, onDelete="CASCADE")
*/
protected $studentMap;
}
class Course
{
protected $id;
protected $name;
/**
* #ORM\OneToMany(targetEntity="StudentCourse", mappedBy="courseMap",
* cascade={"persist", "remove"})
*/
protected $courseInverse;
}
EDIT:
onDelete="CASCADE" and cascade={"persist", "remove"} bits are not compulsory. They handle data redundancy. Is it bad to use redundant relationships?
You would need a OneToMany/ManyToOne
If you didn't need to save the order, it would be a manytomany, but since you do, that middle table now must be its own entity unfortunately.
So you would need the following Entities
Template
with a OneToMany to
TemplateModules (probably a better name for this one)
With a ManyToOne to
Modules

How do I map this relationship?

I'm having trouble mapping this relationship in Doctrine. I have a UseCase, which has many UseCaseSteps. A UseCaseStep has many sub-steps, which is a OneToMany on UseCaseStep. Here's the pertinent code I have atm:
/**
* UseCase
*
* #ORM\Table(name="use_cases")
* #ORM\Entity(repositoryClass="DesignCase\Bundle\Bundle\Entity\UseCaseRepository")
*/
class UseCase
{
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="Actor", inversedBy="use_cases", cascade={"persist", "remove"})
* #ORM\JoinTable(name="actors_use_cases")
*/
private $actors;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="UseCaseStep", mappedBy="useCase", cascade={"persist", "remove"})
* #ORM\OrderBy({"order" = "ASC"})
*/
private $steps;
}
/**
* UseCaseStep
*
* #ORM\Table(name="use_case_steps")
* #ORM\Entity(repositoryClass="DesignCase\Bundle\Bundle\Entity\UseCaseStepRepository")
*/
class UseCaseStep
{
/**
* #var integer
*
* #ORM\ManyToOne(targetEntity="UseCase")
*/
private $useCase;
/**
* #var ArrayCollection
*
* #ORM\OneToMany(targetEntity="UseCaseStep", mappedBy="parent", cascade={"persist", "remove"})
* #ORM\OrderBy({"order" = "ASC"})
*/
private $subSteps;
/**
* #var UseCase
*
* #ORM\ManyToOne(targetEntity="UseCase")
*/
private $useCaseReference;
/**
* #var UseCaseStep
*
* #ORM\ManyToOne(targetEntity="UseCaseStep")
* #ORM\JoinColumn(nullable=true)
*/
private $parent;
/**
* #var ArrayCollection
*
* #ORM\ManyToMany(targetEntity="BusinessRule", cascade={"persist", "remove"})
*/
private $businessRules;
}
That code isn't complete, but I think it has all the relevant information. What I want to do is create a new entity TestCase, which has many TestCaseSteps. A TestCase IS a UseCase with a little more information... same for TestCaseStep and UseCaseStep. IE, a TestCaseStep is a UseCaseStep with data input and expected output fields added to it. A user can create many TestCases from one UseCase.
I tried making UseCase and UseCaseStep #MappedSuperclass, but that doesn't have the desired effect. I get the obvious, "It is illegal to put an inverse side one-to-many or many-to-many association on mapped superclass" error. Plus, from the docs, I don't think that's the right approach anyway.
I'm having trouble wrapping my brain around it. Any thoughts? I hope I explained that well enough...
You have an issue there that is much more fundamental than Doctrine. You want to show inheritance in the database. For this approach there is no real correct solution. You could go with making an Entity TestCase that extends UseCase and overwrites the respective properties (need to make them protected) with another relation to TestCaseStep.
You do something similar with UseCaseStep and TestCaseStep. That way you have inheritance in the entities. Now you would have to make sure that you use another table and you end up with completely seperate entities database-wise. They just share the same properties in the entities but are seperate in database.
That approach would be in my opinion the easiest one to follow. Everything else seems to be very complicated as you cannot properly use one table with a different amount of properties for each entity. Each database table has a fixed set of properties that need to be reflected in an entity.
Another approach would surely be to just use the properties in the sub-entity that is used by this entity and create another relationship (many-to-one) between the TestCase and the UseCase or TestCaseStep and UseCaseStep respectively. But the latter approach isn't very easy and can end up being very complicated if you don't have a lot of knowledge about Doctrine, Symfony and databases in general.

Symfony2 ORM FK Composite

I'm new with Symfony2 and Doctrine 2 ORM, then i got a problem with composite FK association.
While the association OneToMany-ManyToOne by a single auto-increment ID works good, i got many troubles with the same kind of association but through a composite PK.
What i would like to do is an entity-structure that mirrors the below shema.
http://imageshack.us/photo/my-images/9/z07m.jpg (Sorry but I cannot insert images into the post)
where
prd_product_data.product_id
prd_product_data.language_id
make up together the PK of 'prd_product_data'
and
prd_product_image.pdoduct_id
prd_product_image.language_id
make up the FK linked to the table 'prd_product_data'.
These below
prd_product_image.pdoduct_id
prd_product_image.language_id
prd_product_image.file_image_id
make up, all together, the PK of 'prd_product_image'.
I read that Doctrine 2.1 and up, supports natively the composed PK - FK association but there are very few examples. Moreover, surfing on the web, i found just scattered fragments of similar situations but nothing of useful.
The main issue now, is that i'm unable to create one unique object for the two ids, like such an unique id.
For example...
Snapshot for the Entity ProductData where "product and language should make up the same object:
/**
*
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="product")
*/
protected $products_Pimgs;
/**
*
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="language")
*/
protected $products_Limgs;
Snapshot for the Entity ProductImage where *product_id* and *language_id* made up the FK for the entity ProductData:
/**
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="ProductData", inversedBy="products_Pimgs")
* #ORM\JoinColumn(name="product_id", referencedColumnName="product_id")
*/
protected $product;
/**
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="ProductData", inversedBy="products_Limgs")
* #ORM\JoinColumn(name="language_id", referencedColumnName="language_id")
*/
protected $language;
/**
*
* #ORM\Id
* #ORM\ManyToOne(targetEntity="FileImage", inversedBy="files_images")
* #ORM\JoinColumn(name="file_image_id", referencedColumnName="id")
*/
protected $file_image;
From these snapshots it's evident that those keys are working separately.
In the end, this is my doctrine version, taken from the composer:
"doctrine/orm": ">=2.2.3,<2.4-dev",
How can i create an unique reference with two objects with ORM?
Read the documentation chapter Composite Primary Keys.
/**
* #ORM\Id
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="product")
*/
protected $products_Pimgs;
/**
* #ORM\Id
* #ORM\OneToMany(targetEntity="ProductImage", mappedBy="language")
*/
protected $products_Limgs;

Doctrine2 symfony2 multiple manytomany relations

i have a Gift entity, this entity has a sender, and a receiver...both from the entity User
a user can be a sender of many gifts to other users. but also a receiver of many gifts from many users
the way i see it, the solution inside my Gift entity would be like this:
/**
* #ORM\ManyToMany(targetEntity="Tracker\UserBundle\Entity\User")
* #ORM\JoinTable(name="gift_user",
* joinColumns={#ORM\JoinColumn(name="sender_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="gift_id", referencedColumnName="id")}
* )
*/
protected $senders;
/**
* #ORM\ManyToMany(targetEntity="Tracker\UserBundle\Entity\User")
* #ORM\JoinTable(name="gift_user",
* joinColumns={#ORM\JoinColumn(name="receiver_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="gift_id", referencedColumnName="id")}
* )
*/
protected $receivers;
but when i run php app/console doctrine:schema:update --dump-sql i get:
[Doctrine\DBAL\Schema\SchemaException]
The table with name 'finaldb.gift_user' already exists.
how do i have to change my syntax, configuration, so i end up with a table like this?
gift_id | sender_id | receiver_id
What you are trying to achieve is not possible without two join tables.
Each #ManyToMany association requires a different join table. That because the join table does not know anything else than two linked entities (without knowing the direction of the association). Also, join tables generated by Doctrine ORM don't have any auto-incremental identifier, since the two references already represent the table's primary key.
Here is the stuff :
You can use joinTable to specific the join table name
/**
* #ORM\ManyToMany(targetEntity="Tracker\UserBundle\Entity\User")
* #ORM\JoinTable(name="gift_user",joinTable="myprefix_mytable_senders",
* joinColumns={#ORM\JoinColumn(name="sender_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="gift_id", referencedColumnName="id")}
* )
*/
protected $senders;
/**
* #ORM\ManyToMany(targetEntity="Tracker\UserBundle\Entity\User")
* #ORM\JoinTable(name="gift_user",joinTable="myprefix_mytable_receivers"
* joinColumns={#ORM\JoinColumn(name="receiver_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="gift_id", referencedColumnName="id")}
* )
*/
protected $receivers;

Resources