Laravel 6 query same table with different where clause - php

I have campaign_report table like this
Schema::create('campaign_report', function (Blueprint $table) {
$table->bigIncrements('id');
$table->date('report_date');
$table->bigInteger('user_id');
$table->bigInteger('campaignId');
$table->double('cost',12,2);
$table->timestamps();
});
I am trying to get all yesterday's campaign reports.
$campaignReports = CampaignReport::where(['report_date' => "$yesterday", 'user_id' => Auth::user()->id])->orderBy('report_date', 'desc')->paginate(25);
Above query is returning all campaigns where report_date is equal to $yesterday.
Along with this query I also want to get the cost value of each campaign where report_date is day before yesterday matching the campaignId column. I want to show the difference of cost between yesterday's campaigns and day before yesterday's campaigns.
like
foreach($campaignReports as $campaignReport)
{
$difference = $campaignReport->cost - $campaignReport->dayBeforeYesterdayCost;
}
Can anyone help me in building this query using Query Builder or Eloquent?

You can write a relation in your CampaignReport model that calculate difference between yesterday's cost and the day before that
public function dayBeforeYesterdayCost() {
$dayBeforeYesterday = Carbon::parse($this->report_date)->subDays(1); //return date of day before yesterday
$dayBeforeYesterdayCost = CampaignReport::where('campaignId', $this->campaignId)
->where('report_date', $dayBeforeYesterday)
->first();
return $dayBeforeYesterdayCost ? $dayBeforeYesterdayCost->cost : 0;
}
public function lastDayDifference() {
$difference = $this->cost - $this->dayBeforeYesterdayCost;
return $difference;
}
Now you can return $campaignReports with lastDayDifference relation like this:
$campaignReports = CampaignReport::where(['report_date' => "$yesterday", 'user_id' => Auth::user()->id])
->with('lastDayDifference')
->orderBy('report_date', 'desc')
->paginate(25);
At the end you have one object attached to your every single $campaignReport

Group by date(report_date) which will just give you the date part, order by the same descending, then just take the values for yesterday and the day before. Something like:
CampaignReport::select(DB::raw('date(report_date) report_date', DB::raw('count(*) as count'))
->where('report_date','>=',$twoDaysAgo)
->where('user_id', Auth::user()->id])
->groupBy('report_date')
->orderBy('report_date', 'desc');

Related

whereMonth failing to retrieve appointment dates by month

I have two models in my application, Appointment and Date, an appointment has many dates and a date belongs to an appointment, now I want to search for appointments with dates which were created in a specific month, I do this by looking at appointments with dates, where this dates fullDate field is equal to the passed month, I use eloquent whereMonth for this.
Sadly the functions returns no results despite being results, I suspect this might be because Date model fullDate field is a string instead of a timestamp so maybe that's why it's failing, I tried casting fullDate to timestamp but I'm getting the same results.
fullDate is a string like this: "26-3-2020".
This is my controller method:
public function list2(Request $request)
{
$month = $request->input('month');
$appointments = Appointment::whereHas('dates', function ($query) use ($month){
$query->whereMonth('fullDate', $month);
})->with(['user'])->latest()->paginate($request->input('paginate'));
}
Date model migrations:
public function up()
{
Schema::create('dates', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('appointment_id')->index();
$table->foreign('appointment_id')->references('id')->on('appointments')->onDelete('cascade')->onUpdate('cascade');
$table->string('fullDate');//34-3-2020
$table->timestamps();
});
}
Any idea why it's failing.
fullDate column type should be timestamp,
and you should add this in the Date model:
protected $dates = [
'fullDate',
];

Laravel Eloquent get where doesnt have, search where has when not null

This question is really hard to word, so I apologise for the title!
Lets say I have a Rooms model and a Bookings model, 1 room can have many bookings.
I am building a table with filters, and I need to be able to run a filter on the booking relationship IF there is a booking, else grab the record anyway.
Lets say my room has a booking relationship like so
public function latestBooking(){
return $this->hasOne('App\Models\Bookings', 'room_id', 'id')
->orderBy('expiry_date', 'DESC')->limit(1);
}
The above relationship gets me the latest booking.
I'm running a 'vacant from' filter like so
if ($request->has('filters.vacant_from')) {
$rooms = $rooms->whereHas('latestBooking', function ($query) use ($request) {
$query->where('expiry_date', '<', Carbon::createFromFormat('d/m/Y',$request->input('filters.vacant_from'))->format('Y-m-d'));
});
}
The issue is that this only gets rooms that have a booking and are available after the date specified. I need it to be able to search all rooms, if it does have a booking, check if the expiry date is after the date specified, if it doesn't have a latest booking, get it anyway as its a vacant room.
Basically how would I structure my filter function so that it runs like this
Search all rooms, if it has a latest booking, check its expiry date is after the date specified and only grab it if its true/vacant, if it doesn't have a latest booking then grab it anyway as it is vacant
I have a suggestion for you regarding your latestBookingRelationship. You should create another relationship and add a greater than today condition to it and maybe name it activeLatestBooking.
Then, your latest Booking should comprise all booking rooms irrespective of whether their booking is active or not.
public function activeLatestBooking(){
return $this->hasOne('App\Models\Bookings', 'room_id', 'id')
->where('expiry_date', '>', date('d/m/Y', strtotime('today')))->orderBy('expiry_date', 'DESC')->limit(1);
}
public function latestBooking(){
return $this->hasOne('App\Models\Bookings', 'room_id', 'id')
->orderBy('expiry_date', 'DESC')->limit(1);
}
Then, to answer your question:
if ($request->has('filters.vacant_from')) {
$rooms = $rooms->whereHas('latestBooking', function ($query) use ($request) {
$query->where('expiry_date', '<', Carbon::createFromFormat('d/m/Y',$request->input('filters.vacant_from'))->format('Y-m-d'));
})->orWhereDoesntHave('latestBooking');
}
What the filter query does is this: It gets all latest bookings whose expiry_date is less than the vacant_from date...and the orWhereDoesntHave gets all rooms that have never been booked.
the booking relationship should be like this,
public function latestBooking(){
return $this->hasMany('App\Models\Bookings')->orderBy('expiry_date', 'DESC');
}
as this is a one to many relationship. laravel relationship
and you can write your filter like this,
if ($request->has('filters.vacant_from')) {
$rooms = $rooms->whereHas('latestBooking', function ($query) use ($request) {
$query->whereDate('expiry_date', '<', Carbon::createFromFormat('d/m/Y',$request->input('filters.vacant_from'))->format('Y-m-d'));
});
}
you can use whereDate to run date queries in laravel. Hope this helps
Assuming you have hasMany relation between Rooms and Bookings model with name bookings
$rooms = Rooms::whereHas('bookings', function ($query) use ($request) {
$query->whereDate('expiry_date', '<', Carbon::createFromFormat('d/m/Y',$request->input('filters.vacant_from'))->format('Y-m-d'));
})->orWhereDoesntHave('bookings')->get();

If to compare two dates using Carbon on Laravel, a date from a table and a now() instance

I'm trying to display some items from a table and I'm ordering by the time they begin, I only want to show the next three items starting from now(). Here is my controller function:
Probably the whole thing is completely wrong, but still, any help will be greatly appreciated.
public function next(Request $request)
{
$eventos = Event::orderBy('start','asc');
$eventTime = Carbon::createFromDate($eventos->start);
$mytime = Carbon::now();
if($eventTime > $mytime){
$eventos = paginate(3);
return view('evento.next',compact('eventos'));
}
}
public function next(Request $request)
{
$eventos=Event::where('start','>=',Carbon::now()) // select all recodrs where start Time more than now date
->orderBy('start','asc') // order all records by asc
->take(3) // take first 3 record
->get(); // now get the result
return view('evento.next',compact('eventos'));
}

Getting specific date ranges from database in Laravel

I need to get results from a DB divided by dates such as today, yesterday, this week, last week, etc.
I can easily do this with whereRaw and some SQL:
whereRaw('Date(created_at) = CURDATE()')->get();
I wonder if there is an easier, proper way to do this with Eloquent.
You could create a scope for a particular class like this:
public function scopeYourQuery($query, $user) {
return $query->where('user_id', $user->id)->orderBy('created_at', 'desc')->first();
}
This just gets the first item of a descending ordered list ordered by created_at date per user.
If you wanted something that was between date ranges? You just pass in your date and extend it a bit with some PHP, maybe something like this would work:
public function scopeSomeDateQuery($query, $fetch_date, $user)
{
//clone the users chosen month - so we can make the range until the following month
$also_fetch_date = clone $fetch_date;
$next_month = $also_fetch_date->addMonth();
$next_month = $next_month->format('Y-m-d');
$fetch_date = $fetch_date->format('Y-m-d');
//return the query for the monthname
return $query->orderBy('created_date')->where('created_date', '>=', $fetch_date)->where('created_date', '<', $next_month)->where('user_id', $user->id);
}
This would look in a monthly range (per user) to get an ordered list of items with a created_date in that range.

Laravel groupBy

I'm trying to redesign my Laravel 4.2 code and like to group a list from results over the last days.
code:
public function getTrending($type = null, $category = null)
{
$posts = $this->posts($type, $category)->with('comments', 'votes', 'category', 'user', 'votes.user')
->leftJoin('votes', 'posts.id', '=', 'votes.post_id')
->leftJoin('comments', 'posts.id', '=', 'comments.post_id')
->select('posts.*', DB::raw('count(comments.post_id)*7 + count(votes.post_id)*30 + posts.views as popular'))
->groupBy('posts.id')->with('user')->orderBy('popular', 'desc')->whereMonth('posts.created_at', '>=', date('n', strtotime('-1 month')))
->paginate(perPage());
return $posts;
}
I want to group the results as it is (relevance: comments, votes, visit) + grouping the results on a daily base.
Like:
Today (with Date xx.xx.xx)
result 1 (Max Votes, Comment, ...)
result 2
result 3
Yesterday (with Date xx.xx.xx)
result 4 (Max Votes, Comments, ...)
result 5
result 6
Is this possible?
You can use Carbon;
->groupBy(function($date) {
return Carbon::parse($date->created_at)->format('Y'); // grouping by years
//return Carbon::parse($date->created_at)->format('m'); // grouping by months
});
No I don't believe you can group your data in a single query like that.
Assuming your code is giving you the dataset you desire, without grouping by date, I would loop over the dates I want and get the data for every day and format it with the date heading etc.

Categories