Bill Garrison Bill Garrison - 7 months ago 48
PHP Question

Laravel 5.2 - modify a model's builder

So, I am using Laravel's built in soft Deletes and I have run into an issue. When I call

withTrashed()
it returns a query builder object. This would be fine for most cases but after I call this I then want to call a method like
filter($this->filters)
which is specific to the MODEL and I no longer have access to now that I only have a query builder.

The reverse relationship also does not work as
withTrashed()
also wants a model where any kind of parsing method I can think of would return the model's query builder.

So I was hoping to find a way to modify a model object with where clauses so I can add my filters and send the model to
withTrashed()
WITH the filters in place. I am honestly not sure how to do this. Worst case scenario I can have the filter method return the query builder without any global scopes and add the
withTrashed()
query on to the end manually.

So the end result would be something like this:

$model->filter($this->filters)->withTrashed();


Im not trying to get a giant collection and whittle it down. Even with chunking when you have a few million rows it can get slow really quick, especially when you bring in filtering. Technically, for a one off, I could just add multiple
->where()
clauses to the query builder before i call
->get()
but that would mean doing custom filtering in every controller's index. So i am looking to abstract it as a method in the model that parses filters sent in and adds them to the model (this is the part im not sure on. Kind of like: github.com/marcelgwerder/laravel-api-handler

Any ideas?

Answer

I believe you're looking for query scopes. You can create a new query scope on your model, and then it can be used like any other query builder method.

For example, to create a filter() scope:

class MyModel extends Model {
    public function scopeFilter($query, $filters) {
        // modify $query with your filters

        return $query;
    }
}

With that query scope defined, you call it like any other query builder method:

$data = \App\MyModel::withTrashed()->filter(/* your filters */)->get();

You can read more about query scopes here.