The new withAttributes method for relationships and scopes in Laravel
Scopes in Laravel are a way to encapsulate common queries that you may need to run against a model. They allow you to define a query you can use in multiple places in your application.
This minimizes the code while writing the query and is an easy way to ensure every query for a given model receives certain constraints.
Here’s an example of a local scope in Laravel for instance.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* Scope a query to only include the most starred posts.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeStarred($query)
{
return $query->where('starred', '>', 30);
}
}
// this will return all the
// posts that have more than 30 stars
$posts = Post::starred()->get();
As you can tell, the starred
scope is a local scope that returns all the posts that have more than 30 stars. The same goes for global scopes as well.
The new withAttributes
method
To make scopes more powerful, the newest release brings a new method called withAttributes
that allows you to add a where clause to the query with the given attribute constraints, and also applies the attributes to any model that are created via the relationship or scope.
This means that not only will the query be constrained by the attributes, but any models that are created via the relationship or scope will also have the attributes applied automatically.
Using it on scopes
Here’s an example of how you can use the withAttributes
method on a scope.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
/**
* Scope a query to only include the most starred posts.
*
* @param \Illuminate\Database\Eloquent\Builder $query
* @return \Illuminate\Database\Eloquent\Builder
*/
public function scopeFeatured($query)
{
return $query->withAttributes(['featured' => true]);
}
}
Here’s how you can use this for both, creating a model and querying the model.
<?php
use App\Post;
// this will create a new post with
// the `featured` attribute set to `true`
$post = Post::featured()->create([
'title' => 'My featured post'
]);
$post->featured; // true
// this will return all the posts that
// have the `featured` attribute set to `true`
$posts = Post::featured()->get();
Using it in relationships
You can also use the withAttributes
method on relationships. Here’s an example.
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
public function featuredPosts()
{
return $this->posts()->withAttributes(['featured' => true]);
}
}
Here’s how you can use it to retrieve all the featured posts for a user.
<?php
use App\User;
$user = User::find(1);
// this will return all the posts
// that have the `featured` attribute set to `true`
$posts = $user->featuredPosts()->get();
Similarly, you can also set the attributes while creating a new model via the relationship.
<?php
use App\User;
$user = User::find(1);
// this will create a new post with
// the `featured` attribute set to `true`
$post = $user->featuredPosts()->create([
'title' => 'My featured post'
]);
$post->featured; // true
In closing
I think this feature is pretty neat and it essentially combines two scenarios into one conveniently. It’s a nice addition to Laravel’s Eloquent ORM and I’m sure it will be useful in many instances.
Like this article?
Buy me a coffee👋 Hi there! I'm Amit. I write articles about all things web development. You can become a sponsor on my blog to help me continue my writing journey and get your brand in front of thousands of eyes.