Search code examples
phplaravellaravel-4laravel-3

Can not manage Laravel query builder


$a = 0;
$searchqueryMake = 'whereHas';
foreach ($options as $param)
{
    if($a>0 && $searchCriteria == 2)
    {
          $searchqueryMake = 'orWhereHas';
          $u = ($u->$searchqueryMake('option', function($q) use($param){
                $q->where('option_id', '=', $param );
          }));
    }
    else
    {
         $u = ($u->$searchqueryMake('option', function($q) use($param){
                 $q->where('option_id', '=', $param );
         }));
    }
$a++;
}

$a = 0;
$searchqueryMake = 'whereHas';
foreach ($specific_University as $param)
{
    if($a>0 && $searchCriteria == 2)
    {
        $searchqueryMake = 'orWhereHas';
        $u = $u->$searchqueryMake('degree', function($q) use($param){
            $q->whereHas('university', function($q) use($param){
                $q->where('id', '=', $param);
            });
        });
    }
    else
    {
        $u = $u->$searchqueryMake('degree', function($q) use($param){
            $q->whereHas('university', function($q) use($param){
                $q->where('id', '=', $param);
            });
        });
    }
$a++;
}

I have written this code for getting below sql result For AND condition sql result will be this-

    select * from `users` where `group_id` = ? and
 (select count(*) from `options` inner join `user_option` on `options`.`id` = `user_option`.`option_id` where
 `user_option`.`user_id` = `users`.`id` and
 `option_id` = ?) >= 1 and
 (select count(*) from `options` inner join `user_option` on `options`.`id` = `user_option`.`option_id` where
 `user_option`.`user_id` = `users`.`id` and `option_id` = ?) >= 1 and
 (select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and
 `id` = ?) >= 1) >= 1 and
 (select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and
 `id` = ?) >= 1) >= 1 and
 (select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and
 `id` = ?) >= 1) >= 1

and again when user choose or condition the sql result is -

    select * from `users` where `group_id` = ? and 
(select count(*) from `options` inner join `user_option` on `options`.`id` = `user_option`.`option_id` where
 `user_option`.`user_id` = `users`.`id` and
 `option_id` = ?) >= 1 or
 (select count(*) from `options` inner join `user_option` on `options`.`id` = `user_option`.`option_id` where
 `user_option`.`user_id` = `users`.`id` and `option_id` = ?) >= 1 and
 (select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and `id` = ?) >= 1) >= 1 or
 (select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and
 `id` = ?) >= 1) >= 1 or
 (select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and
 `id` = ?) >= 1) >= 1

Top most query is fine because there all condition is in AND. But bottom one is not getting proper value because there we need all the conditions AND and OR and also need to separate by a parenthesis to get proper result which I can not do using this eloquent method. Can any one help me to find out this problem...

The exact query is this what I need -

select * from `users` where `group_id` = ? and 
((select count(*) from `options` inner join `user_option` on `options`.`id` = `user_option`.`option_id` where
 `user_option`.`user_id` = `users`.`id` and
 `option_id` = ?) >= 1 or
 (select count(*) from `options` inner join `user_option` on `options`.`id` = `user_option`.`option_id` where
 `user_option`.`user_id` = `users`.`id` and `option_id` = ?) >= 1) and
 ((select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and `id` = ?) >= 1) >= 1 or
 (select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and
 `id` = ?) >= 1) >= 1 or
 (select count(*) from `degrees` inner join `user_degree` on `degrees`.`id` = `user_degree`.`degree_id` where
 `user_degree`.`user_id` = `users`.`id` and
 (select count(*) from `universities` where
 `degrees`.`university_id` = `universities`.`id` and
 `id` = ?) >= 1) >= 1))

Solution

  • Alright this is a pretty huge query and I honestly don't have the time to go over it in detail. But here's how you can wrap parenthesis around basically every where condition. This is called nested where

    Firstly, here are a few normal wheres:

    where('foo', 'foo')->orWhere('foo', 'bar')->where('bar', 'bar')
    

    This results in:

    WHERE foo = 'foo' OR foo = 'bar' AND bar = 'bar'
    

    Which would be executed like:

    WHERE foo = 'foo' OR ( foo = 'bar' AND bar = 'bar' )
    

    To change that we can add a where with closure:

    where(function($query){
        $query->where('foo', 'foo');
        $query->orWhere('foo', 'bar');
    })->where('bar', 'bar');
    

    Now the SQL looks like this:

    WHERE ( foo = 'foo' OR foo = 'bar' ) AND bar = 'bar'
    

    I hope you can work with that and change your code accordingly.