Query Builder with multiple entry points - laravel

I have different filters I want to use for my model, but they are all optional.
if($foo) {
$model = Model::where('id', 1);
}
if($bar) {
$model = $model->where('age', 3);
}
So this code will only run if the first statement will success.
$model = Model::where('id', '<>', -1);
if($foo) {
$model->where('id', 1);
}
if($bar) {
$model->where('age', 3);
}
This would work, but it's dirty :(
So is it possible to save the Model to a variabel so I don't have to make a static call inside all if statements?

https://laravel.com/api/5.4/Illuminate/Database/Eloquent/Model.html#method_query
https://laravel.com/api/5.4/Illuminate/Database/Query/Builder.html#method_when
Model::query()->when($foo, function ($query) {
$query->where('id', 1);
})->when($bar, function ($query) {
$query->where('age', 3);
});

You could make your filters in a where function, this will group them all together nicely.
For example:
$models = Model::where(function ($query) use ($request) {
$query->where('id', '<>' -1);
if ($request->has('id')
$quer->where('id', $request->id);
if ($request->has('age'))
$query->where('age', $request->age);
})->get();

Related

Laravel Eloquent: When() on a JSONB column

I don't think I understand the proper use of when().
I'm trying to use it in this fashion:
I have a jsonb column (called info) which has multiple properties. I want to check if one of the values is 'Chemical' and perform some query. Otherwise, perform another query. This is how I am using it:
$query->when(
'info->type' === 'Chemical',
function ($query) {
return $query->has('bottles', 0);
},
function ($query) {
return $query->where('info->quantity', '<=', 0);
}
);
The first function would be the truthy value and the second function would be falsey. However, it never hits the first function.
What am I doing wrong? Is this not how you use when?
You are correct, the only error is that info->type is never going to be equal to Chemical because you are comparing strings.
So, whatever you write as the expression, it must literally be something that has nothing to do with the query.
when works as an alias of an if, so you don't need to break your query like this:
$query = Model::query();
if ($expression) {
$query->where('column_a', 1);
} else {
$query->where('column_a', 0);
}
$query->where('whatever', 123);
if ($expression2) {
$query->where('abc', 1);
}
Using when, it would be like this:
$query = Model::query()
->when(
$expression,
fn (Builder $query) => $query->where('column_a', 1),
fn (Builder $query) => $query->where('column_a', 0),
)
->when(
$expression2,
fn (Builder $query) => $query->where('abc', 1)
);
Following your example, you will need to get what info->type is, let's say you are able to get that from another part:
$infoType = 'value';
$query = Model::query()
->when(
$infoType === 'Chemical',
function ($query) {
return $query->has('bottles', 0);
},
function ($query) {
return $query->where('info->quantity', '<=', 0);
}
);
More about when on the documentation.
You can read more by just checking the when()'s source code (Laravel 9)

Multiple keywords search sql sentence not showing in Laravel8

I'm studying keyword search.
I successed single keyword search and now I'm trying to make multiple one.
as Half-width space keyword split.
I use this Middlewarefrom this website
https://qiita.com/logue/items/64c4b5545f76ef17de70
When I dd() . I can see keyword split are good.
but when I search function runs There is no sql sentence appear
and I can display empty result page.
Could you teach me correct code please?
Controller
public function order_adv()
{
$keyword = request('search_adv');
if(!empty($keywords)) {
foreach ($keywords as $keyword) {
$products = Product::when('w_m','like','%'.$keyword.'%');
}
}
return view('products.result_adv' , compact('products'))
->with('i', (request()->input('page', 1) - 1) * 5);
}
WEB.php
Route::get('products/search_adv', [ProductController::class, 'search_adv'])->name('search_adv');
Route::post('products/search_adv', [ProductController::class, 'order_adv'])->name('products.search_adv')->middleware('keyword');
You can use where call back method
public function order_adv()
{
$keywords =explode(' ',request('search_adv'));
$products = Product::when(count((array)$keywords),function($query)use($keywords){
$query->where(function($query)use($keywords){
foreach ($keywords as $keyword) {
$query->orWhere('w_m','like','%'.$keyword.'%');
}
});
})->get();
return view('products.result_adv' , compact('products'))
->with('i', (request()->input('page', 1) - 1) * 5);
}
$keywords = request('search_adv');
if (count($keywords) > 0) {
$products = Product::where(function($query)use($keywords) {
foreach ($keywords as $keyword) {
$query->orWhere('w_m', 'LIKE', "%{$keyword}%");
}
})->get();
}
In your case use where Clauses,
https://laravel.com/docs/8.x/queries#where-clauses
use when in condition statement,
https://laravel.com/docs/8.x/collections#method-when

How can I combine both of these conditions? in laravel

I'am new with laravel. How can I combine both of these conditions?
public function student($classroom_id)
{
$members = Classroom::findOrFail($classroom_id,)->members->load('role');
$members = User::where([
['role_id', 2]
])->get();
return response()->json($members);
}
Try this:
public function student($classroom_id)
{
$members = Classroom::whereHas('members.role', function ($query) {
$query->where('id', '2');
})->findOrFail($classroom_id)->members->load('role');
return response()->json($members);
}

I can't use variable in a function whereHas

I'm new with laravel. I can't use $class _id in a function whereHas. What should I do?
public function show($classroom_id)
{
$classrooms = Group::whereHas('members', function ($query) {
$query->where([['user_id', '=', Auth::id()], ['classroom_id', $classroom_id]]);
})->get();
return response()->json($classrooms);
}
See use (classroom_id)
$groups = Group::whereHas('natures', function($q) use($classroom_id)
{
$q->where('classroom_id', '=', $classroom_id);
});

Multilevel relationship whereHas on eloquent Model in Laravel

I'd like to find
Project::with('tasks.tags')->get();
where only projects with a particular id of tag return in the result set.
For ex. I'd like to find a project with tasks and tasks with tags with only id of 1. In other words, filter the tasks return inside of the Project - Task relationship.
I have tried various ways but have failed so far.
I have tried:
$project = Project::with('tasks.tags')->whereHas('tasks', function($query){
$query->whereHas('tags', function($query) {
$query->where('id', 1);
});
})->get();
And:
$project = Project::with('tasks.tags')->whereHas('tasks', function($query){
$query->whereHas('tags', function($query) {
$query->where('tag_id', 1);
});
})->get();
This is how the relationships are setup:
In Project.php
public function tasks()
{
return $this->hasMany(Task::class, 'project_id')->setEagerLoads([]);
}
In Task.php
public function tags()
{
return $this->morphToMany(Tag::class, 'taggable')->setEagerLoads([]);
}
Note that relationship between Task and Tags is of morphToMany.
Any pointers?
You would need to scope the eager loading as well. Something like the following should work:
$project = Project::with(['tasks.tags' => function ($query) {
$query->where('id', 1);
}])->whereHas('tasks', function ($query) {
$query->whereHas('tags', function ($query) {
$query->where('id', 1);
});
})->get();
Found the answer over here.
Project::with(['tasks' => function($q) {
$q->whereHas('tags', function($query) {
$query->where('tag_id', 1);
});
}])->get();

Resources