Using Query Builder Constraints on Eloquent Relationships

Since all Eloquent relationships also serve as query builders, constraints can be chained onto relationship calls. Imagine you have a course page that displays only the published course lessons. In your controller, you would query the lessons adding a query constraint for only published lessons.

public function show()
{
    $course = Course::find(1);

    return view('courses.show', [
        'course' => $course->lessons()->where('is_published', true)->get(),
    ]);
}

In the spirit of keeping controllers lean, we can clean up the above code by using a local query scope. In the Lesson model, add a method named scopePublished.

// Lesson Model

public function scopePublished($query)
{
    return $query->where('is_published', true);
}

Then go to the Course model and add a new method named publishedLessons.

// Course Model

public function lessons(): HasMany
{
    return $this->hasMany(Lesson::class);
}

public function publishedLessons(): HasMany
{
    return $this->lessons()->published();
}

Return to the controller and use the new publishedLessons method.

public function show()
{
    $course = Course::find(1);

    return view('courses.show', [
        'course' => $course->publishedLessons()->get(),
    ]);
}