I want to save two time interval in my database. where it will check the database and if someone already booked that time it won't save the time whereas if it's empty it will save time which user will give as a input.
Eg. A user want to book the schedule 8:00 to 8:30, while saving into
the database it will check in the database whether someone already take
that time or not, if it's not then it will save otherwise it won't. Meanwhile
user can't give input even in 8:15 also.
How do i solve this overlapping problem?
here is the controller code I have used, it doesn't running though:
public function postAllocateRoom(Request $request)
{
$classRoom = new ClassRoom();
$classRoom->department_id=$request->Input(['department_id']);
$classRoom->room_id=$request->Input(['room_id']);
$classRoom->course_id=$request->Input(['course_id']);
$classRoom->day_id=$request->Input(['day_id']);
$classRoom->start=$request->Input(['start']);
$classRoom->end=$request->Input(['end']);
$startTime = Carbon::parse($request->input('start'));
$endTime = Carbon::parse($request->input('end'));
$classRoomCount = ClassRoom::where(function ($query) {
$query->where('start', '>=', $startTime)
->where('end', '<=', $startTime); })->count();
$messages ="Class Room Already Taken";
if ($classRoomCount > 0) {
return redirect('allocateRoomPage',$message);
}
else {
$classRoom->save();
return redirect('allocateRoomPage');
}
}
The rule for time overlapping is simple (see here for a complete graphic explanation):
start1 < end2 AND end1 > start2
So your query can be:
$classRoomCount = ClassRoom::where
(
function( $query ) use( $startTime, $endTime )
{
$query->where( 'start', '<', $endTime )
->where( 'end', '>', $startTime);
}
)->count();
Firstly, to be able to have access to $startTime and $endTime within the query closure you will need to pass them through using the use construct i.e.
function ($query) use ($startTime, $endTime)
The following should work to get the correct counts for classrooms booked between certain times:
$classRoomCount = ClassRoom::where(function ($query) use ($startTime, $endTime) {
$query
->where(function ($query) use ($startTime, $endTime) {
$query
->where('start', '>=', $startTime)
->where('end', '<', $startTime);
})
->orWhere(function ($query) use ($startTime, $endTime) {
$query
->where('start', '<', $endTime)
->where('end', '>=', $endTime);
});
})->count();
Hope this helps!
Related
My table column data type is Date and the date format is "2022-05-25". My Query is
$customers = Customer::with(['outstanding_invoices', 'address', 'rep'])
->where('status', 'A');
$from_date = Carbon::parse($from_date)->format('Y-m-d');
$end_date = Carbon::parse($end_date)->format('Y-m-d');
$customers->whereHas('outstanding_invoices', function ($query) use ($from_date, $end_date) {
$query->whereBetween('invoice_date', [$from_date, $end_date]); //* 1
// $query->where('invoice_date', '>=', $from_date); //* 2
// $query->where('invoice_date', '<=', $end_date);
// $query->whereDate('invoice_date', '>=', $from_date); //* 3
// $query->whereDate('invoice_date', '<=', $end_date);
});
$customers = $customers->get();
I have tried below three commented options but did not filter to the dates.
I've got a query in my Laravel project that returns a collection of data from my database between two dates, it's then grouped by the hour (but I can change this to my liking), I'd now like to return the "dates" for data before they existed in the database as a way of building up a list of dates that I can display in my web page, eve though there will be no data for these days, my chart would look consistent.
As an example:
I want to see the past 30 days of data as a history, but the first 20 days of this period have no data yet, I still need to return the date keys for these days, except with just no data in them.
My current code is as follows (I'm using Carbon):
$uptimeData = UptimeChecks::where('user_id', 1)
->where('monitor_id', 1)
->where('checked_at', '>=', '2021-01-01 00:00:00')
->where('checked_at', '<=', '2021-01-30 23:59:59')
->orderBy('checked_at', 'asc')
->select('event', 'checked_at')
->get();
$from = Carbon::now()->subDays(60);
$period = CarbonPeriod::create($from, '2021-01-30 23:59:59');
$dates = $period->toArray();
foreach ($dates as $key => $date) {
$dates[$key] = Carbon::parse($date)->format('Y-m-d');
}
$uptimeData = collect($uptimeData);
$uptimeData = $uptimeData->merge($dates);
$uptimeDataTimeline = $uptimeData->groupBy(function ($item, $key) {
if (isset($item->checked_at)) {
$date = Carbon::parse($item->checked_at);
} else {
$date = Carbon::parse($item);
}
return $date->format('Y-m-d');
});
Even though there would be no entries to display a "checked_at" column, can this be spoofed with the date for that day with no data?
Update 03/05 # 20:30
I've updated my description to reflect the latest attempt to solve this problem, I appear to have constructed what I need, however, have some issues:
Where I'm looping over my $dates is there a way to build up some structure within each item so I don't have to do if/else checks on all my variables and keys?
For some reason, the "fake" dummy dates are being added after the real data, e.g: 1st Jan, 2nd Jan, 30th Dec ... how can I reverse this?
One way to achieve this is by creating a collection of the dates for the time period you want, and then merging the results of a query grouped by date into it.
Here's an example:
$from = '2021-01-01';
$to = '2021-01-31';
$period = CarbonPeriod::create($from, $to);
$dates = collect($period->toArray())->mapWithKeys(function ($date) {
return [$date->format('Y-m-d') => []];
});
// $dates = ['2021-01-01' => [], '2021-01-02' => [], ...etc]
$uptimeChecks = UptimeChecks::query()
->where('user_id', 1)
->where('monitor_id', 1)
->whereBetween('checked_at', [$from, $to])
->orderBy('checked_at', 'asc')
->select('event', 'checked_at')
->get();
$uptimeDates = $uptimeChecks->groupBy(function ($item, $key) {
return $item->checked_at->format('Y-m-d');
});
// $uptimeDates = ['2021-01-02' => ['event1', 'event2'], ...etc]
$uptimeData = $dates->merge($uptimeDates);
// $uptimeData = ['2021-01-01' => [], '2021-01-02' => ['event1', 'event2'], ...etc]
This assumes you are casting the checked_at field to a date in your UptimeChecks Model.
Im currently building a reservation system for a restaurant and i have a question regarding edge cases in the reservation. to filter out tables that are not available i try to get the reservations and filter out the tables. for example, if reservation a starts at june 17 11:00 and ends june 17 12:00
you should not be able to book that table for that time period, however you should be able to end an earlier reservation at 11:00 and start a new reservation at 12:00 for that table.
this is the code that i had in laravel that did this (sort of):
$startDate = $request->query('start_date');
$endDate = $request->query('end_date');
$people_amount = $request->query('people_amount');
$reservation_id = $request->query('reservation_id');
$tables = Table::all();
$reservations = Reservation::whereBetween('start_datetime', [$startDate, $endDate])->orWhereBetween('end_datetime', [$startDate, $endDate])->get();
this worked perfectly except it wil not account for edge cases so i did this:
$reservations = Reservation::where([['start_datime', '>', $startDate],
['start_datetime', '<', $endDate]
])->orWhere([['start_datetime', '>', $startDate],
['end_datetime', '>', $startDate]]);
somewhere i went wrong but for the life of me i cant figure it out. any help would be greatly appreciated!
(this is the entire code):
public function showTables(Request $request)
{
$startDate = $request->query('start_date');
$endDate = $request->query('end_date');
$people_amount = $request->query('people_amount');
$reservation_id = $request->query('reservation_id');
$tables = Table::all();
// $reservations = Reservation::whereBetween('start_datetime', [$startDate, $endDate])->orWhereBetween('end_datetime', [$startDate, $endDate])->get();
// dd($reservations);
$reservations = Reservation::where([['start_datetime', '<', $startDate],
['start_datetime', '>', $endDate]
])->orWhere([['start_datetime', '<', $startDate],
['end_datetime', '<', $startDate]])->get();
if (isset($reservation_id)) {
$reservations = $reservations->filter(function ($item) use ($reservation_id) {
return $item->id != $reservation_id;
});
}
// dd($reservations);
foreach ($reservations as $key => $reservation) {
foreach ($tables as $key => $table) {
if ($table->seats_amount < $people_amount) {
unset($tables[$key]);
}
if ($table->id === $reservation->table_id) {
unset($tables[$key]);
}
}
}
TableCollection::wrap('tables');
return new TableCollection($tables);
}
edit, the fix:
$reservations = Reservation::where([['start_datetime', '>', $startDate],
['start_datetime', '<', $endDate]
])->orWhere([['end_datetime', '>', $startDate],
['end_datetime', '<', $endDate]])->orWhere([['start_datetime', '<', $startDate],
['end_datetime', '>', $startDate]])->orWhere([['start_datetime', '=', $startDate],
['end_datetime', '=', $endDate]])->get();
I want to display in the admin panel statitics about users and other things in the database.
For example to show how many users were registered today, this month etc.
For now I am doing this with the users for today the following way:
$users = User::where('admin', 0)->get();
$usersRegisteredToday = array_filter($users->toArray(), function ($user) {
$registerDate = \DateTime::createFromFormat('Y-m-d H:i:s', $user['created_at']);
$registerDate->setTime(0,0,0);
$today = new \DateTime();
$today->setTime(0,0,0);
$diff = $today->diff($registerDate);
$diffDays = (integer)$diff->format("%R%a"); // Extract days count in interval
return $diffDays == 0;
});
return view('admin.index', compact("users", "usersRegisteredToday"));
And in the view:
<p class="text-no">Today: {{ count($usersRegisteredToday) }} </p>
I wonder if there is a better, simpler and faster way to do this, because I think if I get the information for the other things that way it will be very slow and heavy. So i want to know the best and lightest way to do this.
As of Laravel 5.3 we can use whereDate / whereMonth / whereDay / whereYear
For example to get records created today:
$users = User::whereDate('created_at', DB::raw('CURDATE()'))->get();
Possibly a similar question is asked here: Get only records created today in laravel
$todayStart = (new Carbon())->setTime(0, 0);
$todayEnd = (new Carbon())->setTime(23, 59, 59);
$users = User::where('admin', 0)
->where('created_at', '>=', $todayStart)
->where('created_at', '<=', $todayEnd)
->get();
You could use query scopes which would make it even better. Inside User model:
class User extends Model
{
public function scopeCreatedBefore(Carbon $date)
{
return $this->where('created_at', '<=', $date);
}
public function scopeCreatedAfter(Carbon $date)
{
return $this->where('created_at', '>=', $date);
}
}
And for the usage:
$todayStart = (new Carbon())->setTime(0, 0);
$todayEnd = (new Carbon())->setTime(23, 59, 59);
$users = User::where('admin', 0)
->createdAfter($todayStart)
->createdBefore($todayEnd)
->get();
Its quite easy to do it. Im doing this in laravel 5.6
We are working in controller here. Lets say $date1 and $date2 is your range.
First, parse the date to carbon
$olddate = Carbon::parse($date1)->format('Y-m-d');
$newdate = Carbon::parse($date2)->format('Y-m-d');
Now, we get the users within that date range.
$users = Users::latest()
->whereBetween('created_at', array($olddate, $newdate))
->orderBy('id', 'desc')
->get(); // or count if you just want to count
basically, the function will look like below
public function betweendates(Request $request)
{
// get dates from request
$date1= $request->olddate;
$date2= $request->newdate;
// parse date to carbon
$olddate = Carbon::parse($date1)->format('Y-m-d');
$newdate = Carbon::parse($date2)->format('Y-m-d');
// the magic stuff
$users = Users::latest()
->whereBetween('created_at', array($olddate, $newdate))
->orderBy('id', 'desc')
->count();
return view('users.dashboard', compact('users'));
}
$datetime = new DateTime('today');
$datetime->modify('+2 day');
$expired_tags = DB::table('tags')
->where('active', '=', 1)
->where('expiry_date', '=', $datetime)
->get();
I'm trying to understand how I can ask:
Give me all tags that are two days away from being expired. But the above seems to be taking the Hour, Minute and Second into account ... I simply need to ask for the Year, Month, Day and compare that aspect of the two dates.
Okay, so I figured out a great way of doing what I want ...
$starting_time = new DateTime('today');
$starting_time->modify('+1 day');
$ending_time = new DateTime('today');
$ending_time->modify('+1 day +23 hours +59 minutes +59 seconds');
$expired_tags = DB::table('tags')
->where('active', '=', 1)
->whereBetween('expiry_date', array($starting_time, $ending_time))
->get();
This grabs all records that have a datetime anytime during the next calendar day! :)
$today = new DateTime('today');
$expired_tags = DB::table('tags')
->where('active', '=', 1)
->where('expiry_date', '>=', $today->modify('+1 day')->format('Y-m-d'))
->where('expiry_date', '<', $today->modify('+1 day')->format('Y-m-d'))
->get();