Как правильно связать модели и пользовательские классы в Laravel - PullRequest
1 голос
/ 09 октября 2019

Я не понимаю, как правильно подключить модель и фильтр. Я реализовал это с помощью Dependency Injection в контроллере, но мне не нравится тот факт, что это нужно делать в каждом методе, где должна применяться фильтрация. Было бы очень удобно, если бы сама модель понимала, какой класс с фильтрами использовать.

Подскажите, как сделать лучше.

Класс фильтрации:

namespace App\Classes\Filter;

class QueryFilter
{
    protected $query;
    protected $params;

    public function apply($query, $params)
    {
        $this->query = $query;
        $this->params = $params;

        foreach ($this->filters() as $filter => $value){
            if(method_exists($this, $filter)){
                $this->$filter($value);
            }
        }

        return $this->query;
    }

    public function filters()
    {
        return $this->params;
    }
}

Наследники реализуютфильтры для разных моделей:

namespace App\Classes\Filter;

class PositionFilter extends QueryFilter
{

    public function title($value)
    {
        $this->query->where('title', 'LIKE', "%$value%");
    }

}

class GasStationFilter extends QueryFilter
{

    public function number($value)
    {
        $this->query->where('number', 'LIKE', "%$value%");
    }

    public function region($value)
    {
        $this->query->whereHas('region', function ($query) use ($value){
           $query->where('regions.id', $value);
        });
    }
}

В контроллере я внедряю требуемый класс с фильтрами и применяю фильтрацию следующим образом (я использую область действия в модели):

    public function index(GasStationIndexRequest $request, GasStationFilter $filters)
    {
        $gasStations = GasStation::with('region')
            ->filter($request->validated(), $filters)
            ->take(10)
            ->get();

        return GasStationSelect2Resource::collection($gasStations);
    }

Модель:

namespace App\Models;

class GasStation extends ListModel
{
    public function region(): BelongsTo
    {
        return $this->belongsTo(Region::class);
    }

    public function scopeFilter($query, $params, $filters) : Builder
    {
        return $filters->apply($query, $params);
    }


}
...