Skip to content

Instantly share code, notes, and snippets.

@andylolz
Created October 13, 2012 19:49
Show Gist options
  • Save andylolz/3885906 to your computer and use it in GitHub Desktop.
Save andylolz/3885906 to your computer and use it in GitHub Desktop.
Laravel question

The problem

So this isn’t my actual scenario, but I think it illustrates my problem quite well. Imagine an online school report system. I have Teachers, Students, and Reports. Teachers and Students are both Users. The relationship between Students and Reports is one-to-one (a student just has a single report card), but between Teachers and Reports is one-to-many (a teacher has a whole classroom-worth of reports.) The Report model has both a student_id and a teacher_id, both of which are foreign keys to the User table.

I’d like to represent these relationships in my models, so for a given User I can call:

User::find(5)->reports;

I expect you can already see a problem!

So the following is something like pseudocode (since I don’t think it will work!) but here’s roughly what I want to do:

class User extends Eloquent {
  
  public function reports() {
    switch($this->user_type->name) {
      case 'student':
        return $this->has_one('Report', 'student_id');
        break;
      case 'teacher':
        return $this->has_many('Report', 'teacher_id');
        break;

      return null;
    }
  }

  // Just for a bit of background, here's the separate relationship to my UserType model
  // which I'm sure is very standard!
  public function user_type() {
    return $this->belongs_to('UserType', 'user_type_id');
  }
}

I think there’s a fundamental problem with the above, but if I’m mistaken about that please let me know!

An alternative method would be to define student_report() and teacher_reports() methods, but this is a bit weird because e.g. for a teacher instance..

$teacher->student_report;

..is meaningless. Similarly:

$student->teacher_reports;

..is also meaningless. They could simply return null, which seems ok, but it is not really a very elegant solution.

The plan

Ok so the alternative method I was considering is to subclass my User model:

class User extends Eloquent {
  public function reports() {
    return null;
  }
  
  // etc..
}

class Student extends User {
  public static $table = 'users';

  public function reports() {
    // I know I said the relationship here is one-to-one..!
    // But I don't mind hacking this too much.
    return $this->has_many('Report', 'student_id');
  }
}

class Teacher extends User {
  public static $table = 'users';

  public function reports() {
    return $this->has_many('Report', 'teacher_id');
  }
}

This actually works fine! However, something like:

Teacher::all();

..will return all Users, which is clearly not a meaningful result. I want to automatically append a WHERE user_type=? to lots of the queries that Eloquent runs. I can do this by implementing Eloquent methods in my subclasses, but this seems really like overkill! So what’s the alternative? Could I add something in my Teacher and Student constructors that ensure this extra WHERE clause is appended to queries?

@victorboissiere
Copy link

That is a very good question. I am also looking for an answer :( I am getting kind of desperate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment