Skip to content
Advertisement

How do I create a eloquent Polymorphic relation

I have a two eloquent models model User and Retailer. I want to create a new model “Task” where there there should be a field “added_by” which can denote either a user or a retailer.

How can I create the migration for Task so that there is a field that can denote either user or retailer?

Schema::create('tasks', function (Blueprint $table) {
   $table->id();
   $table->unsignedBigInteger('product_id');
   $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
   $table->morphes('added_by');
   $table->timestamps();
});

How can I create a Task which references a user for example?

Task::create([
'product_id' => 1,
'added_by' => ????
]);

Also when I get a eloquent instance of task how can i know if the added_by is referencing to a user or a retailer?

Advertisement

Answer

The syntax for the migration is $table->morphs(...), not $table->morphes(...).

$table->morphs('added_by') will create the columns added_by_id and added_by_type


Option 1: 1-M Polymorphic Relationships

You need to define some relationships in the User, Retailer and Task models

User

class User extends Authenticable
{
    public function tasks()
    {
        return $this->morphMany(Task::class, 'added_by');
    }
}

Retailer

class Retailer extends Model
{
    public function tasks()
    {
        return $this->morphMany(Task::class, 'added_by');
    }
}

Task

class Task extends Model
{
    protected $fillable = ['product_id'];
    
    public function added_by()
    {
        return $this->morphTo();
    }
}

Eloquent Relationships – One to Many Polymorphic Relations


To add a Task for an User or a Retailer, you use the relationship method.

$user->tasks()->create(['product_id' => $productId]);

$retailer->tasks()->create(['product_id' => $productId]);

Eloquent Relationships – Inserting and Updating Related Models


Option 2: M-N Polymorphic Relationships

The other option is to use a Many to Many Polymorphic Relationship between Product and both User and Retailer

You need to define some relationships in the User, Retailer and Product nodels

User

class User extends Authenticable
{
    // Optional
    public function tasks()
    {
        return $this->morphMany(Task::class, 'added_by');
    }

    public function products()
    {
        return $this->morphToMany(Product::class, 'added_by', 'tasks')
                    ->using(Task::class)
                    ->withTimestamps();
    }
}

Retailer

class Retailer extends Model
{
    // Optional
    public function tasks()
    {
        return $this->morphMany(Task::class, 'added_by');
    }

    public function products()
    {
        return $this->morphToMany(Product::class, 'added_by', 'tasks')
                    ->using(Task::class)
                    ->withTimestamps();
    }
}

Product

class Product extends Model
{
    // Optional
    public function tasks()
    {
        return $this->hasMany(Task::class, 'product_id');
    }

    public function users()
    {
        return $this->morphedByMany(User::class, 'added_by', 'tasks')
                    ->using(Task::class)
                    ->withTimestamps();
    }
}

Task

use IlluminateDatabaseEloquentRelationsMorphPivot;

class Task extends MorphPivot
{
    public $incrementing = true;

    // Optional
    public function added_by()
    {
        return $this->morphTo();
    }

    // Optional
    public function product()
    {
        return $this->belongsTo(Product::class, 'product_id');
    }
}

Eloquent Relationships – Many to Many Polymorphic Relation


To associate an User or Retailer with a Product (using Task as a morph pivot)

$user->products()->attach($productId);

$retailer->products()->attach($productId);

Eloquent Relationships – Updating Many to Many Relationships

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement