Search code examples
sqllaraveleloquentmodels

Laravel | Polymorphic Relationship unknown column


This is my first time using a polymorphic relationship.

I am creating a LMS where a Assignment can be allocated to a individual user or a team so reading the Laravel docs it seems that the Polymorphic Relationship will be a good way to go about it.

I have created 4 tables.

Users: | id | username | password | created_at | updated_at |

Teams: | id | friendly_name | slug |

Team User: | id | user_id | team_id |

Assignment Allocation:

| id | assignment_id | assignmentable_type | assignmentable_id | created_at | updated_at

So when the assignment_allocations has data in it looks like this...

| id | assignment_id | assignmentable_type | assignmentable_id | | 1 | 1 | App\Models\User | 1 |

However I get this error:

SQL: select * from users where users.assignmentable_id = 1 and users.assignmentable_id is not null and users.assignmentable_type = App\Models\User

SO obviously I have done something wrong, however I cannot for the life of me figure out what I've done wrong.

This is my functions that relate to this:

AssignmentAllocation.php

public function assignmentable()
{
    return $this->morphTo();
}

User.php

public function assignments()
{
    return $this->morphMany('App\Models\User', 'assignmentable');
}

Team.php

public function assignments()
{
    return $this->morphMany('App\Model\Team', 'assignmentable');
}

Any help is greatly appreciated.


Solution

  • There are 2 potential answers depending on your data structure, which isn't clear from your question.

    1. User/Team to Assignment is a one-to-many relationship (each Assignment has one User/Team, and each User/Team has many Assignments

    2. Many-to-many relationship where each User/Team has many Assignments and each Assignment has many Users/Teams


    One to many

    In a one-to-many you wouldn't need an Assignment table and an AssignmentAllocation table, so I am assuming your AssignmentAllocation is your Assignment model. If not then you need to put the assignmentable_type and assignmentable_id columns on the assignments table instead, and use Assignment.php instead of AssignmentAllocation.php.

    AssignmentAllocation.php

    public function assignmentable()
    {
        return $this->morphTo();
    }
    

    User.php

    public function assignments()
    {
        return $this->morphMany('App\Models\AssignmentAllocation', 'assignmentable');
    }
    

    Team.php

    public function assignments()
    {
        return $this->morphMany('App\Models\AssignmentAllocation', 'assignmentable');
    }
    

    Your error is because Laravel is searching the users table for the match (you have morphMany('User'..), when it should be searching the AssignmentAllocation table. So just switch them out.

    1) The morphMany acts like a hasMany, so you're saying:

    Each User hasMany Assignments, and each Team hasMany Assignments. The first part of the morphMany says "search the AssignmentAllocation table", and the second part says "search for assignmentable_id and assignmentable_type being equal to this instance of this model".

    2) morphTo acts like belongsTo so you're saying:

    Each Assignment belongsTo an assignmentable.


    Many to many

    However if AssignmentAllocation is a many-to-many pivot table and each Assignment has many Users or Teams, and each User/Team has many Assignments, then you need a morphToMany/morphedByMany pair.

    User.php

    public function assignments()
    {
        return $this->morphToMany('App\Models\Assignment', 'assignmentable');
    }
    

    Team.php

    public function assignments()
    {
        return $this->morphToMany('App\Models\Assignment', 'assignmentable');
    }
    

    Assignment.php model NOTE: not the AssignmentAllocation model

    public function users()
    {
        return $this->morphedByMany('App\Models\User', 'assignmentable');
    }
    
    public function teams()
    {
        return $this->morphedByMany('App\Models\Team', 'assignmentable');
    }
    

    You should rename the assignment_allocation table to assignmentables, or add the required third and fourth arguments to the morph functions. I prefer to keep the table names consistent.