In my application I have a cigar humidor entity that has 8 slots. I would like each slot to hold an instance of any given of the hundreds of cigars there are to pick from.I can add a cigar to the cigar slot once for one humidor but I can not swap to a different humidor and add the same cigar to the slot1. I was thinking that with being in different humidors that it would surely not be an issue but I am now getting the exception "An exception occurred while executing 'UPDATE humidor SET slot_1 = ? WHERE id = ?' with params [2, 8]:SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2' for key 'UNIQ_4AE64E7F3CF622F8'"' I'm not exactly an expert with doctrine and am not totally sure on how I should go about modeling this. Any advice would be fantastic.
Here is the humidor with the slots
/**
* Humidor
*
* #ORM\Table(name="humidor")
* #ORM\Entity(repositoryClass="AppBundle\Repository\HumidorRepository")
*/
class Humidor
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255, nullable=true)
*/
private $name;
/**
* #ORM\ManyToOne(targetEntity="UserBundle\Entity\User", inversedBy="humidors")
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
private $user;
/**
* #ORM\OneToOne(targetEntity="Cigar")
* #ORM\JoinColumn(name="slot_1", referencedColumnName="id")
*/
private $slot1;
/**
* #ORM\OneToOne(targetEntity="Cigar")
* #ORM\JoinColumn(name="slot_2", referencedColumnName="id")
*/
private $slot2;
/**
* #ORM\OneToOne(targetEntity="Cigar")
* #ORM\JoinColumn(name="slot_3", referencedColumnName="id")
*/
private $slot3;
/**
* #ORM\OneToOne(targetEntity="Cigar")
* #ORM\JoinColumn(name="slot_4", referencedColumnName="id")
*/
private $slot4;
/**
* #ORM\OneToOne(targetEntity="Cigar")
* #ORM\JoinColumn(name="slot_5", referencedColumnName="id")
*/
private $slot5;
/**
* #ORM\OneToOne(targetEntity="Cigar")
* #ORM\JoinColumn(name="slot_6", referencedColumnName="id")
*/
private $slot6;
/**
* #ORM\OneToOne(targetEntity="Cigar")
* #ORM\JoinColumn(name="slot_7", referencedColumnName="id")
*/
private $slot7;
/**
* #ORM\OneToOne(targetEntity="Cigar")
* #ORM\JoinColumn(name="slot_8", referencedColumnName="id")
*/
private $slot8;
and then my cigar entity
/**
* Cigar
*
* #ORM\Table(name="cigar")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CigarRepository")
* #ORM\HasLifecycleCallbacks()
*/
class Cigar
{
/**
* #ORM\PrePersist()
*/
public function onPrePersist(){
$this->setName($this->getManufacturer()->getName() . " " . $this->getVariant());
}
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var int
*
* #ORM\Column(name="gauge", type="integer")
*/
private $gauge;
/**
* #var string
*
* #ORM\Column(name="body", type="string", length=255)
*/
private $body;
/**
* #var string
*
* #ORM\Column(name="wrapper_country", type="string", length=255)
*/
private $wrapperCountry;
/**
* #var string
*
* #ORM\Column(name="variant", type="string", length=255)
*/
private $variant;
/**
* #var string
*
* #ORM\Column(name="description", type="text")
*/
private $description;
/**
* #var string
*
* #ORM\Column(name="filler_country", type="string", length=255)
*/
private $fillerCountry;
/**
* #ORM\ManyToOne(targetEntity="Manufacturer", inversedBy="cigars")
* #JoinColumn(name="manufacturer_id", referencedColumnName="id")
*/
private $manufacturer;
/**
* #ORM\ManyToOne(targetEntity="Wrapper", inversedBy="cigars")
* #JoinColumn(name="wrapper_id", referencedColumnName="id")
*/
private $wrapper;
/**
* #ORM\ManyToOne(targetEntity="Shape", inversedBy="cigars")
* #JoinColumn(name="shape_id", referencedColumnName="id")
*/
private $shape;
/**
* #ORM\Column(type="string")
*
*/
private $image;
/**
* #var string
* #ORM\Column(type="string")
*/
private $name;
As you have one-to-one mapping, doctrine creates unique index for those columns. Let's consider this example (I've left only single slot as it's enough for this example):
id slot_1
1 11
2 12
This means that you have 2 cigars with IDs 11 and 12 assigned to humidor 1 and 2 respectively. There is unique index on slot_1 column here - this guarantees that any single cigar does not belong to two different humidors.
If you try to switch them, following SQL statements are generated:
UPDATE humidors SET slot_1 = 12 WHERE id = 1;
UPDATE humidors SET slot_1 = 11 WHERE id = 2;
Unfortunately, first statement cannot be executed, as database does not allow cigar 12 to be in both humidor 1 and 2 at once.
Simplest solution would be to change one-to-one relations to many-to-one (in your $slotX fields) - this would remove unique constraints, otherwise it would work the same in your example as there is no reverse relation. Furthermore, as there are 8 slots and cigars cannot belong to several of these (if I correctly understand), rules are already not strictly controlled by the database itself.
Another way would be to switch those with temporary null values etc. but it's even harder with doctrine, as you would need two separate flush statements and, optionally, manually wrapping these in a transaction to avoid inconsistent state in the database.
Related
Am having a bit of a challenge creating entity relationship between a product its Category and associated color(s) with the following Entities (I omitted the getters and setters though):
#Product
/**
* Product
*
* #ORM\Table(name="product")
* #ORM\Entity(repositoryClass="AppBundle\Repository\ProductRepository")
*/
class Product
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=255)
*/
private $name;
/**
* #var float
*
* #ORM\Column(name="price", type="float")
*/
private $price;
/**
* #var int
*
* #ORM\Column(name="category", type="integer")
*
* Many Products have one category
*
* #ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id", nullable=false)
*/
protected $category;
/**
* #var int
*
* Many Products have one color
*
* #ORM\ManyToOne(targetEntity="Color", inversedBy="products")
* #ORM\JoinColumn(name="color_id", referencedColumnName="id")
*
* #ORM\Column(name="color", type="integer")
*/
private $color;
}
#Category
/**
* Category
*
* #ORM\Table(name="category")
* #ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
*/
class Category
{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="string", length=170, unique=true)
*/
private $name;
/**
* #var string
*
* #ORM\Column(name="desc", type="string", length=170, nullable=true)
*/
private $description;
/**
* One Category has many products assigned to it
*
* #ORM\OneToMany(targetEntity="Product", mappedBy="category", cascade={"persist"})
*/
private $products;
/**
* Class Constructor
*
* #param None
* #return void
**/
public function __construct()
{
$this->products = new ArrayCollection();
}
}
#Color
class Color{
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="color", type="string", length=191, unique=true)
*/
private $color;
/**
* #var string
*
* #ORM\Column(name="code", type="string", length=191, unique=true)
*/
private $hexcode;
/**
* One Color has many products assigned to it
*
* #ORM\OneToMany(targetEntity="Product", mappedBy="color", cascade={"persist"})
*/
private $products;
/**
* Class Constructor
*
* #param none
* #return void
**/
public function _construct(){
$this->products = new ArrayCollection();
}
}
When I run:
* php bin/console doctrine:schema:validate:
I get the error messages:
* The association AppBundle\Entity\Category#products refers to the owning
side field AppBundle\Entity\Product#category which is not defined as
association, but as field.
* The association AppBundle\Entity\Category#products refers to the owning
side field AppBundle\Entity\Product#category which does not exist.
and:
* The association AppBundle\Entity\Color#products refers to the owning side
field AppBundle\Entity\Product#color which is not defined as association,
but as field.
* The association AppBundle\Entity\Color#products refers to the owning side
field AppBundle\Entity\Product#color which does not exist.
I noticed that whenever I comment out the lines:
** #ORM\Column(name="category", type="integer")
** #ORM\Column(name="color", type="integer")
The above errors vanish but I get a new message and error saying:
** [Mapping] OK - The mapping files are correct.
** [Database] FAIL - The database schema is not in sync with the current
mapping file.
What could i be doing wrong, am new to the doctrine concept, and i have followed the documentations. Any help would be appreciated...
For the Doctrine ORM the relations are not Integers but Entity objects.
Remove The #ORM\Column annotations from all fields with relations (in each entity).
Then update your database schema in development environment with:
php bin/console doctrine:schema:update --force
Then generate a doctrine migration file to execute on your production server
php bin/console doctrine:migrations:generate
Update the generetad migration file to your needs
And execute him by this way
php bin/console doctrine:migrations:execute timestampOfTheMigrateFile
I've been struggling for the past few days on a simple case of cascade removing using Doctrine.
Doctrine and Symfony are up to date.
I have two entities Serie and Asset that are linked to each other by two relationships OneToOne and OneToMany.
The schema is exactly like this :
A Serie has many Assets. (content).
A Serie can have an Asset. (a preview, this field is nullable).
However, no matter how I try to write and rewrite the annotations, I ALWAYS end up with this error:
An exception occurred while executing 'DELETE FROM serie WHERE id = ?' with params [1]:
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or
update a parent row: a foreign key constraint fails
(galanthis.asset, CONSTRAINT FK_2AF5A5CAA3A9334 FOREIGN KEY
(serie) REFERENCES serie (id))
Of course, the problem disappear if I delete the "preview" field and its annotations in the following code:
/**
* Serie
*
* #ORM\Table(name="serie")
* #ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
* #ORM\HasLifecycleCallbacks
*/
class Serie
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=96)
*/
private $title;
/**
* #var integer
*
* #Gedmo\SortablePosition
* #ORM\Column(name="position", type="integer", nullable=true)
*/
private $position;
/**
* #var \Portfolio
*
* #ORM\ManyToOne(targetEntity="Portfolio", inversedBy="series")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="portfolio", referencedColumnName="id")
* })
*/
private $portfolio;
/**
* #var \Asset
*
* #ORM\OneToOne(targetEntity="Asset")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="preview", referencedColumnName="id", nullable=true, onDelete="SET NULL")
* })
*/
private $preview;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\OneToMany(targetEntity="Asset", mappedBy="serie", cascade={"remove"})
**/
private $assets;
Here's the code for the Asset entity:
/**
* Asset
*
* #ORM\Table(name="asset")
* #ORM\Entity(repositoryClass="Gedmo\Sortable\Entity\Repository\SortableRepository")
* #ORM\HasLifecycleCallbacks
* #ORM\InheritanceType("SINGLE_TABLE")
* #ORM\DiscriminatorColumn(name="asset", type="string")
* #ORM\DiscriminatorMap({"asset" = "Asset", "video" = "Video","image" = "Image"})
*
*/
class Asset
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var string
*
* #ORM\Column(name="path", type="string", length=128)
*/
protected $path;
/**
* #var string
*
* #ORM\Column(name="filename", type="string", length=64)
*/
protected $filename;
/**
* #var integer
*
* #ORM\Column(name="position", type="integer", nullable=true)
* #Gedmo\SortablePosition
*/
protected $position;
/**
* #var string
*
* #ORM\Column(name="description", type="string", length=255, nullable=true)
*/
protected $description;
/**
* #var string
*
* #ORM\Column(name="mime", type="string", length=16, nullable=true)
*/
protected $mime;
/**
* #var \Serie
*
* #ORM\ManyToOne(targetEntity="Serie", inversedBy="assets")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="serie", referencedColumnName="id")
* })
*/
protected $serie;
/**
* #var UploadedFile
*/
protected $file;
/**
* #var string
*/
protected $extension;
It's driving me crazy, it's just some simple relationships... Is there a mistake I'm not seeing anymore, or do i need to use a workaround?
My guess is to set the cascade={"remove"} on the ManyToOne relationship in the Asset entity and not the other way around. That way, it tells Doctrine what to do when you delete a serie that is linked to many assets.
I nead help.
I have 3 entities. Book, Category And BookCategory - book can have multiple categories so i used another table.
I can easily acces Book and Category useing BookCategory table but i dont know how to do this by Book->BookCategory->Category.
class Category
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="name", type="text")
*/
private $name;
/**
* #var Category
* #ORM\ManyToOne(targetEntity="Category", inversedBy="Category")
* #ORM\JoinColumn(name="parent", referencedColumnName="id")
*/
private $parent;
class BookCategory
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var Book
* #ORM\ManyToOne(targetEntity="Book", inversedBy="BookCategory")
* #ORM\JoinColumn(name="book_id", referencedColumnName="id")
*/
private $bookId;
/**
* #var Category
* #ORM\ManyToOne(targetEntity="Category", inversedBy="BookCategory")
* #ORM\JoinColumn(name="category_id", referencedColumnName="id")
*/
private $categoryId;
/**
* #var integer
*
* #ORM\Column(name="priority", type="integer")
*/
private $priority;
class Book
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="title", type="text")
*/
private $title;
/**
* #var string
*
* #ORM\Column(name="author", type="text")
*/
private $author;
/**
* #var float
*
* #ORM\Column(name="price", type="float")
*/
private $price;
How i need to config my entities or how to make my DQL to achive wanted results?
With your code, you only established the relationship from BookCategory to Book. As you said, that enables you to get the Book associated to one BookCategory.
To go the other way and get all BookCategory that belong to one book, you also need to specify this relationship. What you want is a OneToMany relationship from Book to BookCategory.
<?php
//...
use Doctrine\ORM\Mapping\OneToMany;
class Book
{
//...
/**
* #OneToMany(targetEntity="BookCategory", mappedBy="bookId")
*/
private $bookCategories;
//...
}
class BookCategory
{
//...
/**
* #var Book
* #ORM\ManyToOne(targetEntity="Book", inversedBy="bookCategories")
* #ORM\JoinColumn(name="book_id", referencedColumnName="id")
*/
private $bookId;
//...
}
After adding the necessary getters and setters, getBookCategories() will give you an Array with all BookCategory that belong to the Book.
For more details, have a look at the official Symfony2 documentation:
http://symfony.com/doc/current/book/doctrine.html#relationship-mapping-metadata
Edit:
Included use statement. Corrected inversedBy property for bookId.
Hi I read this article http://docs.doctrine-project.org/en/latest/reference/inheritance-mapping.html yet I'm not quiet sure how to accomplish the following:
I have a "user"-Table, a "man"-Table and a "woman"-table.
I want my php classes Man and Woman extend the User Object.
Annotationmapping:
namespace Core\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* User
*
* #ORM\Table(name="user", uniqueConstraints={#ORM\UniqueConstraint(name="email_UNIQUE", columns={"email"}), #ORM\UniqueConstraint(name="username_UNIQUE", columns={"username"})})
* #ORM\Entity
*/
class User
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="IDENTITY")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="first_name", type="string", length=255, nullable=true)
*/
private $firstName;
/**
* #var string
*
* #ORM\Column(name="middle_name", type="string", length=255, nullable=true)
*/
private $middleName;
/**
* #var string
*
* #ORM\Column(name="last_name", type="string", length=255, nullable=true)
*/
private $lastName;
/**
* #var string
*
* #ORM\Column(name="username", type="string", length=255, nullable=false)
*/
private $username;
/**
* #var string
*
* #ORM\Column(name="email", type="string", length=255, nullable=false)
*/
private $email;
/**
* #var string
*
* #ORM\Column(name="password", type="string", length=255, nullable=false)
*/
private $password;
/**
* #var \DateTime
*
* #ORM\Column(name="created_at", type="datetime", nullable=true)
*/
private $createdAt;
/**
* #var \DateTime
*
* #ORM\Column(name="updated_at", type="datetime", nullable=false)
*/
private $updatedAt;
/**
* #var \DateTime
*
* #ORM\Column(name="last_login", type="datetime", nullable=false)
*/
private $lastLogin;
/**
* #var string
*
* #ORM\Column(name="login_hash", type="string", length=255, nullable=true)
*/
private $loginHash;
/**
* #var boolean
*
* #ORM\Column(name="is_premium", type="boolean", nullable=false)
*/
private $isPremium = '0';
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Core\Entity\Bill", inversedBy="user")
* #ORM\JoinTable(name="user_has_bill",
* joinColumns={
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="bill_id", referencedColumnName="id")
* }
* )
*/
private $bill;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Core\Entity\Picture", inversedBy="user")
* #ORM\JoinTable(name="user_has_picture",
* joinColumns={
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="picture_id", referencedColumnName="id")
* }
* )
*/
private $picture;
/**
* Constructor
*/
public function __construct()
{
$this->bill = new \Doctrine\Common\Collections\ArrayCollection();
$this->picture = new \Doctrine\Common\Collections\ArrayCollection();
}
}
Woman:
namespace Core\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Woman
*
* #ORM\Table(name="woman", indexes={#ORM\Index(name="fk_woman_user1_idx", columns={"user_id"})})
* #ORM\Entity
*/
class Woman
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
*/
private $id;
/**
* #var \Core\Entity\User
*
* #ORM\Id
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\OneToOne(targetEntity="Core\Entity\User")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="user_id", referencedColumnName="id")
* })
*/
private $user;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Core\Entity\Cart", inversedBy="woman")
* #ORM\JoinTable(name="woman_has_cart",
* joinColumns={
* #ORM\JoinColumn(name="woman_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="cart_id", referencedColumnName="id")
* }
* )
*/
private $cart;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Core\Entity\Interest", inversedBy="woman")
* #ORM\JoinTable(name="woman_has_interest",
* joinColumns={
* #ORM\JoinColumn(name="woman_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="interest_id", referencedColumnName="id")
* }
* )
*/
private $interest;
/**
* #var \Doctrine\Common\Collections\Collection
*
* #ORM\ManyToMany(targetEntity="Core\Entity\Man", inversedBy="woman")
* #ORM\JoinTable(name="woman_has_man",
* joinColumns={
* #ORM\JoinColumn(name="woman_id", referencedColumnName="id")
* },
* inverseJoinColumns={
* #ORM\JoinColumn(name="man_id", referencedColumnName="id")
* }
* )
*/
private $man;
/**
* Constructor
*/
public function __construct()
{
$this->cart = new \Doctrine\Common\Collections\ArrayCollection();
$this->interest = new \Doctrine\Common\Collections\ArrayCollection();
$this->man = new \Doctrine\Common\Collections\ArrayCollection();
}
}
The man mapping looks (for now) the same as the woman.
Here a little Snippet from MysqlWorkbench http://s14.directupload.net/images/131013/fbg7okyn.png
The basic idea is this:
Men and Women share some common logic and individual logic. For example take a login. Men and Women need an email and a password to log in. Since it's redundant to implement the same login logic twice I thought of creating a more abstract class, the User, which is where I want to put everything which applies to men and women, like name, email, password, login logic etc...
This is where it gets tricky with doctrine. Men and women will have individual fields to store in the database, yet they still need their "common data"(name, password etc...), so a simple class Man extends User might not work out correctly. I store the corresponding id of the User on men and women. So there is an identification.
What I had in mind is, if I do $men->getPassword() it should use the getPassword()function of the corresponding User object.
I hope I cleared up my intend.
Kind Regards and thank you for digging through.
i have done this what you're looking for in one of my projects once, It's done not too good code wise, but the mapping is fine ;) Please check this link
Item.php.dist would be your User Entity
(Property|Vehicle).php.dist would be your Man / Women Entity
Please notice that the Property Discriminator Mapping is missing within the code examples. I do it differently in the application ;)
Ultimately you wouldn't want to have separate "Tables" on your SQL Server. It all belongs to the Superclass "User" and therefore belongs to the User-Table. You will extends the UserTable and use DiscriminatorMapping to map specific entities.
Note: A Man can not be editted to become a Woman! You'd have to kill the man and give birth to a woman :P
Imagina this Model:
User
*id
-name
-surname
Man extends User
-pc_power
Woman extends User
-nail_color
Your DB-Schema would look like this:
Table User:
*id (pk)
-discriminator (not nullable) (value: man or woman)
-name (not nullable)
-surname (not nullable)
-pc_power (nullable as far as DB is concerned)
-nail_color (nullable as far as DB is concerned)
You do not need 3 tables to mod your models like this. It makes literally no sense to do this. It just slows your Queries down by quite a bit.
Now a Dataset could look like this:
A Man: (1, man, john, doe, 4ghz, null)
A Woman: (2, woman, john, doe, null, pink)
Now on Doctrines side of things you do Queries against the USER-Entity
$entity = $userRepository->find(1);
echo get_class($entity); // returns "Man"
$entity = $userRepository->find(2);
echo get_class($entity); // returns "Woman"
Does that make things more clear, because otherwise i'm simply unable to help you :P
I have an entity that in it's lifetime moves to different tables. Like so:
A village has many units
An army movement on the map contains many units
After an attack, the log file contains many units (with extra amount_killed column)
So anyway, this Unit is what I consider my entity, that can either be attached to a Village, Movement or Log via a table and foreign key.
I would think in Doctrine there is a way to say, this is an entity and it can as a foreign key to multiple tables. The thing is, I want to pluck Units from my Village and put them into a Movement but they're not defined as the same item so it will break.
My code for current usage will look something like this for transferring an entity to another table:
$villageUnits = $village->getVillageUnits();
$movementUnits = new ArrayCollection();
foreach ($villageUnits as $villageUnit) {
$movementUnit = new MovementUnit();
$movementUnit
->setLevel($villageUnit->getLevel());
->setAmount($villageUnit->getAmount());
->setUnitType($villageUnit->getUnitType());
$movementUnits->add($movementUnit);
}
At the moment, they're all seperate entities defined with Doctrine as follows:
TABLES
village_units
---------
id, village_id, unit_type_id, amount, level
movement_units
---------
id, movement_id, unit_type_id, amount, level
log_units
---------
id, log_id, unit_type_id, amount, amount_killed, level
ENTITIES
/**
* MovementUnit
*
* #ORM\Table(name="movement_units")
* #ORM\Entity
*/
class MovementUnit
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\GeneratedValue(strategy="IDENTITY")
* #ORM\Id
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="amount", type="integer", nullable=false)
*/
private $amount;
/**
* #var integer
*
* #ORM\Column(name="level", type="integer", nullable=false)
*/
private $level;
/**
* #var Movement
*
* #ORM\ManyToOne(targetEntity="Movement")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="movement_id", referencedColumnName="id")
* })
*/
private $movement;
/**
* #var UnitType
*
* #ORM\OneToOne(targetEntity="UnitType")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="unit_type_id", referencedColumnName="id")
* })
*/
private $unitType;
}
/**
* VillageUnit
*
* #ORM\Table(name="village_units")
* #ORM\Entity
*/
class VillageUnit
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\GeneratedValue(strategy="IDENTITY")
* #ORM\Id
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="amount", type="integer", nullable=false)
*/
private $amount;
/**
* #var integer
*
* #ORM\Column(name="level", type="integer", nullable=false)
*/
private $level;
/**
* #var Village
*
* #ORM\ManyToOne(targetEntity="Village")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="village_id", referencedColumnName="id")
* })
*/
private $village;
/**
* #var UnitType
*
* #ORM\OneToOne(targetEntity="UnitType")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="unit_type_id", referencedColumnName="id")
* })
*/
private $unitType;
}
/**
* LogUnit
*
* #ORM\Table(name="log_units")
* #ORM\Entity
*/
class LogUnit
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer", nullable=false)
* #ORM\GeneratedValue(strategy="IDENTITY")
* #ORM\Id
*/
private $id;
/**
* #var integer
*
* #ORM\Column(name="amount", type="integer", nullable=false)
*/
private $amount;
/**
* #var integer
*
* #ORM\Column(name="dead", type="integer", nullable=false)
*/
private $dead;
/**
* #var integer
*
* #ORM\Column(name="level", type="integer", nullable=false)
*/
private $level;
/**
* #var LogArmy
*
* #ORM\ManyToOne(targetEntity="LogArmy")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="log_army_id", referencedColumnName="id")
* })
*/
private $logArmy;
/**
* #var UnitType
*
* #ORM\OneToOne(targetEntity="UnitType")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="unit_type_id", referencedColumnName="id")
* })
*/
private $unitType;
}
I had the exact same problem and solved it with the answer of Robin in this question: Doctrine 2 Inheritance Mapping with Association
Just change the inheritanceType from "SINGLE_TABLE" to "JOINED" and your setup is working. If not, try using doctrine-module orm:schema-tool:create it will create the tables for you.