Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

eloquent search/where on custom attributes

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?

like image 260
NiRR Avatar asked Jan 19 '15 07:01

NiRR


2 Answers

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;
});
like image 189
lukasgeiter Avatar answered Nov 08 '22 08:11

lukasgeiter


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();
like image 4
Uğur Arıcı Avatar answered Nov 08 '22 07:11

Uğur Arıcı