I have a search form with multiple input and select boxes I need help to get if conditions in my query in order to each part works separately and all at once.
he
I suggest tu use each separeted and its help you to feature easaly manupulate code
as your typical condition your sub_option come from third table last relation ship is used.
if(count($request['suboptions'])) {
$product->whereHas('options',function($options) use ($request) {
$options->whereHas('suboptions',function($suboption)use($request) {
$suboption->whereIn('id',$request['suboptions']);
});
});
}
for min price max price i assume your price in procuct table
if(! empty($request['min_price'])) {
$product->where('price','>=',$request['min_price']);
}
if(! empty($request['max_price'])) {
$product->where('price','<=',$request['max_price']);
}
for brand as you say brand_id column in product table then
if(count($request['brands'])) {
$product->whereIn('brand_id',$request['brands']);
}
You can use laravel orWhere
and orWhereHas
to get results separately and all at once, let's say you do not select min_price
and max_price
but you have selected brand
then all products with this brnad should be return, your query will look like this
$products = Product::orWhere('price','>=',$min_price)
->orWhere('price','<=',$max_price)
->orWhereHas('brand',function($query){
$query->whereIn('id', $brand_ids);
})
->orWhereHas('suboptions',function($query){
$query->whereIn('id', $suboptions_ids);
})
->orWhereHas('subspecifications',function($query){
$query->whereIn('id', $subspecifications_ids);
})->get();
$products
will have products collection If any of the condition stated in above query matched.
Hope this helps.
Here's how I'd do it. Note the use of when
for simplifying optional where conditions (no need to set variables either), and the closure for constraining both the whereHas
and the with
(if you want to eager load the relationships).
$products = Product::query()
->when($request->min_price, function ($query, $min_price) {
return $query->where('price', '>=', $min_price);
})
->when($request->max_price, function ($query, $max_price) {
return $query->where('price', '<=', $max_price);
})
->when($request->suboptions, function ($query, $suboptions) {
$suboptionsConstraint = function ($q) use ($suboptions) {
return $q->whereIn('id', $suboptions);
};
return $query->whereHas('suboptions', $suboptionsContraint)
->with(['suboptions' => $suboptionsContraint]);
})
->when($request->brands, function ($query, $brands) {
$brandsConstraint = function ($q) use ($brands) {
return $q->whereIn('id', $brands);
};
return $query->whereHas('brands', $brandsConstraint)
->with(['brands' => $brandsConstraint]);
});
This is just to give an idea. You can use a multiple ->where()
and eager loading ->with()
for your query.
Take a look with this query below:
$products = Product::where('price', '>=', $min_price) // you get the max and min price
->where('id', '<=', $max_price)->select('id')
->with([
"brand" => function ($query) {
$query->whereIn('id', $brand_ids); // [1, 2, 3,...]
},
"specifications" => function ($query) {
$query->where('some_column', '=', 'possible-value'); // single condition
},
"specifications.subspecifications" => function ($query) {
$query->where([
'some_column' => 'possible-value',
'another_column' => 'possible-value'
]); // you can also pass arrays of condition
}
])->get(); // This will return the products with the price set by the user
// Since we're just using ->with(), this will also return those products
// that doesn't match the other criteria specifications) so we
// still need to filter it.
Finally, you can filter the products which matches the specifications
,
- the product
with an empty specifications
means this product does not match the criteria, therefore we'll have to remove it from the collection.
$filtered = $products->filter(function ($product, $key) {
return count($product->brand) > 0 && count($product->specifications) > 0;
// add your other boolean conditions here
});
dd($filtered->toArray()); // your filtered products to return
This is the method I use to search using laravel eloquent with multiple input:
$input = Input::all(); //group all the inputs into single array
$product = Product::with('options','suboptions','brand');
//looping through your input to filter your product result
foreach ($input as $key => $value)
{
if ($value!='') {
if ($key == "max_price")
$product = $product->where('price','<=', $value);
elseif ($key == "min_price")
$product = $product->where('price','>=', $value);
elseif ($key == "brands")
$product = $product->whereIn('brand_id', $value); //assuming that your Input::get('brands') is in array format
elseif ($key == "suboptions")
$product = $product->whereIn('suboption_id', $value);
}
}
$product = $product->get();
The method above will return all products if no input is submitted, and will filter the result based on the input if available, on top of this it's also a good practice to sanitize your inputs with validations before proceeding with the query
it is very simple to make dynamic search by using treats we can use this for all models I made this dynamic as possible
This is a trait that can be used by any models
This function will remove code repetitions into your project
public function scopeSearch($query, $keyword, $columns = [], $relativeTables = [])
{
if (empty($columns)) {
$columns = array_except(
Schema::getColumnListing($this->table), $this->guarded
);
}
$query->where(function ($query) use ($keyword, $columns) {
foreach ($columns as $key => $column) {
$clause = $key == 0 ? 'where' : 'orWhere';
$query->$clause($column, "LIKE", "%$keyword%");
if (!empty($relativeTables)) {
$this->filterByRelationship($query, $keyword, $relativeTables);
}
}
});
return $query;
}
Filter into relationship also
private function filterByRelationship($query, $keyword, $relativeTables)
{
foreach ($relativeTables as $relationship => $relativeColumns) {
$query->orWhereHas($relationship, function($relationQuery) use ($keyword, $relativeColumns) {
foreach ($relativeColumns as $key => $column) {
$clause = $key == 0 ? 'where' : 'orWhere';
$relationQuery->$clause($column, "LIKE", "%$keyword%");
}
});
}
return $query;
}