skip to Main Content

I wrote a code something like this:

$bunnies = Bunny::with(['carrots' => function ($query) use ($request){
    if (empty($request->carrotStatus))
        return;
    $query->where('status', $request->carrotStatus);
}, 'owner'])
->select('bunnies.*')
->join('carrots', 'bunnies.id', '=', 'carrots.bunny_id')
->where(function (Builder $query) use ($request){
    if (empty($request->carrotStatus))
        return;
    $query->where('carrots.status', $request->carrotStatus);
})
->where(function (Builder $query) use ($request) {
    if (empty($request->multiSearch)) {
        return;
    }
    $query
        ->orWhereLike('carrots.name', "%{$request->multiSearch}%")
        ->orWhereLike('bunnies.name', "%{$request->multiSearch}%");
})
->groupBy('bunnies.id')
->orderBy('bunnies.id', 'asc')
->paginate(
    perPage: $request->get('pageSize', 5),
    page: $request->get('page', 1)
);

It runs in strict mode. https://laravel-news.com/shouldbestrict

I wonder if it is possible to make it less ugly. I don’t like that I give the bunny type twice Bunny:: and ->select('bunnies.*') and that I use table names instead of model names only. I don’t like the with part, but I am not sure if it is possible to replace it to load in strict mode. Can somebody help with these two?

2

Answers


  1. Chosen as BEST ANSWER

    I managed to solve this:

    $bunnies = Project::whereHas('carrots', function ($query) use ($request){
        if (!empty($request->carrotStatus))
            $query->where('carrots.status', $request->carrotStatus);
        if (!empty($request->multiSearch))
            $query->where(function ($query) use ($request){
                $query->orWhereLike('carrots.name', "%{$request->multiSearch}%")
                ->orWhereLike('bunnies.name', "%{$request->multiSearch}%");
            });
    })
    ->orderBy('bunnies.id', 'asc')
    ->paginate(
        perPage: $request->get('pageSize', 5),
        page: $request->get('page', 1)
    );
    
    if (empty($request->carrotStatus))
        $bunnies->load('carrots');
    else
        $bunnies->load(['carrots' => function ($query) use ($request){
            $query->where('status', $request->carrotStatus);
        }]);
    $bunnies->load('owner');
    

    I replaced the with to load, so I was able to separate the eager loading part from the query. After it I moved the !empty conditions outside the closures. And finally I changed the ugly select-join to whereHas which is in theory somewhat faster too. I was not able to use model names only, but it is not a real issue since I carrots is not a table name, but the relationship name here.


  2. you can break the query into multiple parts like this :

    $query = Bunny::with(['carrots' => function ($query) use ($request) {
        if (!empty($request->carrotStatus)) {
            $query->where('status', $request->carrotStatus);
        }
    }, 'owner'])
    ->select('bunnies.*')
    ->join('carrots', 'bunnies.id', '=', 'carrots.bunny_id');
    
    if (!empty($request->carrotStatus)) {
        $query->where('carrots.status', $request->carrotStatus);
    }
    
    if (!empty($request->multiSearch)) {
        $query->where(function (Builder $query) use ($request) {
            $query->orWhere('carrots.name', 'like', "%{$request->multiSearch}%")
                  ->orWhere('bunnies.name', 'like', "%{$request->multiSearch}%");
        });
    }
    
    $bunnies = $query->groupBy('bunnies.id')
        ->orderBy('bunnies.id', 'asc')
        ->paginate(
            perPage: $request->get('pageSize', 5),
            page: $request->get('page', 1)
        );
    
    

    also you can use if(!condition) { what you wanna do } instead of if(condition) return then what you want to do under it 🙂

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search