0

I'm trying to build a filter on my data using laravel .. I have many to many relationships between the BasicItem model And AttValue Model and table Item_value between them.

this code works as what I want but I need it to be more dynamic depending on the user choice ex. this $value is what the user choices

$values = array(
        "0" => ['Dell','hp'],
        "1" => ['Mac' ,'linux','windows'],
        "2" => ['12.3' ,'12.5'],
        "3" => ['8 GB RAM'],
    );
    $x = BasicItem::whereHas('AttValue', function($query) use ($values) {
        $query->whereIn('attributeValue', $values["0"] );
    })
        ->WhereHas('AttValue', function($query) use ($values)  {
            $query->whereIn('attributeValue',$values["1"]);
        })
        ->WhereHas('AttValue', function($query) use ($values)  {
            $query->whereIn('attributeValue',$values["2"]);
        })
        ->WhereHas('AttValue', function($query) use ($values)  {
            $query->whereIn('attributeValue',$values["3"]);
        })
        ->get();

Now I want to Repeat the

->WhereHas('AttValue', function($query) use ($values)  {
    $query->whereIn('attributeValue',$values["$i"]); 

statement as many as the length of the array

Abdulla Nilam
  • 36,589
  • 17
  • 64
  • 85
Ammar
  • 3
  • 2

3 Answers3

0

Simple and sweet query:

use Illuminate\Support\Arr;

$x = BasicItem::whereHas('AttValue', function($query) use ($values) {
        $query->whereIn('attributeValue', Arr::flatten($values));
    })
    ->get();

infinite/dynamic whereHas,

$x = BasicItem::query();

foreach($values as $value) {
    $x->whereHas('AttValue',
        fn($query) => $query->whereIn('attributeValue',$value)
    );
}

$x->get();
JS TECH
  • 1,556
  • 2
  • 11
  • 27
  • This would basically make the query an OR query, which would change the context of the query – Techno Oct 03 '22 at 11:41
  • I really need to make several whereHas statements , because This data depends on each other , what I want like a query on result of last whereHas query.. – Ammar Oct 03 '22 at 11:48
  • The query OP wants, looks like this: `select * from basic_items where exists(select * from att_values where attributeValue in ('dell', 'hp')) AND exists(select * from att_values where attributeValue in ('mac', 'linux', 'windows'))) //etc` and your query looks like this: `select * from basic_items where exists(select * from att_values where attributaValue in ($everything))` Maybe it is more clear to see the difference in intentions this way? – Techno Oct 03 '22 at 12:12
0
$values = array(
            "0" => ['Dell', 'hp'],
            "1" => ['Mac', 'linux', 'windows'],
            "2" => ['12.3', '12.5'],
            "3" => ['8 GB RAM'],
        );

        $val_arr = [];
    foreach ($values as $value) {
        foreach ($value as $item){
            $val_arr[] = $item;

        }
    }

        $x = BasicItem::whereHas('AttValue', function($query) use ($val_arr) {
            $query->whereIn('attributeValue', $val_arr );
        })->get();

you can do this just whereHas. You can look your array put 1 array and you can whereIn this array.

Hasan Çetin
  • 172
  • 1
  • 9
  • This would basically make the query an OR query, which would change the context of the query. Plus you are checking for `$values[0]` and an array already containing `$values[0]` – Techno Oct 03 '22 at 11:42
  • but you shown us always same item you are searching for. cause of that you dont need always write whereHas i made this single, and your value always searching end of array with for loop. – Hasan Çetin Oct 03 '22 at 11:45
  • I really need to make several whereHas statements , because This data depends on each other , what I want like a query on result of last whereHas query – Ammar Oct 03 '22 at 11:47
  • I'm not the OP ;) What I mean is, now you retrieve a value if it only has `8 GB RAM`, while it should also have a match for any of all of the above – Techno Oct 03 '22 at 11:47
  • @RobBiermann exactly , but how to make it dynamic ? – Ammar Oct 03 '22 at 11:53
  • @Ammar look at my answer too please ?:D – Techno Oct 03 '22 at 11:54
0

If you want the query to work contextually the same, the best way is to do this:

$x = BasicItem::query();
foreach($values as $value) {
    $x->whereHas('AttValue', function($query) use ($value)  {
        $query->whereIn('attributeValue',$value);
    });
}
$x->get();

Only results will show that have attributeValue in first array AND second array AND third array AND forth array and so on.

EDIT: Changed solution to loop over whereHas in stead of whereIn

Techno
  • 1,668
  • 1
  • 9
  • 19