I think that the best way to go is a one to many polymorphic relationship.
Database/migrations setup
To do so you would need:
- A
members
table to hold members data.
- One table for each type of payable entity in your system (
classes
, insurance
, events
and exams
)
- A
payments
table structured with the following migration:
Schema::create('payments', function (Blueprint $table) {
$table->increments('id');
// Payment related fields like date and amount
$table->unsignedInteger('member_id');
// Assuming id is the primary key on the members table
$table->foreign('member_id')->references('id')->on('members');
// This one will create two fields:
// - payable_type
// - payable_id
$table->morphs('payable');
});
This way each record would hold the member that made the payment (through member_id
) and the paid entity (through payable_type
and payable_id
).
Eloquent Models Relationships
You then have to setup morphing relationships on your payment model like:
// app\Payment.php
class Payment extends Model
{
// ...
public function payable()
{
return $this->morphTo();
}
public function member()
{
return $this->belongsTo(Member::class);
}
}
Your member model as:
// app\Member.php
class Member extends Model
{
// ...
public function payments()
{
return $this->hasMany(Payment::class);
}
}
And for each payable entity:
// app\Insurance.php
class Insurance extends Model
{
// ...
public function payments()
{
return $this->morphMany(Payment::class, 'payable');
}
}
// app\Event.php
class Event extends Model
{
// ...
public function payments()
{
return $this->morphMany(Payment::class, 'payable');
}
}
// app\Exam.php
class Exam extends Model
{
// ...
public function payments()
{
return $this->morphMany(Payment::class, 'payable');
}
}
// app\Course.php
// I renamed "Class" payable entity to "Course"
// as "class" is a reserved keyword in PHP and
// you can't give a class the name "Class".
class Course extends Model
{
// ...
public function payments()
{
return $this->morphMany(Payment::class, 'payable');
}
}
Usage
If you would need to retrive all the payments (of different types) made by a user you would just have to query the member model like that:
$member = Member::with('payments.payable')->first();
dd($member->payments);
If you set up model relations accordingly, Laravel will resolve the different correct Eloquent model instances based on the payable_type and payable_id of each record with a matching member_id.
As a result, $member->payments
will be a collection of instances of Payment each with a relationship to one of Insurance
, Exam
, Course
and Event
classes (based on the payable_type stored in database).
For reference and a more detailed usage, you could look at the official Laravel docs here.