I have a table which is a combination of 3 tables being passed to my blade file.
$late_books = Borrow::join('books', 'borrows.book_id', '=', 'books.id')
->join('borrowers', 'borrows.borrower_id', '=', 'borrowers.id')
->where('borrows.late_return_status', '=', 1)
->where('borrows.return_date', '=', null)
->get(['borrowers.borrower_name', 'borrowers.IC', 'borrowers.phone_no' ,'books.ISBN', 'books.book_title', 'books.year','books.author', 'books.publisher_name',
'borrows.issue_date', 'borrows.due_date']);
Within the blade file, i need to add a button which has the fines.
$due_date = \Carbon\Carbon::parse($late_books->first()->due_date);
$today = \Carbon\Carbon::now();
$result = $due_date->diffInDays($today);
$fine = $result * 5;
The fine should be specific to each book borrowed, the current way ive done it shows same fine for all books.
return view('admin.latereturn', compact('late_books', 'search', 'fine'));
Im sure this question has been asked in some form before but im not exactly sure what to search. Sorry if it's a duplicate.
If i get you
you can Defining An Accessor for appending attribute inside your model as the following:
class Borrow extends Model
{
protected $appends = ['fine'];
public function getFineAttribute()
{
$due_date = \Carbon\Carbon::parse($this->due_date);
$today = \Carbon\Carbon::now();
$result = $due_date->diffInDays($today);
$fine = $result * 5;
return $fine;
}
}
and you can access fine attribute inside your blade as $model_instance->fine
#foreach($late_books as $lb)
<span> {{$lb->fine}} </span>
#endforeach
I hope this helpful for you
Related
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)'));
});
}
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.
Am trying to reuse a query but it fails.
In my method I have:
public function getPacked($from, $to){
$initquery = RealTimeTblTrucks::find()
->leftJoin('tbl_truck_history','tbl_truck_history.truck_id=tbl_trucks.id')
->where(["between","tbl_truck_history.created_at",$from,$to])
->andWhere(["tbl_truck_history.status"=>20]);
$data = [];
$data[SELF] =$initquery
->andWhere(["tbl_trucks.truck_category"=>28])
->count();
$data[NORMAL] = $initquery->andWhere(["tbl_trucks.truck_category"=>27])
->count();
$data[BULKER] = $initquery->andWhere(['in', 'tbl_trucks.truck_category', [26,34]])
->count();
return $data;
}
Now the first ($data[SELF]) returns the correct information but the next ones NORMAL and BULKER didn't return the correct information.
When I check on the raw query I can see that the last two are affected by the first one such that the new query at $data[NORMAL] contains a check for truck_category = 20 which should only be executed on the first array item (SELF).
How to refactor this to make it work?
Advantage of clone over creation a new object, is that, all properties will be copied into the new object instead of resetting them. This is quite useful when you use query builder.
public function getPacked($from, $to) {
$initquery = RealTimeTblTrucks::find()
->leftJoin('tbl_truck_history','tbl_truck_history.truck_id=tbl_trucks.id')
->where(["between","tbl_truck_history.created_at",$from,$to])
->andWhere(["tbl_truck_history.status"=>20]);
$data = [];
$querySelf = clone $initquery;
$data[SELF] = $querySelf
->andWhere(["tbl_trucks.truck_category"=>28])
->count();
$queryNormal = clone $initquery;
$data[NORMAL] = $queryNormal->andWhere(["tbl_trucks.truck_category"=>27])
->count();
$queryBulker = clone $initquery;
$data[BULKER] = $queryBulker->andWhere(['in', 'tbl_trucks.truck_category', [26,34]])
->count();
return $data;
}
Refer Yii2 clone detail
In the controller below, if I return $friendPosts (which has the post ids), the ids are shown in the view without problems.
But when I try to return the $sharedPosts (which has the whole row), nothing shows up in the view.
Controller
public function getProfile($email)
{
$myFriends = Auth::user()->friends()->lists('id');
$friendShares = Share::where('user_id',$myFriends)->get();
$friendPosts = $friendShares->lists('post_id');
$sharedPosts = Post::where('id', $friendPosts)->get();
return view('profile.index')
->with ('friendShares', $sharedPosts);
}
View
#foreach ($friendShares as $friendShares)
<p> {{$friendShares}}</p>
#endforeach
$myFriends = Auth::user()->friends()->lists('id');
$friendShares = Share::where('user_id',$myFriends)->get();
$friendPosts = $friendShares->lists('post_id');
$sharedPosts = Post::where('id', $friendPosts)->get();
should be
$myFriends = Auth::user()->friends()->lists('id');
$friendShares = Share::whereIn('user_id',$myFriends)->get();
$friendPosts = $friendShares->lists('post_id');
$sharedPosts = Post::whereIn('id', $friendPosts)->get();
You are working with more ids, not just one, so you have to use whereIn() which looks trough an array of values.
Next time it would be useful if you tell us what you actually wanted/tried to do with your code.
I have a model called School and it has many Students .
Here is the code in my model:
public function students()
{
return $this->hasMany('Student');
}
I am getting all the students with this code in my controller:
$school = School::find($schoolId);
and in the view:
#foreach ($school->students as $student)
Now I want to order the Students by some field in the students table. How can I do that?
You have a few ways of achieving this:
// when eager loading
$school = School::with(['students' => function ($q) {
$q->orderBy('whateverField', 'asc/desc');
}])->find($schoolId);
// when lazy loading
$school = School::find($schoolId);
$school->load(['students' => function ($q) {
$q->orderBy('whateverField', 'asc/desc');
}]);
// or on the collection
$school = School::find($schoolId);
// asc
$school->students->sortBy('whateverProperty');
// desc
$school->students->sortByDesc('whateverProperty');
// or querying students directly
$students = Student::whereHas('school', function ($q) use ($schoolId) {
$q->where('id', $schoolId);
})->orderBy('whateverField')->get();
you can add orderBy to your relation, so the only thing you need to change is
public function students()
{
return $this->hasMany('Student');
}
to
public function students()
{
return $this->hasMany('Student')->orderBy('id', 'desc');
}
To answer the original question, the students dynamic property can also be accessed as a relationship method.
So you have this to fetch all students:
$students = $school->students;
Now as a relationship method, this is equivalent:
$students = $school->students()->get();
Given this, you can now add in some ordering:
$students = $school->students()->orderBy('students.last_name')->get();
Since eloquent will be performing a join, make sure to include the table name when referencing the column to order by.
You can also add this to your students method if you want to set a default order that $school->students will always return. Check out the documentation for hasMany() to see how this works.
For Many to one relation I found one answer on:
https://laracasts.com/discuss/channels/eloquent/order-by-on-relationship
$order = 'desc';
$users = User::join('roles', 'users.role_id', '=', 'roles.id')
->orderBy('roles.label', $order)
->select('users.*')
->paginate(10);
this can save day... of anyone
You can use this like this:
$students = $school->students()->orderBy('id', 'desc');
You can also use
$students = $school->students()->orderBy('id', 'desc')->paginate(10);