Conditional query with WhereBetween in Laravel - laravel

I've got the following controller function section for a little search block form:
$manifests = DB::table('carrier_manifests')
->join('customers', 'carrier_manifests.carrierOrigin', '=', 'customers.id')
->select('carrier_manifests.*', 'customers.customer_name')
->where([
['manifestNumber', 'LIKE', '%' . $manifest . '%'],
['originTerminal','LIKE','%' . $terminal . '%'],
['carrierOrigin', $direction[0], $direction[1]],
])
->whereNull('deleted_at')
->orderBy('dateUnloaded', 'DESC')
->whereBetween('dateUnloaded', [$startDate, $endDate])
->limit(100)
->get();
Every part of it works correctly except for one section, the whereBetween, because of a workflow necessity, sometimes the dateUnloaded in the clause is not filled in for every carrier_manifest, so that means if the dateUnloaded field is empty, it will be left out of the search results.
Are there any suggestions for how to include those results missing the dateUnloaded?

You should be able to do a nested where() for the null values or between like:
$manifests = DB::table('carrier_manifests')
->join('customers', 'carrier_manifests.carrierOrigin', '=', 'customers.id')
->select('carrier_manifests.*', 'customers.customer_name')
->where([
['manifestNumber', 'LIKE', '%' . $manifest . '%'],
['originTerminal','LIKE','%' . $terminal . '%'],
['carrierOrigin', $direction[0], $direction[1]],
])
->whereNull('deleted_at')
->orderBy('dateUnloaded', 'DESC')
->where(function($query) use ($startDate, $endDate) {
return $query->whereBetween('dateUnloaded', [$startDate, $endDate])
->orWhereNull('dateUnloaded');
})
->limit(100)
->get();

So from what I have understood is that dateUnloaded may or may not be provided to the query.
In such a case you can use the when method of laravel
Example taken from laravel docs
https://laravel.com/docs/5.6/queries
$users = DB::table('users')
->when($role, function ($query) use ($role) {
return $query->where('role_id', $role);
})
->get();
Here you can see that if $role is present then only the query will be executed otherwise not.

Please Try This...
$manifests = DB::table('carrier_manifests')
->join('customers', 'carrier_manifests.carrierOrigin', '=', 'customers.id')
->select('carrier_manifests.*', 'customers.customer_name')
->where([
['manifestNumber', 'LIKE', '%' . $manifest . '%'],
['originTerminal','LIKE','%' . $terminal . '%'],
['carrierOrigin', $direction[0], $direction[1]],
])
->whereNull('deleted_at')
->orderBy('dateUnloaded', 'DESC')
->where(function($q) use ($startDate,$endDate){
if($endDate !="" && $startDate !=""){
$q->whereBetween('dateUnloaded', [$startDate, $endDate]);
}
return $q;
})
->limit(100)
->get();

Related

Laravel whereDate() is not working as expected

The following is part of my query for querying data between two dates:
->whereDate('fixture_date', '>=', Carbon::now()->subDays($pastDays))
->whereDate('fixture_date', '<=', Carbon::now()->addDays($futureDays))
->when(request('search'), function ($query) {
$query->orWhere('fixture_hometeam_name', 'LIKE', '%' . request('search') . '%')
->orWhere('fixture_awayteam_name', 'LIKE', '%' . request('search') . '%');
})
When request('search') is empty, I am getting the expected results but when not, the whereDate queries are not working.
How should this be modified to give the correct results?
Add another layer to add parenthesis around the orWhere of the search.
->whereDate('fixture_date', '>=', Carbon::now()->subDays($pastDays))
->whereDate('fixture_date', '<=', Carbon::now()->addDays($futureDays))
->when(request('search'), function ($query) {
$query->where(function($subQuery) {
$subQuery->orWhere('fixture_hometeam_name', 'LIKE', '%' . request('search') . '%')
->orWhere('fixture_awayteam_name', 'LIKE', '%' . request('search') . '%');
})
})
You can use whereBetween instead of two whereDate.
->whereBetween('fixture_date', [
now()->subDays($pastDays)->startOfDay(), now()->addDays($futureDays)->endOfDay()
])->when($request->search, function ($query, $search) {
return $query->where(function ($query) use ($search) {
$query->where('fixture_hometeam_name', 'like', "%{$search}%")
->orWhere('fixture_awayteam_name', 'like', "%{$search}%");
});
https://laravel.com/docs/8.x/queries#logical-grouping
You should always group orWhere calls in order to avoid unexpected behavior when global scopes are applied.

How can I Refactor this search filter query?

I need to search in multiple tables. I'm checking every single request object. For example: I am checking if the request has that object then concating it to my main query and getting that query result at the last. It doesn't looks and isn't good. How can I make this search query filter better in laravel?
Note: I have searched questions in stackoverflow but they are dealing with only one model.
$query = DB::table('clients')
->leftjoin('ecommerce_contacts','ecommerce_contacts.client_id', '=', 'clients.id')
->select('ecommerce_contacts.*', 'clients.*')
->where('clients.is_deleted', '=', '0');
if(!is_null($request->fname)){
$query+=->where('clients.fname', 'like', '%$request->fname%');
}
if(!is_null($request->lname)){
$query+=->where('clients.lname', 'like', '%$request->lname%');
}
if(!is_null($request->gender)){
$query+=->where('clients.sex', $request->sex);
}
if(!is_null($request->number)){
$query+=->where('ecommerce_contacts.sex', 'like', $request->number);
}
if(!is_null($request->registered_date)){
}
if(!is_null($request->purchase)){
}
$client = $query->get();
$data = json_encode($clients);
return $data;
Use conditional clauses:
DB::table('clients')
->leftjoin('ecommerce_contacts','ecommerce_contacts.client_id', '=', 'clients.id')
->select('ecommerce_contacts.*', 'clients.*')
->where('clients.is_deleted', '=', '0')
->when(request()->has('fname'), function ($query) {
return $query->where('clients.fname', 'like', '%' . request()->fname . '%');
})
->when(request()->has('lname'), function ($query) {
return $query->where('clients.lname', 'like', '%' . request()->lname . '%');
})
->when(request()->has('gender'), function ($query) {
return $query->where('clients.sex', '=', request()->gender);
})
...
$query=DB::table('clients')
->leftjoin('ecommerce_contacts','ecommerce_contacts.client_id', '=', 'clients.id')
->select('ecommerce_contacts.*', 'clients.*')
->where('clients.is_deleted', '=', '0');
$search_fields=['fname','lname','gender','number','registered_date','purchase'];
foreach($search_fields as $key){
if(!is_null($key)){
$query->orWhere('clients.'.$key, 'LIKE', '"%" . '.$request->$key.' . "%"');
}
}
$client = $query->get();
$data = json_encode($client);
return $data;
I upvoted #DigitalDrifter 's answer because i liked it but I prefer my filter pattern.
Have a look at this:
$query = DB::table('clients')
->leftjoin('ecommerce_contacts','ecommerce_contacts.client_id', '=', 'clients.id')
->select('ecommerce_contacts.*', 'clients.*')
->where('clients.is_deleted', '=', '0');
!isset($request->fname) ?: $query->where('clients.fname', 'like', '%$request->fname%');
!isset($request->lname) ?: $query->where('clients.lname', 'like', '%$request->lname%');
!isset($request->gender) ?: $query->where('clients.sex', $request->sex);
!isset($request->number) ?: $query->where('ecommerce_contacts.sex', 'like', $request->number);
$client = $query->get();
$data = json_encode($clients);
return $data;
I think this is more readable and requires less line of code.

How To Get Search Query From Multiple Columns in Database

I have search form to get information from table named books.
Right now i'm using this controller
public function search(Request $request)
{
$keyword = $request->input('keyword');
$query = Book::where('judul', 'LIKE', '%' . $keyword . '%');
$book_list = $query->paginate(5);
$pagination = $book_list->appends($request->except('page'));
$total_book = $book_list->total();
return view('dashboards.index', compact('book_list', 'keyword', 'pagination', 'total_book'));
}
The problem is the data that i get from the request only available for judul. it just show empty result if the input keyword search addressed to search writter or publisher
I want the search form able to get data from other columns named writters and publisher
Is there any method to get data from multiple column?
You can use orwhere to fullfill this, like this
Book::where(function ($query) use($keyword) {
$query->where('judul', 'like', '%' . $keyword . '%')
->orWhere('writters', 'like', '%' . $keyword . '%');
})
->get();
I hope it helps you.
You can execute conditional queries in many ways.
1. You can use when():
Book::when($keyword, function ($q) use ($keyword) {
return $q->where('judul', 'LIKE', '%' . $keyword . '%');;
})
->get();
2. Use the where closure:
Book::where(function($q) use ($keyword, $request) {
if ($request) {
$q->where('judul', 'LIKE', '%' . $keyword . '%');
}
})
->get();
3. Do this:
$books = Book::query();
if ($request) {
$books = $books->where('judul', 'LIKE', '%' . $keyword . '%');
}
$books = $books->get();

search function with Where clause not work

hello everyone i try to run a search query with a condition for my column 'structure_id' but when i run the query , it display me also results who are not from 'structure' = 4
here my query :
$search = $request->get('q');
return User::where(function($q) use($search) {
$q->where('name', 'like', '%' . $search .'%')
->orWhere('email', 'like', '%'.$search.'%')
->where('structure_id' , '=' , '4');
})->get();
someone have an idea to resolve this? thanks a lot in advance
change it to
$search = $request->get('q');
return User::where(function($q) use($search) {
$q->where('name', 'like', '%' . $search .'%')
->orWhere('email', 'like', '%'.$search.'%');
})
->where('structure_id' , '=' , '4')
->get();

Laravel 4: A where and whereIn inside a whereHas using Eloquent

Laravel 4 - advanced Where
I'm trying to retrieve Posts that have a $keyword like a certain Companion and besides that I want to retrieve the Posts the have a linking title or content as the $keyword.
But when I try to use a where or whereIn inside a whereHas the query doesn't take these into account. When the state is 0 (not visible) or not inside the category 1 the Post item should not get selected.
$companion_id = Companion::where('name', 'LIKE', '%' . $keyword . '%' )->lists('id');
The code block below has to do two things:
Search for Post items with a title or content like the $keyword
and search for Post items that have Companions like the $keyword
code:
$results = Post::whereHas('companions', function($query) use($companion_id)
{
$query->whereIn('companions.id', $companion_id)
->where('state', '=', 1)
->whereIn('category_id', array(1));
})
->whereIn('category_id', array(1))
->orwhere('title', 'LIKE', '%' . $keyword . '%' )
->orWhere('content', 'LIKE', '%' . $keyword . '%' )
->where('state', '=', '1')
->orderBy('menu_order', 'desc')
->get();
The code above retrieves data succesfully except for the where and whereIn parts inside the whereHas.
Who can help me out?
wrap your orWhere clauses in (..)
you don't need where and whereIn in the whereHas closure, since it queries companions table
you don't need whereIn for category_id, unless you want to pass multiple ids there
.
$results = Post::whereHas('companions', function($query) use($companion_id)
{
$query->whereIn('companions.id', $companion_id);
})
->whereIn('category_id', array(1)) // why not where(..) ?
->where(function ($q) use ($keyword) {
$q->where('title', 'LIKE', '%' . $keyword . '%' )
->orWhere('content', 'LIKE', '%' . $keyword . '%' );
})
->where('state', '=', '1')
->orderBy('menu_order', 'desc')
->get();
Thanks to Jarek Tkaczyk.
His answer was almost correct. All I had to do was wrap the where inside a orWhere. Now I get the Posts that has a Companion like the $keyword and I get the Posts that has the $keyword inside the content or title.
$results = Post::whereHas('companions', function($query) use($companion_id)
{
$query->whereIn('companions.id', $companion_id)
->where('state', '=', '1');
})
->orWhere( function($q) use ( $keyword ) {
$q->where('title', 'LIKE', '%' . $keyword . '%' )
->orWhere('content', 'LIKE', '%' . $keyword . '%' );
})
->whereIn('category_id', array(1, 3))
->where('state', '=', '1')
->orderBy('menu_order', 'desc')
->get();

Resources