Using Scoped Relationships in Laravel Eloquent
When working with Laravel Eloquent, you’ll often need to filter or extend your relationships to suit your app’s needs. Scoped relationships let you add custom constraints to your relationships, making your models more expressive and your queries more reusable.
Let’s walk through some concrete examples to help you understand and use scoped relationships in your own projects!
What is a Scoped Relationship?
A scoped relationship is simply a relationship method on your model that applies extra query constraints. For example, you might want to easily fetch only the “featured” posts for a user, not just all posts.
Example: User and Posts
Let’s say you have a User
model and a Post
model. A user can have many posts:
// app/Models/User.php
public function posts(): HasMany
{
return $this->hasMany(Post::class)->latest();
}
Now, let’s say you want a quick way to get just the featured posts for a user. You can add a new relationship method that scopes the query:
public function featuredPosts(): HasMany
{
return $this->posts()->where('featured', true);
}
Now you can do:
$featuredPosts = $user->featuredPosts;
Creating Models via Scoped Relationships
But what if you want to create a new featured post using this relationship? By default, the featured
attribute won’t be set automatically:
$post = $user->featuredPosts()->create(['title' => 'My Post']);
// $post->featured is NOT true
withAttributes
Introducing Laravel has a withAttributes
function which lets you specify default attributes for models created via the relationship:
public function featuredPosts(): HasMany
{
return $this->posts()->withAttributes(['featured' => true]);
}
Now, when you create a post via this relationship:
$post = $user->featuredPosts()->create(['title' => 'Featured Post']);
// $post->featured is TRUE!
Customizing Query vs. Creation
By default, withAttributes
also adds a where
clause to the query. If you only want the default attribute on creation, not as a query constraint, pass asConditions: false
:
public function featuredPosts(): HasMany
{
return $this->posts()->withAttributes(['featured' => true], asConditions: false);
}
When Should You Use Scoped Relationships?
- When you want to DRY up your code and avoid repeating common query constraints.
- When you want to make your model API more expressive (e.g.,
$user->publishedPosts
,$user->archivedPosts
). - When you want to provide sensible defaults for related model creation.
Real-World Use Case
Suppose you’re building a blog platform. You want to let users quickly fetch or create “draft” or “published” posts:
public function draftPosts(): HasMany
{
return $this->posts()->withAttributes(['status' => 'draft']);
}
public function publishedPosts(): HasMany
{
return $this->posts()->withAttributes(['status' => 'published']);
}
Now you can easily fetch or create posts in either state:
$draft = $user->draftPosts()->create(['title' => 'My Draft']);
$published = $user->publishedPosts()->create(['title' => 'My Article']);
Conclusion
Scoped relationships are a powerful way to make your Eloquent models more expressive and your code more maintainable. Try adding them to your own models to simplify your queries and model creation!