Consider the following scenario:
There are couple of entities in my Laravel application like the following:
Post
Page
Image
Video
All the above entities can have CustomFieldValue
s, which is another entity. The structure of the custom_field_values
table is as follows:
- ID
- entity_id
- custom_field_definition_id
- value
- [Timestamp fields]
All the CustomFieldValue
s belong to a single CustomFieldDefinition
entity. Its table custom_field_definitions
looks like following:
- ID
- parent_entity_name
- definition_name
- [Timestamp fields]
Following are some sample data from the custom_field_definitions
table:
| ID | parent_entity_name | definition_name |
|----|--------------------|-------------------|
| 1 | Post | AuthorTwitterUrl |
| 2 | Page | SeoTitle |
| 3 | Image | OriginalSourceUrl |
| 4 | Video | MpaaRating |
As you can see, CustomFieldDefinition
s are definitions of extra data, that we can store about each type of entity.
Following are some sampel data from the custom_field_values
table:
| ID | entity_id | custom_field_definition_id | value |
|----|-----------|----------------------------|-----------------------------------|
| 1 | 1 | 1 | https://twitter.com/StackOverflow |
| 2 | 1 | 2 | My Page's SEO Title |
| 3 | 1 | 3 | http://example.com/image.jpg |
| 4 | 1 | 4 | G – General Audiences |
A little description about the data contained in the custom_field_values
table:
CustomFieldValue:1
: The value forCustomFieldDefinition:1
and its entity 1 (Post:1
, in this case, becauseCustomFieldDefinition:1
is related toPost
.) is “https://twitter.com/StackOverflow“.CustomFieldValue:2
: The value forCustomFieldDefinition:2
and its entity 1 (Page:1
, in this case, becauseCustomFieldDefinition:2
is related toPage
.) is “My Page’s SEO Title”.CustomFieldValue:3
: The value forCustomFieldDefinition:3
and its entity 1 (Image:1
, in this case, becauseCustomFieldDefinition:3
is related toImage
.) is “http://example.com/image.jpg“.CustomFieldValue:4
: The value forCustomFieldDefinition:4
and its entity 1 (Video:1
, in this case, becauseCustomFieldDefinition:4
is related toVideo
.) is “G – General Audiences”.
custom_field_values
table’s entity_id
can refer to any entity class, therefore it is not a foreign key in the DB level. Only in combination with custom_field_definition_id
we can find to which entity it actually refers to.
Now, all is well and good, until I need to add a relationship called customFieldDefinitions
to any of the entities (Say Post
.).
class Post extends Model {
public function customFieldDefinitions(){
$this -> hasMany ('CustomFieldDefinition');
}
}
The above does not work, because the datapoint that indicates the CustomFieldDefinition
‘s relationship is not a foreign key field in the custom_field_definitions
table, named post_id
. We have to somehow build the relationship based on the fact that some records in the custom_field_definitions
table has “Post” as the value of the field parent_entity_name
.
CustomFieldDefinition::where('parent_entity_name', '=', 'Post');
The above snippet fetches the CustomFieldDefinition
s that are related to the Post
, however, it is not possible to do something like the following with the relationship:
class Post extends Model {
public function customFieldDefinitions(){
$this
-> hasMany ('CustomFieldDefinition')
-> where ('parent_entity_name', '=', 'Post')
;
}
}
The where
constraint works. But Laravel also injects the ID of the current Post
object into the set of constraints.
So, what I want to do is, not consider the current object’s ID at all, and build a “Class Leavel Relationship”, and not an “Object Level Relationship”.
Is this possible under Laravel?
2
Answers
Instead of
hasMany()
, you can createOne To Many (Polymorphic)
relationship betweenPost
,Page
,Image
,Video
andCustomFieldDefinition
.More about polymorphic relationships here.
There might be a workaround but I’m not pretty sure about it.
What you could try doing is to define a mutated attribute and set it as the local key of the relationship:
You could also go further and define a trait which could be used by all your models which have
customFieldDefinitions
. It could look like:Then you can use it wherever needed: