How to simplify Laravel Eloquent where clause? - php

The following example will give me all users that are older than $age and have the gender $gender:
public function get_users_older_than(int $age = null, string $gender = null) {
$users = User::query()
->where('age', '>', $age)
->where('gender', $gender)
->get();
return $users;
}
Is there a way to use the where clause only if age or gender is present in a more eloquent and shorter way then:
public function get_users_older_than(int $age = null, string $gender = null) {
$users = User::query();
if ($age) {
$users = $users->where('age', '>', $age):
}
if ($gender) {
$users = $users->where('gender', $gender):
}
$users = $users->get();
return $users;
}
With that, I could avoid to create and use the extra function and just have one single arrow connected line of code.

A shorter way to do that would be this:
$users = User::where(function ($q) use($age, $gender) {
if ($age) {
$q->where('age', '>', $age);
}
if ($gender) {
$q->where('gender', $gender);
}
})->get();
But just so you know, shorter code does not guarantee more efficiency.

There is also a conditional clauses function when.
Based on what you have, that could look like:
public function get_users_older_than(int $age = null, string $gender = null) {
$users = User::query();
$users->when($age, function ($query, $age) {
$query->where('age', '>', $age);
})->when($gender, function ($query, $gender) {
$query->where('gender', $gender);
})->get();
return $users;
}

Related

How to make a whereIn query builder in Laravel Eloquent with empty parameter

I have made a query in Laravel Eloquent to search in table.
public function searchContest($search){
$category = [];
$area = [];
if(isset($search['area'])){
$area = $search['area'];
}
if(isset($search['category'])){
$category = $search['category'];
}
$qry = self::whereIn('area',$area)
->whereIn('category', $category)
->get();
var_dump($query);
return;
}
But sometimes, area or category is empty and whereIn does not work with it. I'm not able to find any working solutions in the net. How can I make such a query?
Or you can take advantage of the conditional clauses as here
DB::table('table_name')
->when(!empty($category), function ($query) use ($category) {
return $query->whereIn('category', $category);
})
->when(!empty($area), function ($query) use ($area) {
return $query->whereIn('area', $area);
})
->get();
$q = self::query();
if (isset($search['area'])) {
$q->whereIn('area', $search['area']);
}
if (isset($search['category'])) {
$q->whereIn('category', $search['category']);
}
$qry = $q->get();
You can use query scope inside the entity
public function scopeArea($query, $ids)
{
if (! $ids) {
return ;
}
return $query->whereIn('area', $ids);
}
public function scopeCategory($query, $ids)
{
if (! $ids) {
return ;
}
return $query->whereIn('category', $ids);
}
Now you can build the query
$entity
->area($area)
->category($category)
->get();
https://laravel.com/docs/5.7/eloquent#query-scopes

Filters for products

I have query for filters:
public function filter(Request $request)
{
$category_id = $request->category;
$brand_id = $request->brand;
$filters = $request->filters;
if($brand_id == null){
$products = Products::with('brand')->whereHas('category',function($q) use($category_id){
$q->where('category_id', $category_id);
})->whereHas('filters',function($q) use($filters){
$q->where('filter_id', $filters);
})->paginate(9);
}else{
$products = Products::with('brand')->where('brand_id',$brand_id)->whereHas('category',function($q) use($category_id){
$q->where('category_id', $category_id);
})->whereHas('filters',function($qw) use($filters){
$qw->where('filter_id', $filters);
})->paginate(9);
}
//Брэнды всех товаров
$Brands = array();
foreach ($products as $product) {
if(!in_array($product->brand, $Brands)){
array_push($Brands, $product->brand);
}
}
return response()->json(['products' => $products,'brands' => $Brands]);
}
I get response only for first product, but i need to get all products which contain at least one filter from the list.How can I do it?
Just a small refactor + i'm not sure if you receive an array of filters or just a single id. If you need more than 1 id, use whereIn.
If you want to make this even cleaner, you can create Eloquent scope for filters and brands.
public function filter(Request $request)
{
$categoryId = $request->category;
$brandId = $request->brand;
$filters = $request->filters;
$query = Products::with('brand');
if ($brandId) {
$query = $query->where('brand_id', $brandId);
}
if ($filters) {
$query = $query->whereHas('filters', function($q) use ($filters) {
// If you have more than one filter id, use whereIn
// $q->where('filter_id', $filters);
$q->whereIn('filter_id', (array) $filters);
});
}
if ($categoryId) {
$query = $query->whereHas('category', function($q) use ($categoryId) {
$q->where('category_id', $categoryId);
});
}
$products = $query->paginate(9);
$brands = $products->total() > 0 ? $products->items()->pluck('brand')->all() : [];
return response()->json(compact('products', 'brands'));
}
use whereIn() function instead of where() when query products

Laravel array whereIn()

I have a form to filter items:
and I'm looking for something similar to this in Laravel 5.3:
// some variables get from request()->input('...')
$mode = ['A'];
$type = ['a', 'b'];
$group = [0, 1];
// desirable query
$results = Item::whereIn([
['mode_id', $mode],
['type_id', $type],
['group_id', $group]
])->paginate(10);
I can do this
$results = Item::whereIn('mode_id', $mode)
->whereIn('type_id', $type)
->whereIn('group_id', $group)
->paginate(10);
but it's not a dynamic way. For example, if a user select nothing in mode, the query returns an empty array.
We can use conditional clauses:
$results = Item::
when(!empty($mode), function ($query) use ($mode) {
return $query->where('mode_id', $mode);
})
->when(!empty($type), function ($query) use ($type) {
return $query->where('type_id', $type);
})
->when(!empty($group), function ($query) use ($group) {
return $query->where('group_id', $group);
})
->paginate(10);
You can do:
$qb = Item::newQuery();
if (!empty($mode))
{
$qb->whereIn('mode_id', $mode);
}
if (!empty($type))
{
$qb->whereIn('type_id', $type);
}
if (!empty($group))
{
$qb->whereIn('group_id', $group);
}
$results = $qb->paginate(10);
Or build your whereIn associative array w/o empty where's before passing it on.

searching in belongsToMany relationship in laravel 5

Actually i want to search those question which user want to search after select any subject or course.
if a remove either whereHas from subject or course its works but with both its not working.
Please give a better solution for searching in belongsToMany realtionship.
i have a question table with Question model class
class Question extends Model{
public function courses(){
return $this->belongsToMany('App\Models\Course','course_questions');
}
public function subjects(){
return $this->belongsToMany('App\Models\Subject','subject_questions');
}
}
and in my searchController
public function index(Request $request){
$questions = Question::with(['user','courses','branches','subjects','years','universities','question_type'])
->where("status","=",1)
->where(function($query) use($request){
$q = $request->q;
if(isset($q) && !is_null($q)){
$query->where("question","LIKE","%$q%");
}
})
->whereHas('subjects',function($query) use($request){
$subjects = $request->subject;
if(isset($subjects)){
$_subjects = explode(" ",$subjects);
$query->whereIn("slug",$_subjects)
->orWhereIn("subject_name",$_subjects);
}
})
->whereHas('courses',function($query) use($request){
$course = $request->course;
if(isset($course)){
$_course = explode(" ",$course);
$query->whereIn("slug",$_course)
->orWhereIn("course",$_course);
}
})
->paginate();
if($request->ajax()){
$returnHTML = view('questions.question_list')->with('questions', $questions)->render();
return response()->json(array('success' => true, 'pageContent'=>$returnHTML));
}
You should build your query probably this way - you should verify conditions before adding any constraints to your query:
$query = Question::with(['user','courses','branches','subjects','years','universities','question_type'])
->where("status","=",1);
$q = $request->q;
if(isset($q) && !is_null($q)) {
$query = $query->where("question","LIKE","%$q%");
}
$subjects = $request->subject;
if (isset($subjects)) {
$query = $query->whereHas('subjects',function($query) use($subjects){
$_subjects = explode(" ",$subjects);
$query->whereIn("slug",$_subjects)
->orWhereIn("subject_name",$_subjects);
});
}
$course = $request->course;
if (isset($course)) {
$query = $query->whereHas('courses',function($query) use($course ){
$_course = explode(" ",$course);
$query->whereIn("slug",$_course)
->orWhereIn("course",$_course);
});
}
$questions = $query->paginate();
$products = Product::query()->
WhereHas('categories', function ($q) use ($keyword) {
$q->where('products.name', $keyword)
->orWhere('categories.name', $keyword);
})->get();
This is how I have used in my project

How to rewrite this simple unDRY laravel method

I'm wondering how can I rewrite the following User model eloquent business logic to be a bit more DRY. I'm passing three parameters to the model, where all of them are optional, to narrow down the DB search. I'm sure there has to be a elegant way to do this, but it is beyond me at the moment.
public function guests_age($location_id, $year, $gender)
{
if($location_id && $year && $gender)
{
return Guest::select('age')
->where('location_id', '=', $location)
->where('created_at', '=', $year)
->where('gender', '=', $gender)
->get();
}
elseif($location_id && $year && !$gender)
{
return Guest::select('age')
->where('location_id', '=', $location)
->where('created_at', '=', $year)
->get();
}
elseif($location_id && !$year && !$gender)
{
return Guest::select('age')
->where('location_id', '=', $location)
->get();
}
... and so on to cover all cases...
}
Thanks for any help.
try this method
public function guests_age($location_id, $year, $gender)
{
$this->qry = Guest::select('age');
if($location_id)
{
$this->qry->where('location_id', '=', $location);
}
if($year)
{
$this->qry->->where('created_at', '=', $year)
}
if($gender)
{
$this->qry->where('gender', '=', $gender)
}
return $this->qry->get()
... and so on to cover all cases...
}
public function guests_age($args = array())
{
$columns = array('location_id', 'created_at', 'gender');
$query = Guest::select('age');
foreach($columns as $column)
{
if(!empty($args[$column]))
$query = $query->where($column, $args[$column]);
}
return $query->get();
}
//usage:
guests_age(array('location_id' => '1'));
guests_age(array('location_id' => '1', 'gender' => 'm'));
//etc..

Categories