5

Like we can eager load a relationship of an Eloquent model, is there any way to eager load a method which is not a relationship method of the Eloquent model?

For example, I have an Eloquent model GradeReport and it has the following method:

public function totalScore()
{
    return $scores = DB::table('grade_report_scores')->where('grade_report_id', $this->id)->sum('score');
}

Now I am getting a collection of GradeReport Eloquent models.

$gradeReports = GradeReport::where('student_id', $studentId)->get();

How can I eager load the returning values of totalScore method for all GradeReport Eloquent models in the collection?

jedrzej.kurylo
  • 39,591
  • 9
  • 98
  • 107
Debiprasad
  • 5,895
  • 16
  • 67
  • 95

2 Answers2

9

You can add arbitrary properties to your models by adding them to $appends array and providing a getter. In your case the following should do the trick:

class GradeReport extends Model {
  protected $appends = ['totalScore'];

  public function getTotalScoreAttribute() {
    return $scores = DB::table('grade_report_scores')->where('grade_report_id', $this->id)->sum('score');
  }
}

Now all GradeReport objects returned from your controllers will have totalScore attribute set.

jedrzej.kurylo
  • 39,591
  • 9
  • 98
  • 107
  • 6
    it might solve the problem, but it is not eager loading, every time this model attribute is accessed, an call to DB is made – animaacija Sep 04 '16 at 13:58
  • 1
    This works as I have intended. However, I would like to have a small change for the attribute to look better. `protected $appends = ['total_score'];`. – Debiprasad Sep 04 '16 at 14:00
  • @animaacija It might not be eager loaded, but it works as I needed. I guess it's not possible to eager load in this case. – Debiprasad Sep 04 '16 at 14:04
3

The table grade_report_scores would also have an eloquent model xyz on which you define a relationship, query scopes, functions, etc.

Add relationship into GradeReport model:

public function scores()
{
    return $this->hasMany('xyz', 'grade_report_id', 'id');
}

Now you can rewrite your totalScore function into this:

public function totalScores()
{
    return $this->with(['scores' => function ($query) {
        $query->sum('score');
    }])->get();
}

not tested, note the closure, there bight be a need to call $query->select('id', 'srore', 'other used values');

animaacija
  • 170
  • 9
  • 25