Laravel-Many-to-one Polymorphic relationship - php

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
College
Student
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.

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.

I had a similar need and managed to improvise in another way, taking advantage of morph's table structure.
You will need a Collegeable class to be Pivot (https://laravel.com/docs/9.x/eloquent-relationships#defining-custom-intermediate-table-models)
And then the magic:
public function college(){
return $this->hasOneThrough(Colleges::class,
Collegeable::class,
'collegeable_id',
'id',
'id',
'college_id',
);
}
And on the Collegeable Pivot class:
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\Pivot;
class Collegeable extends Pivot
{
protected $table = 'collegeables';
}

Related

Laravel Schema design many to many

hello i'm trying to build school management system on secondary education and i have a ERM design i would Like to ask does laravel handle this type of relationship Many to many? please amend if i'm doing it wrongly since i'm a beginner thanks..
ERM
With 2 db tables many to many reationship
students(id,name,created_at,updated_at)
subjects(id, name, created_at,updated_at)
student_subjects(id, student_id, subject_id)
Models
class Student extends Model{
public function subjects(){
return $this->belongsToMany(Subject::class, 'student_subjects'); //here student_subjects is as a pivot table
}
}
class Subject extends Model{
public function stdents(){
return $this->belongsToMany(Student::class, 'student_subjects'); //here student_subjects is as a pivot table
}
}
Now Save data
$student = Student::find(1);
$student->subjects()->attach(2); // it will save subject 2 for student 1 in `student_subjects` table.
Note: similarly you can create relation for other models
For details check https://laravel.com/docs/5.6/eloquent-relationships#many-to-many

Laravel Double n:m relation

I have a problem creating a "Double" n:m relation in Laravel.
First I have two tables called locations and services. These tables have a n:m relation and a table called location_service. The table has an incremental id and an id of each table.
In the Models I have the following Code:
class Service extends Model
{
public function locations(){
return $this->belongsToMany('app\Location','location_service','service_id','location_id');
}
}
class Location extends Model
{
public function services(){
return $this->belongsToMany('app\Service','location_service','location_id','service_id');
}
}
In addition, I created a table called tags. This table tag can be linked to several location_service and several location_service can be linked to different tags. I created a table called location_service_tag with an incremental id, the id of the location_service and the id of the tag. But how should I do the model? The point is, that there is no Model like app\Location_Service.

Laravel: Which relationship to use?

I have the following scenario:
I'm building a site where Artists show their favorite spots in a city.
So:
There are some Cities and some Artists. A City hasMany Spots.
Artists and Spots also are related together via belongsToMany, because one Spot could have been featured by multiple Artists.
I now want to define a relation in City that gives me all the artists that have something featured in that City (so basically look for artists that are related to a spot from that City)
Is there a relationship type that I can use?
I've tried hasManyThrough but that's looking up spot_id in Artist which is obviously not existent because Artist<>Spot is many to many.
when you have relationship many to many you need to do normalisation for both table, create new table to store spot_id and artist_id. I think in laravel already handle that. This link might be helpful
https://laravel.com/docs/5.5/eloquent-relationships#many-to-many
https://www.captechconsulting.com/blogs/resolve-your-many-to-manys-for-accurate-requirements
Though it's many to many relationship so you have to use belongsToMany
Ex:
In city Model :
class City extends Model{
public function artists(){
return $this->belongsToMany('App\Artist')
}
}
In Artist Model :
class Artist extends Model{
public function city(){
return $this->belongsToMany('App\City')
}
}

How do I access one model from another which don't have direct relationship?

I have an User model. Each user has certain grades and each grade has certain students.
User and Grade models have one-to-many relationship. Grade and Student models have one-to-many relationship too. But, User and Student models don't have any relationship.
Once User is logged in, he should be able to search all students that belongs to the user.
Do I have to create relationship between these two models to?
If I understand the question correctly, a user has multiple students, so what I'd do is create a one-to-many relationship between them like this:
//User.php
public function students()
{
return $this->hasMany(Student::class);
}
//Student.php
public function user()
{
return $this->belongsToOne(User::class);
}
This would allow you to pick up a users students by doing: $students = $user->students Note: I didn't use () here. If you were to execute $students = $user->students() you'd end up with a query builder object.

translating database relationships to Eloquent relationships

So, I've been trying to watch and read eloquent relationships from laracasts. Unfortunately I still don't quite get how to translate database relationships to eloquent relationships (hasOne, belongsTo, hasMany, etc).
Let's say I have an Account and Customer tables. Account table has a "Customer_id" foreign key which references to the "id" on Customer table. Let's assume it's a one-to-many relationship. How should I put it on my models on laravel?
Which table should contain the "hasMany" and which one should have the "belongsTo"?
Just think about how you would say it. In your case it sounds like a Customer has many Accounts and an Account belongs to one Customer.
So you would put the hasMany() in your Customer model and the belongsTo() in your Account model.
class Customer extends Model {
public function accounts() {
return $this->hasMany('App\Account');
}
}
class Account extends Model {
public function customer() {
return $this->belongsTo('App\Customer');
}
}
You can read more about Laravel database relationships here.

Categories