halkujabra
halkujabra

Reputation: 2942

Database relationship name & best practice for it, in my laravel app

I have a database schema in my laravel app. In that schema, there are three models - Boss, Employee & Review.

A Boss can have many employees. An Employee can have many bosses(we can consider bosses from previous jobs). An Employee can Review his/her Boss. Boss can't Review anyone, so only Employee can review.

Thus, there are these relationships -

Employee & Boss has many-to-many relationship

Employee & Review has one-to-many relationship ( one Employee can Review multiple Bosses, thus having multiple reviews from his/her side ).

As you can see there is no direct relationship between Boss & Review. But, the query is -

What are the reviews for Boss 'x'?

To answer this query in laravel, I first thought that it had 'hasManyThrough' relationship. But, 'hasManyThrough' works only when Boss & Employee have 'one-to-many' relationship. That is, when one Boss can have multiple Employee but not vice-versa.

So, my question is - Is there a relationship which is applicable in this scenario(like polymorphic etc.)? If yes, how to use it in laravel?

Upvotes: 0

Views: 906

Answers (1)

Jarek Tkaczyk
Jarek Tkaczyk

Reputation: 81187

No need for that extra table with reviews.

Here's all you need - first the tables:

bosses: id, ...
employees: id, ...
boss_employee: id, boss_id, employee_id, review (nullable), ...

Then the models:

// Boss model
public function employees()
{
  return $this->belongsToMany('Employee')->withPivot('review');
}

public function reviews()
{
  return $this->hasMany('Review');
}

// Employee model
public function bosses()
{
  return $this->belongsToMany('Boss')->withPivot('review');
}

public function reviews()
{
  return $this->hasMany('Review');
}

// Review model
protected $table = 'boss_employee';

public function boss() // or eg. reviewed
{
  return $this->belongsTo('Boss');
}

public function employee() // or eg. reviewer
{
  return $this->belongsTo('Employee');
}

Now, with this setup you can do this:

// get boss and his review
$boss = $employee->bosses->first();
$review = $boss->pivot->review;

// get review for given boss of an employee
$review = $employee->reviews()->where('boss_id', $bossId)->first();

// get bosses with reviews
$bosses = Boss::whereHas('reviews', function ($q) {
  $q->whereNotNull('review');
})->get();

// and so on and so forth

You can enhance your Review model by adding global scope so it returns only the rows from boss_employee table having not null review field. This would be pretty much the same as SoftDeletingScope, but the conditions need to be swapped - by default whereNotNull, instead of whereNull in the SoftDeletingScope.

Upvotes: 1

Related Questions