I created a helper class for searching and filtering my laravel models (method uses tntsearch and a custom scope), currently it works all right but I want to make some improvements to it, sadly it's proving difficult to achieve what I want:
What I want to improve:
1) Being able to call search method statically on all my laravel models, like this:
Model::search();
Currently I have to instantiate the class and call the method like:
 $results = $searchHelper->search($request, $filters);
2)Right now I also have to pass two arguments to constructor, in my class I try dependency injection in construct magic method but I still have to pass request and filters as arguments...
How it looks in my controller:
public function search(Request $request, QueryFilters $filters)
    {
        $search = new Search($request, $filters);
        $posts = $search->search('Post', ['postcategory', 'author', 'favorites']);
        return response()->json([
            'message' => 'Encontramos unas coincidencias',
            'posts' => $posts,
        ], 200);   
    }
My helper class:
<?php
namespace App\Helpers;
use Illuminate\Http\Request;
use App\Filters\QueryFilters;
use App\Filters\Filterable;
class Search
{
    public $request;
    public $filters;
    public function __construct(Request $request, QueryFilters $filters)
    {
        $this->request = $request;
        $this->filters = $filters;
    }
    public function search( $model, $relationships = [] )
    {
        $model = app("App\Models\".$model."); 
        $results = $model::search($this->request->input('search'), '')->get(); 
        if(!$results->isEmpty())
        {
            $ids = implode(',', $results->pluck('id')->toArray());
            $filters->merge(['whereIn' => $ids]);    
        }
        $results = $model::filter($this->filters)->with($relationships)->paginate(10);
        return $results; 
    }
}
I want to call the method like this, NO passing arguments to constructor (DI should handle that), call method STATICALLY
Appointments::search();
                You can define a Searchable trait (instead of your Search class) like this:
trait Searchable
{
    public static function search($relationships = [])
    {
        //You may use the `resolve` method to resolve a class instance.
        $request = resolve(\Illuminate\Http\Request::class);
        //or $request = request();
        $filters = resolve(\App\Filters\QueryFilters::class);
        //rename the other `search` function on your model to `doSearch` to resolve conflicts
        $results = self::doSearch($request->input('search'), '')->get();
        //or using request helper function
        //$results = self::doSearch(request('search'), '')->get(); 
        if(!$results->isEmpty())
        {
            $ids = implode(',', $results->pluck('id')->toArray());
            $filters->merge(['whereIn' => $ids]);    
        }
        $results = self::filter($filters)->with($relationships)->paginate(10);
        return $results; 
    }
}
and implement this Searchable contract on your Eloquent model:
class Appointment extends Model
{
    use Searchable;
    //...
}
now you can call:
Appointment::search();
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With