Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel-Many-to-one Polymorphic relationship

I am using laravel 5.1. The scenario is as follows(this is an example. The real scenario is similar to this example)

I have 3 models

  1. College
  2. Student
  3. Teacher

A college can have many students but a student can belong to only 1 college.

A college can have many teachers but a teacher can belong to only 1 college.

I want to establish relationships between these tables in laravel. One of the methods for this is to place a college_id foreign key on the Students and Teachers table. But in my case, this foreign key will be null a lot of times. So rather than have separate columns in 3-4 tables with mostly null values, I wanted to explore the option of having a polymorphic relationship for College table.

This is what I tried: The example given in the laravel docs(link below) depict a one-to-many relationship whereas my scenario is more of a many to one relationship.

http://laravel.com/docs/5.1/eloquent-relationships#polymorphic-relations

As given in the example, having collegeable_id and collegeable_type columns on the College table would not have fulfilled my requirement as a college can contain many students/teachers so I created a pivot table:

Schema::create('collegeables', function (Blueprint $table) {
        $table->integer('college_id')->unsigned();
        $table->integer('collegeable_id')->unsigned();
        $table->string('collegeable_type');
    });

And I have the following models

College Model:

    namespace App;

use Illuminate\Database\Eloquent\Model;

class College extends Model
{
    public function students()
    {
        return $this->morphedByMany('App\Student', 'collegeable');
    }
}

Student Model:

    namespace App;

use Illuminate\Database\Eloquent\Model;

class Student extends Model
{
    public function college()
    {
        return $this->morphOne('App\Colleges', 'collegeable');
    }
}

With this arrangement, I am able to store students using College model instance like this

$college = \App\College::find(1);
$student = new \App\Student;
$student->name = 'John Doe';
$college->students()->save($student);

But when I try to retrieve a College model instance using a student model instance as specified below, it gives me an error:-

public function index()
    {
        return \App\Student::find(1)->college;
    }

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'colleges.collegeable_id'

This is kind of expected as morphOne works with columns in a table I suppose. If I change the morphOne function in Student Model to morphToMany, the code starts working and I am able to retrieve values as well. But that make this relationship a many to many which again is not what I want.

So my question is this:- Is their a morphSomething function I can use in the student model to be able to retrieve values for the student's college while maintaining the relationship as a one-to-many?

Any help would be really appreciated. Thanks.

like image 773
Saurabh Misra Avatar asked Jan 08 '23 07:01

Saurabh Misra


1 Answers

There's no reason to use Polymorphic relationships here. Instead, just add a foreign key to your colleges table on both your students and teachers tables. Like this:

colleges
    id
    name

teachers
    id
    name
    college_id

students
    id
    name
    college_id

Then your models can use the belongsTo() and hasMany() relations, like so:

class College extends Model {
    public function students() {
        return $this->hasMany(App\Student::class);
    }

    public function teachers() {
        return $this->hasMany(App\Teacher::class);
    }
}

class Teacher extends Model {
    public function colleges() {
        return $this->belongsTo(App\College::class);
    }
}

class Student extends Model {
    public function colleges() {
        return $this->belongsTo(App\College::class);
    }
}

Polymorphic one-to-many relations are for the opposite of this relationship where you have a model that can only be related to a single record, but that record can be many different models.

Edit: To further explain why a polymorphic relationship isn't needed here, let's take a look at where it would be needed. Say you have a simple CRM style website. There are Customers and Projects and you want to have Comments on both. In this case, you would make Comments a polymorphic relationship because Comments belong to a single Customer or a single Project, but not both.

Your relationship is the exact opposite. In your case, Students and Teachers belong to a college. If you were to follow the previous example's pattern, a college would have belonged to a single student or teacher.

like image 120
Josh Avatar answered Jan 12 '23 13:01

Josh