laravel 🚀
vue 🚀
inertia 🚀
Nice way of doing filters in Laravel

I got a chunk of this idea from https://github.com/inertiajs/pingcrm

Basically I made a DTO:

<?php

namespace App\Data;

use Spatie\DataTransferObject\Attributes\CastWith;
use Spatie\DataTransferObject\Attributes\MapFrom;

class FilterDto extends \Spatie\DataTransferObject\DataTransferObject
{
    #[MapFrom('sort')]
    public string $sort = 'created_at';

    #[MapFrom('order')]
    public string $order = 'ASC';

    #[MapFrom('type')]
    public ?string $type;

    #[MapFrom('active')]
    #[CastWith(BoolCaster::class)]
    public bool $active = false;

    #[MapFrom('land_owner')]
    #[CastWith(BoolCaster::class)]
    public bool $land_owner = false;

    #[MapFrom('land_owner_name')]
    public ?string $land_owner_name;

    #[MapFrom('flow_meter')]
    #[CastWith(BoolCaster::class)]
    public bool $flow_meter = false;

    #[MapFrom('allow_gsa_contact')]
    #[CastWith(BoolCaster::class)]
    public bool $allow_gsa_contact = false;

    #[MapFrom('has_well_complete_report')]
    #[CastWith(BoolCaster::class)]
    public bool $has_well_complete_report = false;

    #[MapFrom('well_report_image')]
    #[CastWith(BoolCaster::class)]
    public bool $well_report_image = false;

    #[MapFrom('well_report_doc')]
    #[CastWith(BoolCaster::class)]
    public ?bool $well_report_doc = false;

    #[MapFrom('construction_date_month')]
    public ?int $construction_date_month;

    #[MapFrom('construction_date_year')]
    public ?int $construction_date_year;

    #[MapFrom('pump_hp')]
    public ?int $pump_hp;

    #[MapFrom('pump_type')]
    public ?string $pump_type;

    #[MapFrom('pump_manufacturer')]
    public ?string $pump_manufacturer;

    #[MapFrom('well_driller')]
    public ?string $well_driller;

    #[MapFrom('user_id')]
    public ?int $user_id;

    #[MapFrom('flow_meter_manufacturer')]
    public ?string $flow_meter_manufacturer;

    #[MapFrom('search')]
    public ?string $search;
}

And then in the Controller I did this

    public function wells()
    {
        $filters = request()->all();

        $filters = new FilterDto($filters);

        $users = User::get()->map(fn ($user) => [
            'id' => $user->id,
            'name' => $user->first_name.' '.$user->last_name,
        ]);

        $types = Well::$types;

        return inertia('Admin/Wells/Index', [
            'wells' => Well::query()
                ->with(['user' => function ($query) {
                    $query->select('id', 'first_name', 'last_name', 'email');
                }])
                ->filter($filters)
                ->paginate(50)
                ->withQueryString(),
            'filters' => $filters,
            'users' => $users,
            'types' => $types,
            'months' => $this->months(),
            'years' => $this->years(),
        ]);
    }

Then the model has a "Filter" method:

public function scopeFilter($query, FilterDto $filters)
    {
        return $query->when($filters->sort, function ($query) use ($filters) {
            return $query->orderBy($filters->sort, $filters->order);
        })->when($filters->search, function ($query) use ($filters) {
            $like = '%'.$filters->search.'%';

            return $query->where('lat', 'LIKE', $like)
                ->orWhere('apn', 'LIKE', $like)
                ->orWhere('gsa', 'LIKE', $like)
                ->orWhere('inactive_reason', 'LIKE', $like)
                ->orWhere('land_owner_name', 'LIKE', $like)
                ->orWhere('pump_hp', 'LIKE', $like)
                ->orWhere('pump_manufacturer', 'LIKE', $like)
                ->orWhere('pump_type', 'LIKE', $like)
                ->orWhere('well_driller', 'LIKE', $like)
                ->orWhere('flow_meter_type', 'LIKE', $like)
                ->orWhere('lng', 'LIKE', $like);
        })->when($filters->construction_date_month, function ($query) use ($filters) {
            return $query->where('construction_date_month', '=', $filters->construction_date_month);
        })->when($filters->construction_date_year, function ($query) use ($filters) {
            return $query->where('construction_date_year', '=', $filters->construction_date_year);
        })->when($filters->type, function ($query) use ($filters) {
            return $query->whereType($filters->type);
        })->when($filters->active, function ($query) {
            return $query->whereActive(1);
        })->when($filters->flow_meter, function ($query) {
            return $query->whereFlowMeter(1);
        })->when($filters->has_well_complete_report, function ($query) {
            return $query->whereHasWellCompleteReport(1);
        })->when($filters->allow_gsa_contact, function ($query) {
            return $query->whereAllowGsaContact(1);
        })->when($filters->land_owner, function ($query) {
            return $query->whereLandOwner(1);
        })->when($filters->user_id, function ($query) use ($filters) {
            return $query->whereUserId($filters->user_id);
        });
    }

Finally Inertia/Vue could send this