jbeduya's avatar

Reference could point to multiple models

I would like to know your thoughts on this:

transactions:
- id
- source_id
- source_type

source1:
- id

source2:
- id

source3:
- id

I'm having a hard time how to wrap my head around in setting up the relationship for the transactions table that it could point to any of the model sources.

Any thoughts?

0 likes
5 replies
LaryAI's avatar
LaryAI
AI
Best Answer
Level 58

It looks like you're trying to implement a polymorphic relationship in your database schema. In Laravel, this is a common pattern and is supported out of the box. Here's how you can set it up:

First, you need to define the polymorphic relationship in your Transaction model. This will allow the Transaction model to be associated with more than one type of model (source).

class Transaction extends Model
{
    /**
     * Get the owning source model.
     */
    public function source()
    {
        return $this->morphTo();
    }
}

Next, for each source model, you need to define the inverse of the polymorphic relationship. This will allow you to access the transactions from the source model.

class Source1 extends Model
{
    /**
     * Get all of the source1's transactions.
     */
    public function transactions()
    {
        return $this->morphMany(Transaction::class, 'source');
    }
}

class Source2 extends Model
{
    /**
     * Get all of the source2's transactions.
     */
    public function transactions()
    {
        return $this->morphMany(Transaction::class, 'source');
    }
}

class Source3 extends Model
{
    /**
     * Get all of the source3's transactions.
     */
    public function transactions()
    {
        return $this->morphMany(Transaction::class, 'source');
    }
}

In your transactions table migration, you should have the source_id and source_type columns to store the ID and the type of the related model, respectively.

Schema::create('transactions', function (Blueprint $table) {
    $table->id();
    $table->unsignedBigInteger('source_id');
    $table->string('source_type');
    // Other transaction columns...
    $table->timestamps();
});

Now, when you want to create a transaction for a source, you can do it like this:

$source1 = Source1::find(1);
$transaction = new Transaction(/* ... */);
$source1->transactions()->save($transaction);

And when you want to retrieve the source from a transaction, you can simply do:

$transaction = Transaction::find(1);
$source = $transaction->source; // This will return the related Source1, Source2, or Source3 instance

This setup allows your transactions table to be related to multiple models through a single relationship.

1 like
gych's avatar

Why use a Model per source and not one model for multiple sources?

Store the source_type and source_id in the sources table. Only store the source_id in the transcations table.

Then in the Transcation model use this belongsTo relation

    public function source()
    {
        return $this->belongsTo(Source::class);
    }

And in the Source model use this hasMany relation

    public function transactions()
    {
        return $this->hasMany(Transaction::class);
    }
1 like
jbeduya's avatar

@gych I would also look into this approach. Thank you!

1 like
Snapey's avatar

@jbeduya Polymorphic relationship could be a better approach if the data persistence needs are different between sources (ie, the tables have different column requirements)

2 likes

Please or to participate in this conversation.