Eloquent 'when' method after another 'when' - laravel

I have searched a lot for this but couldn't find related issues.
I have an Eloquent query in my app that is the following:
$cidades = Cidade::when($pesquisa, function ($q) use ($pesquisa) {
return $q->where('nome', 'like', '%' . $pesquisa . '%')
->orWhere('iso_ddd', 'like', '%' . $pesquisa . '%');
})
->when($estado, function ($q) use ($estado) {
return $q->where('estado_id', $estado);
})
->sortable('nome')
->simplePaginate($request->input('p'));
As you can see, I have two 'when' methods to filter the content. My intention is to check wheter each of them are active and filter the query accordingly. But the query above only works if only one of them is active at once. If $pesquisa is set, then it filters the content using the function, but ignores the following 'when' (objects of any $estado show up). If $pesquisa is not set but $estado is, then it correctly runs only the $estado's 'when'.
I could get it to run as excpected by copying $estado's 'when' inside $pesquisa's 'when', like this:
$cidades = Cidade::when($pesquisa, function ($q) use ($pesquisa, $estado) {
return $q->where('nome', 'like', '%' . $pesquisa . '%')
->when($estado, function ($q) use ($estado) {
return $q->where('estado_id', $estado);
})
->orWhere('iso_ddd', 'like', '%' . $pesquisa . '%');
})
->when($estado, function ($q) use ($estado) {
return $q->where('estado_id', $estado);
})
->sortable('nome')
->simplePaginate($request->input('p'));
But I find it a bit redundant. Is there any other way to query it?

I suspect the issue is the fact that there's an or involved. This is what you get when both are set:
SELECT * FROM cidades WHERE nom LIKE ? OR iso_ddd LIKE ? AND estado_id = ?
Due to AND having higher associativity to OR this would get all records where nom LIKE ? OR (iso_ddd LIKE ? AND estado_id = ?) which is not exactly what you seem to want.
You can try:
$cidades = Cidade::when($pesquisa, function ($q) use ($pesquisa) {
return $q->where(function ($q) use ($pesquisa) {
$q->where('nome', 'like', '%' . $pesquisa . '%')
->orWhere('iso_ddd', 'like', '%' . $pesquisa . '%');
});
})->when($estado, function ($q) use ($estado) {
return $q->where('estado_id', $estado);
})
->sortable('nome')
->simplePaginate($request->input('p'));
this should put parentheses around (nom = ? or iso_ddd = ?) to ensure the conditions are grouped correctly.

You can set the when parameter value to true. Then just check the condition inside the when
$cidades = Cidade::when(true, function ($q) use ($pesquisa, $estado) {
if ($estado) {
return $q->where('estado_id', $estado);
}
return $q->where('nome', 'like', '%' . $pesquisa . '%')
->orWhere('iso_ddd', 'like', '%' . $pesquisa . '%');
})
->sortable('nome')
->simplePaginate($request->input('p'));

By looking at the query log (DB::getQueryLog()) I found out that my problem was related to associativity.
The solution was to put the $estado's when before the $pequisa's when. That solved it.
DB::enableQueryLog();
$cidades = Cidade::when($estado, function ($e) use ($estado) {
return $e->where('estado_id', $estado);
})
->when($pesquisa, function ($q) use ($pesquisa, $estado) {
return $q->where('nome', 'like', '%' . $pesquisa . '%')
->orWhere('iso_ddd', 'like', '%' . $pesquisa . '%');
})
->sortable('nome')
->simplePaginate($request->input('p'));

Related

Adding secondary query to query based on parameter in laravel

I am trying to do a complex query based on the input fields of the form.
public function search(Request $request){
$borrado =
$activo = 0;
$models = array();
$escandallos = Scandal::all();
foreach ($escandallos as $escandallo){
if (in_array($escandallo->modelo, $models)) {
}else{
array_push($models, $escandallo->modelo);
}
}
$query = Model::where('modelo', 'like', '%' . $request['modelo'] . '%')
->where('prototipo', 'like', '%' . $request['prototipo'] . '%')
->where('oficial', 'like', '%' . $request['modofi'] . '%')
->where('usuario_realiza', 'like', '%' . $request['usuario'] . '%')
->where('tipo', 'like', '%' . $request['tipo'] . '%')
->where('activa', 'like', '%' . $activo . '%');
if($request['referencia'] || $request['proveedor']){
/** Here i want to do this DB:raw where in clause if reference or provider is in request and need to search in other table*/
$query->DB::raw("where (id_escandallo,id_version) in (select id_escandallo,id_version from escandallo_p where referencia ='".$request['referencia']. "' and proveedor ='".$request['proveedor']."'");
}
$query->orderBy('modelo','desc');
$query->orderBy('id_version','asc');
$scandals = $query->paginate(100);
dd($scandals);
return view('designdoc.escandallos',['scandals'=> $scandals],['models'=>$models]);
}
This return this error:
Property [DB] does not exist on the Eloquent builder instance.
Thank you in advance, any help would be appreciated.
Best regards.
Use ->whereRaw()
$query->whereRaw(...);
also, you can simplify this part
if($request['referencia'] || $request['proveedor']){
$query->whereRaw(...); // but dont use 'where' in the string, its already prepended
}
to this
$query->when($request['referencia'] || $request['proveedor'], function ($q) use ($request) {
$q->whereRaw(...)
});
it is good so that you can chain it with previous command

Eager Loading With Where Condition faulty

public function getListStaff(string $searchString = '')
{
return Staff::with(['citizen_identification' => function ($query) {
$query->where('full_name', 'like', '%' . $searchString . '%');
}])
->where('phone', 'like', '%' . $searchString . '%')
->orWhere('email', 'like', '%' . $searchString . '%')
->paginate(2);
}
I use Repository in project livewire of me, i newbie use livewire, when i code method getListStaff is faulty, i try fix, but not success, please help me fix... Thanhks bros
Because I wrong syntax or visual code error or so ???
It seems like you have missed use statement for searchstring.
In any case, based from you question its not clear what is not working.
return Staff::with([
'citizen_identification' => function ($query) use ($searchString) {
$query->where('full_name', 'like', '%'.$searchString.'%');
},
])
->where('phone', 'like', '%'.$searchString.'%')
->orWhere('email', 'like', '%'.$searchString.'%')
->paginate(2);

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 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();

Laravel eloquent search on fields of related model

I have an eloquent models as,
User : users(id, username, password, email, status)
Profile : profiles(id, user_id, first_name, last_name, gender, dob)
In the controller logic, I am eagerly loading the Profile model.
I can do this,
$user = User::with('Profile')->get();
or
$user = User::with('Profile')->where('status', '1')->get();
but how to do something like,
$user = User::with('Profile')->where('status', '1')->where('gender', 'Male')->get();
That's where whereHas comes in handy:
$user = User::with('Profile')->where('status', 1)->whereHas('Profile', function($q){
$q->where('gender', 'Male');
})->get();
Basically it adds the condition that the user needs to have a profile with gender = Male
If you want to search multiple columns in relation model.
$searchText = 'test text';
Product::with('owner')->where(function($query) use ($searchText)
{
$query->where('product_name', 'LIKE', '%' . $searchText . '%');
$columns = ['product_code', 'place_location', 'remark'];
foreach ($columns as $column ) {
$query->orWhere($column, 'LIKE', '%' . $searchText . '%');
}
$query->orWhereHas('owner', function($q) use ($searchText) {
$q->where(function($q) use ($searchText) {
$q->where('name', 'LIKE', '%' . $searchText . '%');
$q->orWhere('company_name', 'LIKE', '%' . $searchText . '%');
});
});
});
Let's say you've multiple relations
and you want to search records based on multiple relational columns value
User::with('associate')
->where('name', 'like', '%' . $input . '%')
->orWhere(function ($query) use ($input) {
$query->whereHas('associate', function ($q) use ($input) {
$q->where('first_name', 'like', '%' . $input . '%');
});
})
->orWhere(function ($query) use ($input) {
$query->with('roles')->whereHas('roles', function ($q) use ($input) {
$q->where('display_name', 'like', '%' . $input . '%');
});
})
->get();
Suppose, Your search input field name is q.
function name(Request $request){
$query = User::select();
if($request->q && $request->q !=''){
// if you search
$keyword = $request->q;
$query = User::with('Profile')->whereHas('Profile', function($q) use
($keyword){
$q->where('gender', 'like', "%{$keyword}%" );
});
}
$query->latest('id')->paginate();
}

Resources