Reputation: 5002
I added a custom attribute to my model
public function getTouchedAttribute() { ...
I would like to add this to a query
hasMany()->where('touched', ...)
but obviously this isn't a column in the table.
what is the most elegant way to achieve this behavior?
Upvotes: 23
Views: 24548
Reputation: 1280
I know this is a 4 year old topic (from 2015) but it's still getting traffic from web searches. So I want to share an idea;
You can use Local Query Scopes of Eloquent to define custom where clauses.
As said in documentation:
Local scopes allow you to define common sets of constraints that you may easily re-use throughout your application. For example, you may need to frequently retrieve all users that are considered "popular". To define a scope, prefix an Eloquent model method with scope.
And an example: If you define a custom scope on your model:
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
You can use it directly with your model.
App\User::popular()->orderBy('created_at')->get();
So you can define a scopeTouched()
method and implement your logic.
I assume if updated_at not equal to created_at the row is touched here. Of course you can change this behaviour.
public function scopeTouched($query)
{
return $query->where('updated_at', '!=', 'created_at');
}
And use it with your model.
Model::touched()->get();
And of course you can use it with other query builder methods.
Model::touched()->paginate(20);
Model::touched()->orderBy('id', 'DESC')->take(10)->get();
Model::touched()->latest()->first();
Upvotes: 9
Reputation: 152870
One option (and probably the better one in terms of performance) would be to mimic the attribute with raw SQL functions. (Can't help you with that because I don't know what touched
does)
The other way is to use filter
on the resulting collection:
$collection = Model::all();
$filtered = $collection->filter(function($model){
return $model->touched == true;
});
Upvotes: 24