Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Doctrine ORM on EAV Tables

I was planning on creating my application and use an ORM for the models, but the thing is, there's a part of the database which uses Entity-Attribute-Value Tables.

I pretty liked Doctrine ORM but I don't know if it is possible to maybe create classes that would look like any ordinary doctrine entity, when the table actually hooked up to is of EAV style.

Would it be possible to use Doctrine on this, and if so, how?

like image 960
Jronny Avatar asked Jan 02 '13 14:01

Jronny


2 Answers

definitely possible:

Have relationships like this: Object (one to many) -> AttributeValue -> Many to One -> AttributeType

like image 172
Mike Graf Avatar answered Sep 24 '22 23:09

Mike Graf


In view of EAV it seems to be obvious how to build a relation between entity and attribute using doctrine. In the most complicated case we deal with a Many to Many relation.

So lets say we want to map an attribute Name to an entity User. Assuming a user has exactly one name and each name belongs to exactly one user this link can be archived using One to One relation

But how to model the relation between attribute and value? The problem is that values can be of different types or even need different numbers of fields in order to save their information.

Consider the attributes name and phone_number. While a name might be represented by a string, an integer could be needed for the phone number. Or it is even necessary to not only the number but also the area code in a separate filed.

Because EAV requires very flexible value representation, it is not possible to store all of them within the same field in a database table (disregard blobs, data serialization an the like). Therefore most EAV implementations using different tables representing different value types.

In order to reach such flexibility, doctrine features Inheritance Mapping. It basically allows you to extend doctrine entities. Doing so you specify a discriminator for each sub-type of your entity:

/**
  * @Entity
  * @InheritanceType("JOINED")
  * @DiscriminatorColumn(name="value_type", type="string")
  * @DiscriminatorMap({"name" = "Name", "phone" = "PhoneNumber"})
*/
class Value
{
// ...
}

/** @Entity */
class Name extends Value
{
// ...
}

/** @Entity */
class PhoneNumber extends Value
{
// ...
}

The Value class provides common implementation for all values, i.e. an id. Each subclass (i.e. Name and PhoneNumber) extend those common values by their specific ones, for example additional fields.

  • The @DiscriminatorColumn defines a column in the parent relation which stores the type of the value.
  • The @DiscriminatorMap is used by doctrine to map the type from the @DiscriminatorColumn to one of those classes.

The relation between attribute and value can be specified to the parent class. Calling values from the attribute then will fetch all types of values which can be filtered (and dealt with) during runtime using for example instanceof.

like image 26
magic_al Avatar answered Sep 23 '22 23:09

magic_al