Reputation: 1570
I'm trying to create a simple polymorphic attributes table that could store key value pairs for different types of objects. Using single table inheritance, this is my current configuration:
/**
* @Entity @Table(name="attributes")
* @InheritanceType("SINGLE_TABLE")
* @DiscriminatorColumn(name="subject", type="string")
* @DiscriminatorMap({"page" = "PageAttribute", "product" = "ProductAttribute"})
*/
class PageAttribute
{
/**
* @ManyToOne(targetEntity="Page", inversedBy="attributes")
* @JoinColumn(name="subject_id", referencedColumnName="id")
*/
private $page;
}
/**
* @Entity @Table(name="attributes")
*/
class ProductAttribute extends PageAttribute
{
/**
* @ManyToOne(targetEntity="Product", inversedBy="attributes")
* @JoinColumn(name="subject_id", referencedColumnName="id")
*/
private $product;
}
The problem is that when this schema is loaded, the subject_id column is created with a foreign key constraint linking to the pages table.
Is there a way to prevent this constraint so that the subject_id can be used for all foreign keys? Otherwise I'd have to have a column for each type of object, which I'm trying to avoid.
Upvotes: 2
Views: 1019
Reputation: 320
I had this same issue. Here is how I resolved it:
/**
* @Entity @Table(name="attributes")
*/
class ProductAttribute extends PageAttribute
{
public static function getSubject() {
return 'product';
}
/**
* @ManyToOne(targetEntity="Product", inversedBy="attributes")
* @JoinColumn(name="product_id", referencedColumnName="id")
*/
private $product;
}
In other words, instead of using subject_id to reference all entities, you use separate join columns for each type of entity. Then you can use the static function to get the parameter name of the "subject" column.
So for instance:
$subject = $genericPageAttribute->{$genericPageAttribute::getSubject()};
Would in this case return an instance of "Product".
To make this solution even better I'd suggest writing an interface which all "subjects" could implement.
I am not sure if this would cover all cases, but it seems to work fine for me so far.
Let me know how it works (or doesn't) for you!
Upvotes: 1