Eloquent where condition AND ( condition OR condition OR condition ) - laravel

Can somebody tell me what am I doing wrong?
I want to get all projects with status 0 and if any of data matches in eloquent.
My code is like this
public function search(Request $request){
if($request->has('q')){
$search_query = $request->input('q');
$projects = Project::where(['status' => '0'])->get();
$projects = $projects->where(function($query) use ($search_query) {
$query->where('title','LIKE','%'.$search_query.'%')
->orWhere('shortDescription','LIKE','%'.$search_query.'%')
->orWhere('longDescription','LIKE','%'.$search_query.'%')
->orWhere('tags','LIKE','%'.$search_query.'%')
->orWhere('projectLink','LIKE','%'.$search_query.'%');
});
$projects->get();
dd($projects);
}
}
And I am getting this error
ErrorException
explode() expects parameter 2 to be string, object given

I solved the problem but changed the code a little bit... If you like, take it! I tested and it's working.
if($request->has('q')){
// Your $request->q Value
$term = $request->q;
$projects = DB::table('tbl_projects')->where('status', '=', 0)
->where(function ($query) use ($term) {
$query->where('title', 'LIKE', '%'.$term.'%')
->orWhere('shortDescription', 'LIKE', '%'.$term.'%')
->orWhere('longDescription', 'LIKE', '%'.$term.'%')
->orWhere('tags', 'LIKE', '%'.$term.'%')
->orWhere('projectLink', 'LIKE', '%'.$term.'%');
})
->get();
//dd($projects);
}
Raw query is:
select * from `tbl_projects` where `status` = 0 and (`title` LIKE %bla bla% or `shortDescription` LIKE %bla bla% or `longDescription` LIKE %bla bla% or `tags` LIKE %bla bla% or `projectLink` LIKE %bla bla%))
Regards!

Your error is
$projects = Project::where(['status' => '0'])->get();
(['status' => '0']) Where clause params required is different. You must use ('status', '0') or ('status', '=', '0')
When you use ->get(), you have a Collection or EloquentCollection object. You need a QueryBuilder
Try to implement a better programation logic.
A better implementation is
public function search(Request $request){
if($request->has('q')){
// Add array with field coincidences target. Is better if this array is a const static field in the Project model
$searchFields = ['title', 'shortDescription', 'longDescription', 'tags', 'projectLink' ];
// Now you can add 100 fields for search coincidences easily
$search_query = $request->input('q');
$projects = Project::where('status', '0');
foreach($searchFields as $searchField){
if ($searchField == 'title'){
$projects = $projects->where($searchField,'LIKE',"%$search_query%");
continue;
}
$projects = $projects->orWhere($searchField,'LIKE',"%$search_query%");
}
$projects = $projects->get();
dd($projects);
}
}

Related

Laravel 8 - How to use where conditions for relation's column

hello friends can you help me to get the contents of $filter? I want to run where which is where the target column is in the relation array
$filter = $request->get('Biogear');
$data = DetailBarang::with(['barang' => function ($q) use ($filter) {
$q->where('brand', '=', $filter);
}])->get();
return response()->json($data);
you can try this
$filter = $request->get('Biogear');
$data = DetailBarang::with('barang')->whereHas('barang',function (Illuminate\Database\Eloquent\Builder $q) use ($filter) {
$q->where('brand', '=', $filter);
})->get();
return response()->json($data);

How can I render search on Livewire with an orWhere clause not related to search?

I have here a Livewire render function that displays records depending on what is searched on the textbox. It was working fine, and giving me results in an autocomplete manner. However, when I added this line ->orWhere('qty_on_hand', '!=', 0), it stops that autocomplete searching.
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Product;
class LoadInStockProducts extends Component
{
public $searchTerm;
public $amount = 10;
protected $listeners = [
'load-more' => 'loadMore'
];
public function loadMore()
{
$this->amount = $this->amount + 10;
}
public function render()
{
$searchTerm = '%' . $this->searchTerm . '%';
$products = Product::orderBy('name')->where('code', 'like', $searchTerm)
->orWhere('name', 'like', $searchTerm)
->orWhere('description', 'like', $searchTerm)
->orWhere('qty_on_hand', '!=', 0)
->paginate($this->amount);
$this->emit('productStore');
return view('livewire.load-in-stock-products', ['products' => $products]);
}
}
How can I make the autocomplete searching work, even with the ->orWhere('qty_on_hand', '!=', 0) condition? Also, another question, I've tried this ->orWhere('srp', '!=', 0.00) and it's not working. How can I make it work for float types? The srp field is a float type by the way.
Any help is much appreciated.
It sounds to me like you want to produce a query where you search for the given fields, and only show the records that has a quantity on hand - that would look like this in raw SQL,
SELECT *
FROM products
WHERE (
code LIKE '%searchterm%'
OR name LIKE '%searchterm%'
OR description LIKE '%searchterm%'
)
AND qty_on_hand != 0
ORDER BY name
Note how the search for code/name/description is within its own group, and that you look for any match of either of those and where the quantity is different from zero.
In Laravel, that means you have to group the query as well, using a closure.
$products = Product::where(function($query) use ($searchTerm) {
return $query->where('code', 'like', $searchTerm)
->orWhere('name', 'like', $searchTerm)
->orWhere('description', 'like', $searchTerm);
})
->where('qty_on_hand', '!=', 0)
->orderBy('name')
->paginate($this->amount);
You can introduce more groups if you have other conditions, like having two where() with a closure, where the queries inside use orwhere().
$products = Product::where(function($query) use ($searchTerm) {
return $query->where('code', 'like', $searchTerm)
->orWhere('name', 'like', $searchTerm)
->orWhere('description', 'like', $searchTerm);
})
->where(function($query) {
return $query->where('qty_on_hand', '!=', 0)
->orWhere('srp', '!=', 0);
})
->orderBy('name')
->paginate($this->amount);

Laravel query groubBy condition

I have a dB query where I would like to groupBy() only when conditions are met without using union because of pagination.
Unfortunately groupBy() seems to only work when called on the entire query outside of the loop.
This was made for dynamic filtering from $filterArr. Depending on the array I need to select from different columns of the table.
When the $key=='pattern' I would need the distinct results from its column.
the query looks something like this
select `col_1`, `col_2`, `col_3`
from `mytable`
where (`color` LIKE ? or `pattern` LIKE ? or `style` LIKE ?)
group by `col_2` //<< i need this only for 'pattern' above and not the entire query
Heres the model:
// $filterArr example
// Array ( [color] => grey [pattern] => stripe )
$query = DB::table('mytable');
$query = $query->select(array('col_1', 'col_2', 'col_3'), DB::raw('count(*) as total'));
$query = $query->where(function($query) use ($filterArr){
$ii = 0;
foreach ($filterArr as $key => $value) {
if ($key=='color'){
$column = 'color';
}else if ($key=='style'){
$column = 'style';
}else if ($key=='pattern'){
$column = 'pattern';
$query = $query->groupBy('col_2'); // << !! does not work
}
if($ii==0){
$query = $query->where($column, 'LIKE', '%'.$value.'%');
}
else{
$query = $query->orWhere($column, 'LIKE', '%'.$value.'%');
}
$ii++;
}
});
$query = $query->orderBy('col_2', 'asc')->simplePaginate(30);
I think you can simplify your code a bit:
$query = DB::table('mytable');
$query = $query->select(array('col_1', 'col_2', 'col_3'), DB::raw('count(*) as total'));
$query = $query->where(
collect($filterArr)
->only(['color','style','pattern'])
->map(function ($value, $key) {
return [ $key, 'like', '%'.$value.'%', 'OR' ];
})->all()
)->when(array_key_exists('pattern', $filterArr), function ($query) {
return $query->groupBy('col_2');
});
$query = $query->orderBy('col_2', 'asc')->simplePaginate(30);

How to group where clauses in Laravel Query Builder correctly

I am running the following query using the search() function below - the problem is I need to group the where clauses - what am I doing wrong?
select `standings`.*, `users`.`name` as `user` from `standings`
left join `users` on `standings`.`user_id` = `users`.`id`
where `users`.`name` like '%bob%' or `users`.`email` like '%bob%'
and `standings`.`tenant_id` = '1'
In my Standings model I have the following search() that performs the WHERE clause
public static function search($query)
{
return empty($query) ? static::query()
: static::where('users.name', 'like', '%'.$query.'%')
->orWhere('users.email', 'like', '%'.$query.'%');
}
public function render()
{
$query = Standing::search($this->search)
->select('standings.*', 'users.name AS user')
->leftJoin('users', 'standings.user_id', '=', 'users.id')
->orderBy('points', 'desc')
->orderBy('goals_difference', 'desc')
->orderBy('goals_for', 'desc');
if($this->super && $this->selectedTenant) {
$query->where('standings.tenant_id', $this->selectedTenant);
}
return view('livewire.show-standings', [
'standings' => $query->paginate($this->perPage)
]);
}
The query works however it doesn't group the WHERE clause correctly on the users.name & users.email fields - how do I change this search() function so the WHERE query has them grouped like this
where (`users`.`name` like '%bob%' or `users`.`email` like '%bob%')`
You need to group the where clauses in a wrapping where clause. Try this
public static function search($query)
{
return empty($query)
? static::query()
: static::where(function($query){
$query->where('users.name', 'like', '%'.$query.'%')
->orWhere('users.email', 'like', '%'.$query.'%');
});
}
Thanks that for some reason even though looks correct gives me the following error - Object of class Illuminate\Database\Eloquent\Builder could not be converted to string NB I am using Laravel with Livewire (not sure if that should make any difference)
$query->where('users.name', 'like', '%'.$query.'%') and ->orWhere('users.email', 'like', '%'.$query.'%'); is giving the error because while trying to compare $query is being treated as a string hence the error
You can define the search as a query scope on the model
//Assuming a relation Standing belongsTo User
//Query constraint to get all Standing records where
//related User record's name or email are like searchTerm
public function scopeSearch($query, string $searchTerm)
{
return $query->whereHas('user', function($query) use($searchTerm){
$query->where('name', 'like', "%{$searchTerm)%")
->orWhere('email', 'like', "%{$searchTerm}%");
});
}
Laravel docs:https://laravel.com/docs/8.x/eloquent#local-scopes
With the above search scope defined on Standing model, you can have the render function as
public function render()
{
$query = Standing::with('user:id,name')
->search($this->search)
->orderBy('points', 'desc')
->orderBy('goals_difference', 'desc')
->orderBy('goals_for', 'desc');
if($this->super && $this->selectedTenant) {
$query->where('tenant_id', $this->selectedTenant);
}
return view('livewire.show-standings', [
'standings' => $query->paginate($this->perPage)
]);
}

Parameters Group on eloquent query

I have little problem with my search query at the moment. When i run a search query with only the parameter "comite_id" it's working but when i want to run the search query with "comite_id" and the whereBetween with "date_min" and "date_max" the result is not right , it's seems the result don't care about the whereBetween clause because i don't get the right date range.
Someone knows where i'm doing wrong? thanks a lot in advance
Here my controller :
public function getRetrocession(Request $request){
$comites = Structure::where('type_structure_id' , '=' ,'3')->pluck('nom_structure' , 'id');
$search = $request->input('comite_id');
$dt_min = $request->input('dt_min');
$dt_max = $request->input('dt_max');
if ($search) {
$query = Retrocession::where('comite_id', '=', $search)
->orWhere(function ($q) use($search , $dt_min , $dt_max) {
$q->where('comite_id', '=', $search)
->whereBetween('dt_retrocession', [ $dt_min , $dt_max]);
});
}else {
$query = Retrocession::select();
}
$retrocessions = $query->orderBy('dt_retrocession', 'DESC')->paginate(10)
->appends(['recherche' => $search]);
return view('retrocession/index' , compact('retrocessions' , 'comites'));
}
Because you are using orWhere() it always call both where() and orWhere(); thus including the result of where() and orWhere(). You can try this way
$query = Retrocession::where('comite_id', $search)
->when($dt_min && $dt_max, function($q) use ($dt_min, $dt_max) {
$q->whereBetween('dt_retrocession', [$dt_min, $dt_max]);
});
So you always run the first where, and only include whereBetween() WHEN $dt_min and $dt_max are both true.
Bonne chance Mathieu.

Resources