I have a set of working hours and want to generate a list of suggested shifts, all based on the current 'now' time and working backwards into the past.
E.g hours template:
$templateShifts = collect([
(object)[
"id" => 1,
"from_day" => 1, // mon
"from_time" => "09:00:00",
"until_day" => 1,
"until_time" => "12:00:00",
],
(object)[
"id" => 2,
"from_day" => 1, // mon
"from_time" => "13:00:00",
"until_day" => 1,
"until_time" => "17:00:00",
],
(object)[
"id" => 3,
"from_day" => 2, // tue
"from_time" => "09:00:00",
"until_day" => 2,
"until_time" => "17:00:00",
],
(object)[
"id" => 4,
"from_day" => 4, // thur
"from_time" => "09:00:00",
"until_day" => 4,
"until_time" => "17:00:00",
],
(object)[
"id" => 5,
"from_day" => 5, // fri
"from_time" => "09:00:00",
"until_day" => 5,
"until_time" => "17:00:00",
]
]);
If today is thursday(4th jan) it should list date in reverse order:
- Thur 09:00 - 17:00 (4th jan)
- Tue 09:00 - 17:00 (2nd jan)
- Mon 13:00 - 17:00 (1st jan)
- Mon 09:00 - 12:00 (1st jan)
- Fri 09:00 - 17:00 (31st dec)
- Thur 09:00 - 17:00 (30th dec)
- etc
This code feels horrible but I couldn't find a way of repeating a collection loop once it reaches the end without copying the code.
// Paging
$total_count = 1000;
$on_page = 30;
$page = $request->get('page') ?: 1;
$skip = $on_page * ($page - 1);
// Find closest match in the past from now
$date = now();
$year = $date->year;
$weekNo = $date->weekOfYear;
$shifts = collect();
// Decrement week no
if ($skip) {
$weekNo -= $skip;
// Change year till positive weekNo
while ($weekNo < 1) {
--$year;
$date->subYear();
$weekNo += $date->isoWeeksInYear;
}
}
// First page
if (!$skip) {
// First search for shift today
$firstShiftIndex = $templateShifts->search(function ($item, $key) use ($date) {
return $item->from_day == $date->format('N') && $item->from_time <= $date->format('H:i:s');
});
$currentWeekNo = false;
if ($firstShiftIndex === false) {
// Loop back from today till find a matching day
for ($i = 1; $i <= 7; $i++) {
$date = $date->clone()->subDays(1);
$firstShiftIndex = $templateShifts->search(function ($item, $key) use ($date) {
return $item->from_day == $date->format('N');
});
if ($firstShiftIndex !== false) {
$year = $date->year;
$weekNo = $date->weekOfYear;
break;
}
}
}
$templateShifts->slice($firstShiftIndex)->each(function ($item, $key) use ($shifts, $date, $year, $weekNo) {
$shift_from = $date->clone()->setISODate($year, $weekNo, $item->from_day);
list($hour, $minutes) = explode(':', $item->from_time);
$shift_from->setTime($hour, $minutes);
// Crosses into next week/maybe year too
if ($item->until_day < $item->from_day) {
$weekNo++;
if ($weekNo < 1) {
--$year;
$date->subYear();
$weekNo = $date->isoWeeksInYear;
}
}
$shift_until = $date->clone()->setISODate($year, $weekNo, $item->until_day);
list($hour, $minutes) = explode(':', $item->until_time);
$shift_until->setTime($hour, $minutes);
if ($shift_from->toDateString() == $shift_until->toDateString()) {
$name = $shift_from->format('d/m/Y D H:i') . ' - ' . $shift_until->format('H:i');
} else {
$name = $shift_from->format('d/m/Y D H:i') . ' - ' . $shift_until->format('D H:i');
}
$shifts->push([
'id' => $item->id,
'text' => $name
]);
});
}
//
for($i=0; $i < $on_page; $i++) {
--$weekNo;
if ($weekNo < 1) {
--$year;
$date->subYear();
$weekNo = $date->isoWeeksInYear;
}
$templateShifts->each(function ($item, $key) use ($shifts, $date, $year, $weekNo) {
$shift_from = $date->clone()->setISODate($year, $weekNo, $item->from_day);
list($hour, $minutes) = explode(':', $item->from_time);
$shift_from->setTime($hour, $minutes);
// Crosses into next week/maybe year too
if ($item->until_day < $item->from_day) {
$weekNo++;
if ($weekNo < 1) {
--$year;
$date->subYear();
$weekNo = $date->isoWeeksInYear;
}
}
$shift_until = $date->clone()->setISODate($year, $weekNo, $item->until_day);
list($hour, $minutes) = explode(':', $item->until_time);
$shift_until->setTime($hour, $minutes);
if ($shift_from->toDateString() == $shift_until->toDateString()) {
$name = $shift_from->format('d/m/Y D H:i') . ' - ' . $shift_until->format('H:i');
} else {
$name = $shift_from->format('d/m/Y D H:i') . ' - ' . $shift_until->format('D H:i');
}
$shifts->push([
'id' => $item->id,
'text' => $name
]);
});
}