combining when() and whereBetween() methods in laravel query builder - php

I have a Model in Larevel that is taking in parameters for reporting total units in the database.
I want to be able to filter the units returned based on the $entity_ids and the $start and $end dates selected by the user.
entity_ids is working fine with a simple whereIn() method call, but the dates are causing some issue.
My code in Order.php Model is below:
public static function getAllOrdersForReporting($entity_ids, $start, $end) {
$orders = Order::select('all order information entered here')
->whereIn('orders.entity_id', $entity_ids)
->when($start && $end, function ($query, $start, $end) { //<-- Error Thrown Here
return $query->whereBetween('order_date', [$start, $end]);
})
->join('entities', 'entities.id', '=', 'ura_orders.entity_id')
->join('entity_address_information', 'entity_address_information.entity_id', '=', 'ura_orders.entity_id')->distinct()->get();
return $orders;
}
In my ReportingController.php I am entering in the following:
public function displayUnits() {
$entities = request()->entities_ids;
$start = request()->start_date;
$end = request()->end_date;
$orders = Ura_order::getAllOrdersForReporting($entities, $start, $end);
return view('reporting.pages.units', compact('entities', 'start', 'end', 'orders'));
}
However when I run this, I get the following error:
Too few arguments to function
App\Models\Order::App\Models{closure}(), 2 passed in
C:\xampp\htdocs\mywebsite\vendor\laravel\framework\src\Illuminate\Database\Concerns\BuildsQueries.php
on line 91 and exactly 3 expected
Not exactly sure what this error means, except that the Model is seeing only 2 errors passed in and it expected 3.
I marked the line where it is throwing the error up above in the code.
Any advice on how to get this to work? I know the 3rd parameter for when() is supposed to be a callback function, but not sure how to make this work.

You have to use variables in your callback function:
->when($start && $end, function ($query) use ($start, $end) {
return $query->whereBetween('order_date', [$start, $end]);
})

You can try with this code:
->when($start && $end, function ($query, $condition) use($start, $end) {
return $query->whereBetween('order_date', [$start, $end]);
})
As already pointed in the comments the tihrd parameter of a when() should be a function, with the use() statement you can pass the variables in the closure.

Related

Eloquent: has() condition against database value

I have a simple relationship between Bottles and InventoryItems:
InventoryItem.php:
public function bottles(): HasMany
{
return $this->hasMany(InventoryItemBottle::class);
}
I'm trying to query for InventoryItem's that have a bottles count of greater then a user entered threshold.
The user's input is saved in a JSONB. Part of the query looks like this and I've commented the problem line:
->when(
$filters['filter'] === 'show_above_max_threshold',
fn (Builder $query): Builder => $query->where(function (Builder $query): Builder {
return $query->whereColumn('info->quantity', '>', 'info->high_level_warning');
})
->orWhere(function (Builder $query): Builder {
return $query->has('bottles', '>', 'info->high_level_warning'); // stuck here
})
)
The has() method should help here, but how do I get the high_level_warning from the database to pass to it? Or is there another method I could use?
You can use the has function.
See if this helps you.
$threshold = 2;
$items = InventoryItem::has('bottles', '>=', $threshold)->get();

My Scope Filter doesn't works, I'm getting the result of getting a select * from, instead of filtering

I'm working on a small project using Laravel and Vuejs. I try to do a simple filter of ages
I send and I receive correctly my GET parameters (I've double-checked), I get the same result since I send different values.
it seems like my scopeWithFilters function doesn't work because I used the function toSql to see the query and the result was select * from users which means my scope function doesn't work.
This is my scope function :
public function scopeWithFilters($query, $minAge=Null, $maxAge=Null){
$query->when(is_int($minAge), function($query) use ($minAge){
$query->where('birthday_year', '<=', date('Y') - $minAge);
})->when(is_int($maxAge), function($query) use ($maxAge){
$query->where('birthday_year', '>=', date('Y') - $maxAge);
});
return $query;
}
This is my controller function :
public function filter(Request $request){
$query = User::WithFilters(
$request->input('minAge'),
$request->input('maxAge')
)->get();
return UserResource::collection($query);
}
after doing ->toSql() to see the query:
select * from users
PHP is case sensitive, so instead of User::WithFilters( try User::withFilters(. Check the documentation.
Also, you can have a "cleaner code" if you update your filters to this:
public function scopeWithFilters($query, int $minAge=null, int $maxAge=null){
return $query->when($minAge, function($query) use ($minAge) {
$query->where('birthday_year', '<=', date('Y') - $minAge);
})
->when($maxAge, function($query) use ($maxAge) {
$query->where('birthday_year', '>=', date('Y') - $maxAge);
});
}
If you are using PHP 8+, we could reduce your code to this (have in mind it is visual in this case, but maybe it is more readable for you too):
use Illuminate\Database\Eloquent\Builder; // Add this on top with your other USEs
public function scopeWithFilters(Builder $query, int $minAge = null, int $maxAge = null)
{
return $query->when(
$minAge,
fn(Builder $query) => $query->where('birthday_year', '<=', date('Y') - $minAge)
)
->when(
$maxAge,
fn(Builder $query) => $query->where('birthday_year', '>=', date('Y') - $maxAge)
);
}

How to find value within a range - laravel

I have two columns in a table like below
id start end point
1 50 70 5
2 80 100 7
How can find the value's range in my code below.. Now when i submit the mark (70), i want to find the range it belongs to so i can get the respective points.
lets say $marks = 70
public function getGrade($marks)
{
$grade_point = Grade::where(function ($query) use ($marks) {
$query->where('from', '<=', $marks);
$query->where('to', '>=', $marks);
return $grade_point->point;
}
With the code above i get the error
Object of class Illuminate\Database\Eloquent\Builder could not be converted to string
You need to send the query with a method like get(), first(), pluck('column'), value('column')....
lets say $marks = 70
public function getGrade($marks)
{
$grade_point = Grade::where('from', '<=', $marks)->where('to', '>=', $marks);
return (int)$grade_point->value('point');
}
the method value('column') returns the column's value of the firsts result or null.
You have to call ->first(), ->get() or ->all() to execute to the query:
// lets say $marks = 70
public function getGrade($marks)
{
$grade_point = Grade::where(function ($query) use ($marks) {
$query->where('from', '<=', $marks);
$query->where('to', '>=', $marks);
})->first();
return $grade_point->point;
}
Checkout the docs: https://laravel.com/docs/5.8/queries#retrieving-results

How use with() when also joining a table

I have the following tables (with only relevant fields):
devices
id
name
created_at
updated_at
device_reports
id
device_id
location
created_at
updated_at
I have a report with a number of filters on it that is already working, so I want to stick with the eloquent way of doing things. Here is Controller function:
public function devices(Request $request)
{
$devicesQuery = Device::with(['latestReport']);
if ($request->ajax())
{
if($request->input('start') && $request->input('start')!='')
{
$start_date = date('Y-m-d', strtotime($request->input('start')));
$end_date = date('Y-m-d', strtotime($request->input('end')));
$devicesQuery = $devicesQuery->lastReportBetween($start_date,$end_date);
}
$devices = $devicesQuery->paginate(10);
return Response::json(View::make('devices/table', array('devices' => $devices))->render());
}
}
The model's latestReport is defined as:
public function latestReport()
{
return $this->hasOne('App\Models\DeviceReport')->latest();
}
The model's function lastReportBetween is defined as:
public function scopeLastReportBetween($query, $start, $end)
{
$query = $query->join('device_reports AS dr', 'dr.device_id', '=', 'devices.id');
$query = $query->where('dr.id', '=', DB::raw('(SELECT max(dr2.id) FROM device_reports AS dr2 WHERE dr2.device_id = devices.id)'));
$query = $query->where(DB::raw("(IFNULL(dr.gps_time, dr.created_at))"), '>=', DB::raw("STR_TO_DATE('".$start."', '%Y-%m-%d')"));
$query = $query->where(DB::raw("(IFNULL(dr.gps_time, dr.created_at))"), '<=', DB::raw("STR_TO_DATE('".$end."', '%Y-%m-%d')"));
return $query;
}
When running the above with a start/end date selected, I get the correct records returned, but I don't get anything returned in "latestReport", but when I run the page without the date filters in place, it correctly returns the device information and the most recent report record in the latestReport class variable.
Can anyone help me understand how to change this code such that I do get the latestReport back when I also call the lastReportBetween function?
I figured out my problem. I should have been using "whereHas()" instead of manual joins and whatnot.
public function scopeLastReportBetween($query, $start, $end)
{
return $query->whereHas('latestReport', function($reportsQuery) use ($start, $end)
{
$reportsQuery->whereBetween('created_at', [$start, $end])
->where('device_reports.id', '=', DB::raw('(SELECT max(dr2.id) FROM device_reports AS dr2 WHERE dr2.device_id = device_reports.device_id)'));
});
}

Undefined Variable Multiple Query Scopes Laravel

This work perfect:
public function scopeHBO($query)
{
return $query ->where('network', '=', "hbo");
}
Call in Controller: It Works!
$events = Schedule::HBO()->orderBy('searchdate')->get();
When I add another Query Scope like so:
public function scopeHBO($query)
{
return $query
->where('network', '=', "hbo")
->where('searchdate', '>=', 'NOW()');
}
OR:
public function scopeDate($query)
{
return $query->where('searchdate', '>= ', 'NOW()');
}
Then call in the controller:
$events = Schedule::HBO()->Date()->orderBy('searchdate')->get();
I get an error: Undefined variable: event. I tried with with Raw MySql in the same model and it works. Whenever i add a query scope, does not matter what it is.. i get that same error Undefined variable: event.
NOW() is a function, so you need to use a raw query:
where('searchdate', '>=', DB::raw('NOW()'))
Then you can use the scopes. (Do note that I think scopeDate must be called as date(), not Date() - not 100 % sure on that though.)
This sounds less like a generic problem with Laravel, and more like a problem with you specific application.
My guess (which is a wild guess), is that adding that second where clause in your scope method
return $query
->where('network', '=', "hbo")
->where('searchdate', '>=', 'NOW()');
ended up creating a SQL query that returned 0 rows. Then, somewhere in your other code you're doing something like
foreach($events as $event)
{
//...
}
//referencing final $event outside of loop
if($event) { ... }
As I said, this is a wild guess, but the problem doesn't seem to be your query code, the problem seems to be the rest of your code that relies on the query returning a certain number of, or certain specific, rows/objects.

Categories