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)'));
});
}
Related
I have the following error in my code which I'm having trouble figuring out. I would appreciate if anyone could help. What I am trying to do is add validation to the working hours that have been input by an employee. In my create appointment form I have input the following details;
however the following error is returned;
Call to a member function provides_service() on null
in AppointmentsController.php (line 63)
I'm not sure why this is occurring as the data exists in my db;
AppointmentsController - store method
public function store(StoreAppointmentsRequest $request)
$employee = \App\Employee::find($request->employee_id);
$working_hours = \App\WorkingHour::where('employee_id', $request->employee_id)->whereDay('date', '=', date("d", strtotime($request->date)))->whereTime('start_time', '<=', date("H:i", strtotime("".$request->starting_hour.":".$request->starting_minute.":00")))->whereTime('finish_time', '>=', date("H:i", strtotime("".$request->finish_hour.":".$request->finish_minute.":00")))->get();
if($employee->provides_service($request->service_id))
return redirect()->back()->withErrors("This employee doesn't provide your selected service")->withInput();
if($working_hours->isEmpty())
return redirect()->back()->withErrors("This employee isn't working at your selected time")->withInput();
$appointment = new Appointment;
$appointment->client_id = $request->client_id;
$appointment->employee_id = $request->employee_id;
$appointment->start_time = "".$request->date." ".$request->starting_hour .":".$request->starting_minute.":00";
$appointment->finish_time = "".$request->date." ".$request->finish_hour .":".$request->finish_minute.":00";
$appointment->comments = $request->comments;
$appointment->save();
return redirect()->route('admin.appointments.index');
}
halo, i have data and want to display it like picture below
there are two models relationship, Person and Installment.
this is Person model:
class Person extends Model
{
protected $table = 'person';
public function angsuran()
{
return $this->hasMany(Installment::class);
}
}
this is Installment model:
class Installment extends Model
{
protected $table = 'installment';
public function person()
{
return $this->belongsTo(Person::class);
}
}
and this is my controller to querying and display data
$data = Person::with('angsuran')
->whereHas('angsuran', function ($q) {
$q->whereBetween('installment_date', [\DB::raw('CURDATE()'), \DB::raw('CURDATE() + INTERVAL 7 DAY')])
->where('installment_date', '=', function () use ($q) {
$q->select('installment_date')
->where('status', 'UNPAID')
->orderBy('installment_date', 'ASC')
->first();
});
});
return $data->get();
it show error unknow colum person.id in where clause
please help. thanks.
As the comment said, you need to put $q as a parameter to the Closure.
When using subqueries, it's useful to tell the query builder which table it is supposed to query from.
I've rewritten your query. It should achieve what you're looking for. Also, changed the CURDATE to Carbon objects.
today() returns a datetime to today at 00:00:00 hours. If you need the hours, minutes and seconds, replace today() by now().
$data = Person::with('angsuran')
->whereHas('angsuran', function ($subquery1) {
$subquery1->where('installment_date', function ($subquery2) {
$subquery2->from('installment')
->select('created_at')
->where('status', 'UNPAID')
->whereBetween('installment_date', [today(), today()->addWeeks(1)])
->orderBy('installment_date')
->limit(1);
});
});
Using with and whereHas you will end up with two query even if you have limit(1) in your subQuery and the result will show all 4 installment related to the person model. also I don't think you can order on the subquery, it should be before the ->get
so here's i've rewritten your code
$callback = function($query) {
$query->whereBetween('installment_date', [today(), today()->addDays(7)])
->where('status', 'UNPAID')
->orderBy('installment_date');
};
$data = Person::whereHas('angsuran', $callback)->with(['angsuran' => $callback])->get();
or you can use query scope. please see this answer Merge 'with' and 'whereHas' in Laravel 5
Can you give an idea?
I have two tables in to postgresql DB.
The are filled with recods by two separate csv files. But the records of the first csv file are with local timestamp. The second csv file is with timestamps UTC.
So I need to change the time in local of the view in this table that is filled with records with timezone UTC. I used to deal with that problem before using laravel with this code in every page that I need to do that, for example:
date_default_timezone_set('Europe/Sofia');
The controller:
function getdata_chart(Request $request)
{
$start_date = date('d-m-Y 00:00:00');
$end_date = date('d-m-Y 23:59:59');
if($request->start_date != '' && $request->end_date != '')
{
// if user fill dates
$dateScope = array($request->start_date ." 00:00:00", $request->end_date ." 23:59:59");
} else {
// default load page - today
$dateScope = array($start_date, $end_date);
};
$students = MeasCanal::whereBetween('recordtime', $dateScope)
->selectRaw('recordtime')
->selectRaw('max(formattedvalue) filter (where fullname = \'Данни.Кота\') as iazovir')
->selectRaw('max(formattedvalue) filter (where fullname = \'Данни.Температура\') as temperatura350')
->where(function ($query) {
$query->where('fullname', 'like', "Язовир.Данни.Кота")
->orWhere('fullname', 'like', "ГСК_11_350.Данни.Температура");
})
->groupBy('recordtime')
->orderBy('recordtime')
->get();
return response()->json($students);
}
return response()->json($students);
}
Update your Model MeasCanal and add the following :
Import and use :
use Carbon\Carbon;
Add Function :
/**
* Get the user's recordtime.
*
* #param string $value
* #return string
*/
public function getRecordtimeAttribute($value)
{
return Carbon::parse($value)->timezone('Europe/Sofia')->toDateTimeString();
}
I'm not sure this is what you want but i think you can get the idea.
First Method,
You can use accessor;
public function getCustomTimestampAttribute($value)
{
// you can use your logic here to set your timezone by table
$timezone = 'Europe/Sofia';
return Carbon::parse($this->custom_timestamp)->timezone($timezone)->toDateTimeString();
}
then you can get the value like: $model->custom_timestamp
Second Method,
You can use map;
$customDates = $dates->map(function ($date, $key) {
$date->custom_timestamp = Carbon::parse($date->custom_timestamp)->timezone('Europe/Sofia')->toDateTimeString();
return $date;
});
EDIT
In your model(MeasCanal) set recordtime attribute;
public function getRecordtimeAttribute($value)
{
// you can use your logic here to set your timezone by table
$timezone = 'Europe/Sofia';
return Carbon::parse($this->recordtime)->timezone($timezone)->toDateTimeString();
}
then you can simply see the result after the query in your controller like
dd($students);
or even simpler to see:
dd($students->first()->recordtime); // first matched rows recordtime attr.
Note: you cant use accessors with raw queries you should use eloquent models btw.
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.
im using laravel eloquent to update a record in a database table. Im passing in a parameter of 52 which is the id of the record I want to update (primary key).
I am printing the query to check which record its finding and its printing the record with the id of 13 and then when i check the table, id 13 has been updated.
protected $connection = 'sqlsrv';
protected $table = 'todo';
public $timestamps = false;
public static function complete($todoId, $userId)
{
$now = new DateTime();
$query = Self::join('todoTypes', 'todo.typeId', 'todoTypes.id')
->where('todoTypes.canComplete', 1)
->whereNull('todo.completedDate')
->find(52);
$query->where(function ($query) use ($now)
{
$query->whereNull('cancelDate')
->orWhere('cancelDate', '>', $now);
});
if ($query)
{
$query->completedDate = $now;
$query->save();
}
}
How about trying like this?
The query after using find did not make any sense since find returns the first object not a query builder instance.
public static function complete($todoId, $userId)
{
$now = new DateTime();
$object = Self::join('todoTypes', 'todo.typeId', 'todoTypes.id')
->where('todoTypes.canComplete', 1)
->whereNull('todo.completedDate')
->where(function ($query) use ($now) {
$query->whereNull('cancelDate')
->orWhere('cancelDate', '>', $now);
})->find(52);
if ($object) {
$object->completedDate = $now;
$object->save();
}
}
I have managed to fix this by just adding a select at the start
select('todo.id', 'todo.completedDate')
It seems it was getting the right row, but displaying the id as something else.
When I took out the join and the joins where clause, it worked. I suspect it was using the id of the joint row from the todoTypes table as that was 13.