2

I have no idea how to solve my problem.

I have Model1 with relation:

class Model1 extends BaseModel
{
    public function details(): BelongsToMany
    {
        return $this->belongsToMany(
            Detail::class,
            'model1_details',
            'model1_id',
            'detail_id',
        );
    }
}

model1_details is my pivot table.

Also I have array of details ids like [1, 2, 3]. I need to fetch Model1 that belongs to ALL Detail with given ids.

I need to do this inside my filter. That's what I have inside my controller:

$builder = Model1::filter(new ModelListFilter($request));

and inside ModelListFilter:

protected function filter(): Builder
    {
        $request = $this->request;

        $request->whenFilled('details', function ($query) {
            //
        });

        return $this->builder;
    }

I've tried:

$request->whenFilled('details', function ($query) {
            foreach($query as $detailId) {
                $this->builder->whereHas('details', function (Builder $innerQuery) use ($detailId) {
                    $innerQuery->where('detail_id',  $detailId);
                });
            }
        });

But it returns all models Model1 even without any details.

UPD

So the problem wasn't there =) 'details' just wasn't filled in my Request. also my $query was a string, not array, so I called json_decode on it.

Code above retrieves Models belonging to detail with id=1 AND to detail with id=2 and so on.

But I think there might be better solution so I'll leave this question open

UPD 2

also changed this

$innerQuery->where('detail_id',  $detailId);

to this

$innerQuery->where('id',  $detailId);

so here is needed to pass columns we have in 'details' table, not columns from pivot table

Sutonne
  • 68
  • 6

3 Answers3

0

I can't see where you load the relationship with details. Not sure if you're missing a file, but in case you're not, load the relationship in the first part of the query with the eager loading with method:

$builder = Model1::with('details')->filter(new ModelListFilter($request));
Manuel Guzman
  • 483
  • 5
  • 15
  • 1
    Thank you for your suggestion , but It did not help. Also as I understand from laravel documentation is that we don't need 'with' method to use 'whereHas' example from laravel.com/docs/9.x/eloquent-relationships $posts = Post::whereHas('comments', function (Builder $query) { $query->where('content', 'like', 'code%'); })->get(); – Sutonne Feb 03 '23 at 17:42
  • @Natali Not really. WhereHas just validates the existence of the related record but doesn't retrieve it – Manuel Guzman Feb 03 '23 at 18:03
  • Okay, but I don't need to retrieve related model, just check if Model1 has related models with specific ids – Sutonne Feb 03 '23 at 18:09
  • Yes. My bad. I re-read the question. Can you get the compiled query of this issue? – Manuel Guzman Feb 03 '23 at 18:18
  • I understood where was my problem and updated question, thank you again – Sutonne Feb 03 '23 at 18:29
  • Now you can try the second answer (the whereIn one) – Manuel Guzman Feb 03 '23 at 19:30
0

You are almost there but you still missing two things,

WhereIn list

to get model whereHas their details ids in a list you need to use WhereIn instead of looping the query

Eager load the details relationship

to get the details list with each model you have to use the with keyword to eager load the relationship

Solution

// builder
$builder = Model1::with('details')->filter(new ModelListFilter($request));

// filter
$request->whenFilled('details', function (array $details) {
       $this->builder->whereHas('details', function (Builder 
            $innerQuery) use ($details) {
                    $innerQuery->whereIn('detail_id',  $details);
            }
        });
HijenHEK
  • 1,256
  • 1
  • 4
  • 13
  • Thank you! But it's opposite solution. Using this code I get Models belonging to detail with id=1 OR id=2 OR id=3. What I need is Model belonging to tag with id=1 AND to tag with id=2 AND... – Sutonne Feb 03 '23 at 18:06
0

Found solution to my problem here. So it seems like there is no better solution(

Sutonne
  • 68
  • 6