From Laravel's docs, the model polymorphism is defined as follows:
Polymorphic relations allow a model to belong to more than one other model on a single association
Sounds like it's designed to work with belongsTo
instead of hasMany
side. Here's a scenario that I want to achieve:
In my system, there are many project types, each projec type will have its own invoice field layout. Let's say we have a Project
model that has a type
field, whose value could be contract
or part-time
. We have another two tables called ContractInvoice
and PartTimeInvoice
to define their respective field layout, both of these invoice tables have a project_id
referencing a project record. What I want to do is I want a universal interface to retrieve all invoices given a project, something like $project->invoices
.
Current solution
I can't figure out how to achieve this via polymorphism. So what I am currently doing is kind silly, using a switch
statement in my invoice()
method on Project
model class:
switch ($this->type) {
case 'contract':
$model = 'App\ContractInvoice';
break;
case 'part-time':
$model = 'App\PartTimeInvoice';
break;
}
return $this->hasMany($model);
I feel like there must be a better way to do this. Can someone please shed some light?
I don't see how a polymorphic relationship would be beneficial in this case. If you had different project type models and a single invoices table, then the invoices could morphTo the projects. But as you've described it, the switch statement sounds like it is adequate. You could achieve the same means using when
conditionals like:
public function invoices()
{
return $this->when($this->type === 'contract', function () {
return $this->hasMany(ContractInvoice::class);
})->when($this->type === 'part-time', function () {
return $this->hasMany(PartTimeInvoice::class);
});
}
The type
attribute on the Project
model and the separate invoice tables are defining a rigid relationship between them, which goes against the idea of polymorphism. Think likes
for comments
and posts
.