(Laravel) Polymorphic relation through pivot table
Asked Answered
D

1

6

Let's say, I have an Event model, which has more participants of various models (Player, Coach, Admin) through polymorphic relation and a pivot table (EventParticipant), which also contains a boolean column participate. I want to get participants through $event->participants which retrieves a collection of players, coaches, and admins through a polymorphic relation.

I have something similar created with standard non-polymorphic relation in trainings, like this:

class Training extends Model
{
    /**
    * Training has more players.
    */
    public function players() {
        return $this->belongsToMany('App\Player', 'training_player')
            ->using('App\TrainingPlayer')
            ->withPivot('participate');
    }
}

class TrainingPlayer extends Pivot
{
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'participate' => 'boolean'
    ];
}

How could this be modified in the case of events, where participants() can be either Player, Coach, or Admin model? (Maybe something with MorphPivot class but I can't imagine how.)

(Instead of player_id (in TrainingPlayer class) which refers to id of the Player model, there are two columns role and rollable_id (in EventParticipant class) which refers to id of the Player, Coach, or Admin model, respectively)

class Event extends Model
{
    /**
    * Event has more participants (players, coaches, or admins).
    */
    public function participants() {
        //
    }
}

class EventParticipant extends MorphPivot
{
    //
}

Any help would be appreciate. :) Thx

Discommodity answered 30/9, 2018 at 16:8 Comment(4)
Do you mean laravel.com/docs/…?Hyetal
Yes, but in particular I mean paragraphs under "Defining Custom Intermediate Table Models" heading which say something about using Illuminate\Database\Eloquent\Relations\MorphPivot class but I don't know how exactly implement that in my situation because the documentation also is very insufficient here.Discommodity
It's not possible to get all the different models (Player, Coach, Admin) with a single relationship. You need one MorphedByMany relationship per model.Hyetal
Ohh, good to know @JonasStaudenmeir. I am trying to find a solution few hours but I ended up with 3 belongsToMany() relationships (players, coaches, admins) with wherePivot('role', ...) condition... and the method participants() which merges all the aforementioned collections but obviously participants() returns a collection not a query builder, so I can't specify a query like this: $event->participants()->with('user_account')->get(), so a workaround is needed...Discommodity
H
7

I have been looking for something similar and came up with a solution. As per Jonas comment, you can't have different Models in 1 related set but you can have 1 for each model using 1 pivot table.

You can now query this with \App\Team::find(1)->with(['managers', 'users'])->get();

Schema::create('associations', function (Blueprint $table) {
    $table->id();
    $table->string('association_type');
    $table->integer('association_id');
    $table->integer('team_id');
    $table->integer('meta')->nullable();
    $table->timestamps();
});

Schema::create('managers', function (Blueprint $table) {
    $table->id();
    $table->timestamps();
});

Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->timestamps();
});

Schema::create('teams', function (Blueprint $table) {
    $table->id();
    $table->timestamps();
});
class Manager extends Model
{
    public function teams()
    {
        return $this->belongsToMany('\App\Team', 'associations')->using('App\Association');
    }
}

class Team extends Model
{
    public function managers()
    {
        return $this->morphedByMany('App\Manager', 'association')->using('App\Association');
    }

    public function users()
    {
        return $this->morphedByMany('App\User', 'association')->using('App\Association');
    }
}

class User extends Authenticatable
{
    public function teams()
    {
        return $this->belongsToMany('\App\Team', 'associations')->using('App\Association');
    }
}

// App/Association
use Illuminate\Database\Eloquent\Relations\MorphPivot;

class Association extends MorphPivot
{
    protected $table = 'associations';  // not sure if this is needed
}
Houseman answered 10/8, 2020 at 11:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.