laraveleloquenteloquent-relationshiplaravel-relations

How can I make this code easy . i use this query() function for many section


** How can I make this code easy . i use this query() function for many section i want to get event by filter. my filter based on tags and category(both are in pivot table) **

public function index(Request $request)
{
    $customQuery = Event::where('status', '1');
    if ($request->vehical_type) { //vehical filter
        $customQuery->where('vehical_type', '=', $request->vehical_type);
    }
    if ($request->tag) { //tag filter
        $id = $request->tag;
        $customQuery->whereHas('tags', function (Builder $query) use ($id) {
            $query->where('tag_id', $id);
        });
    }
    if ($request->category) { //category filter
        $id = $request->category;
        $customQuery->whereHas('categories', function (Builder $query) use ($id) {
            $query->where('category_id', $id);
        });
    }
    $events = $customQuery->get(); //get event according to filters
    $tags = Tag::whereHas('events', function (Builder $query) { //get all tags of events
        $query->where('event_id', '>', 0);
    })->get();
    $categories = Category::whereHas('events', function (Builder $query) { //get all categories of events
        $query->where('event_id', '>', 0);
    })->get();
    return view('frontend.event.index', compact('events', 'tags', 'categories'));
}

Solution

  • You could use when for conditionals in the query and short hand closures with fn to put them in a single line. whereRelation instead of whereHas could make those queries a bit shorter too.

    public function index(Request $request)
    {
        $events = Event::query()
            ->where('status', '1')
            ->when(
                $request->vehical_type,
                fn($query) => $query->where('vehical_type', $request->vehical_type)
            )
            ->when(
                $request->tag,
                fn($query) => $query->whereRelation('tags', 'tag_id', $request->tag)
                // or fn($query) => $query->whereHas('tags', fn($tags) => $tags->where('tag_id', $request->tag))
            )
            ->when(
                $request->category,
                fn($query) => $query->whereRelation('categories', 'category_id', $request->category)
                // or fn($query) => $query->whereHas('categories', fn($category) => $category->where('category_id', $request->category))
            )
            ->get();
    
        $tags = Tag::query()
            ->whereRelation('events', 'event_id', '>', 0)
            // or ->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
            ->get();
    
        $categories = Category::query()
            ->whereRelation('events', 'event_id', '>', 0)
            // or ->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
            ->get();
    
        return view('frontend.event.index', compact('events', 'tags', 'categories'));
    }
    

    You could also maybe use a query scope to put the search in the Event model.

    # Event.php
    public function scopeSearch(Builder $query, array $filter = [])
    {
        return $query
            ->when(
                array_key_exists('vehicle_type', $filter),
                fn($query) => $query->where('vehical_type', $filter['vehicle_type'])
            )
            ->when(
                array_key_exists('tag', $filter),
                fn($query) => $query->whereRelation('tags', 'tag_id', $filter['tag'])
                // or fn($query) => $query->whereHas('tags', fn($tags) => $tags->where('tag_id', $filter['tag']))
            )
            ->when(
                array_key_exists('category', $filter),
                fn($query) => $query->whereRelation('categories', 'category_id', $filter['category'])
                // or fn($query) => $query->whereHas('categories', fn($category) => $category->where('category_id', $filter['category']))
            );
    }
    
    public function index(Request $request)
    {
        $filter = [
            'vehicle_type' => $request->vehicle_type,
            'tag' => $request->tag,
            'category' => $request->category,
        ];
    
        $events = Event::query()
            ->where('status', '1')
            ->search($filter)
            ->get();
    
        $tags = Tag::query()
            ->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
            ->get();
    
        $categories = Category::query()
            ->whereHas('events', fn($events) => $events->where('event_id', '>', 0))
            ->get();
    
        return view('frontend.event.index', compact('events', 'tags', 'categories'));
    }