start = $_start->getTimestamp(); $this->end = $_end->getTimestamp(); } public function addAvailability(DateTime $_start, DateTime $_end) { $this->available[] = new TimeSlot($_start, $_end); // sort by start usort($this->available, function ($item1, $item2) { return $item1->start <=> $item2->start; }); // compact (join adjacent overlapping slots) // $this->vdump($this->available); $this->normalize(); $this->vdump($this->available); } public function removeAvailability(DateTime $_start, DateTime $_end) { $removeStart = $_start->getTimestamp(); $removeEnd = $_end->getTimestamp(); $cleaned = $this->removeEmbeddedInAvailSlot($removeStart, $removeEnd); if(!$cleaned) { for ($i=0; $iavailable); $i++) $this->available[$i]->processed = false; $this->removeStart($removeStart, $removeEnd); for ($i=0; $iavailable); $i++) $this->available[$i]->processed = false; $this->removeEnd($removeStart, $removeEnd); $this->removeEmbeddedInRemoveSlot($removeStart, $removeEnd); } // sort by start usort($this->available, function ($item1, $item2) { return $item1->start <=> $item2->start; }); $this->normalize(); $this->vdump($this->available); // add to unavailable $this->unavailable[] = new TimeSlot($_start, $_end); // $this->normalizeUnavailable(); } private function removeEmbeddedInAvailSlot($removeStart, $removeEnd) { for ($i=0; $iavailable); $i++) { // removeStart at or after slot start // removeEnd at or before slot end // split slot into 2 if ($removeStart >= $this->available[$i]->start && $removeEnd <= $this->available[$i]->end) { $newSlot = new TimeSlot(new DateTime(), new DateTime()); $newSlot->start = $removeEnd; $newSlot->end = $this->available[$i]->end; $this->available[$i]->end = $removeStart; array_splice($this->available, $i + 1, 0, [$newSlot]); return true; // nothing more to do } } return false; } private function removeEmbeddedInRemoveSlot($removeStart, $removeEnd) { $allDone = true; for ($i=0; $iavailable); $i++) { // removeStart at or before slot start // removeEnd at or after slot end // remove slot if ($removeStart <= $this->available[$i]->start && $removeEnd >= $this->available[$i]->end) { array_splice($this->available, $i, 1); $allDone = false; } } if(!$allDone) { $this->removeEmbeddedInRemoveSlot($removeStart, $removeEnd); // recurse till clean } return false; } private function removeStart($removeStart, $removeEnd) { $allDone = true; for ($i=0; $iavailable); $i++) { if($this->available[$i]->processed) continue; // removeStart at or after slot start // removeStart at or before slot end // update slot to end at removeStart if($removeStart >= $this->available[$i]->start && $removeStart <= $this->available[$i]->end) { $this->available[$i]->end = $removeStart; $this->available[$i]->processed = true; $allDone = false; break; } } if(!$allDone) { $this->removeStart($removeStart, $removeEnd); // recurse till clean } } private function removeEnd($removeStart, $removeEnd) { $allDone = true; for ($i=0; $iavailable); $i++) { if($this->available[$i]->processed) continue; // removeEnd at or after slot start // removeEnd at or before slot end // update slot to start at removeEnd if($removeEnd >= $this->available[$i]->start && $removeEnd <= $this->available[$i]->end) { $this->available[$i]->start = $removeEnd; $this->available[$i]->processed = true; $allDone = false; break; } } if(!$allDone) { $this->removeEnd($removeStart, $removeEnd); // recurse till clean } } private function normalize() { $allDone = true; for ($i=0; $iavailable)-1; $i++) { if($this->available[$i]->end >= $this->available[$i+1]->start && // ends in the middle of next slot $this->available[$i]->end <= $this->available[$i+1]->end) { // extend self & delete next $this->available[$i]->end = $this->available[$i+1]->end; array_splice($this->available, $i+1, 1); $allDone = false; break; } if($this->available[$i]->end >= $this->available[$i+1]->end) // ends after next slot end { // delete next array_splice($this->available, $i+1, 1); $allDone = false; break; } if($this->available[$i]->start >= $this->available[$i]->end) // starts and ends at the same time! { // delete self array_splice($this->available, $i, 1); $allDone = false; break; } } if(!$allDone) { $this->normalize(); // recurse till clean } } private function normalizeUnavailable() { $allDone = true; for ($i=0; $iunavailable)-1; $i++) { if($this->unavailable[$i]->end >= $this->unavailable[$i+1]->start && // ends in the middle of next slot $this->unavailable[$i]->end <= $this->unavailable[$i+1]->end) { // extend self & delete next $this->unavailable[$i]->end = $this->unavailable[$i+1]->end; array_splice($this->unavailable, $i+1, 1); $allDone = false; break; } if($this->unavailable[$i]->end >= $this->unavailable[$i+1]->end) // ends after next slot end { // delete next array_splice($this->unavailable, $i+1, 1); $allDone = false; break; } if($this->unavailable[$i]->start >= $this->unavailable[$i]->end) // starts and ends at the same time! { // delete self array_splice($this->unavailable, $i, 1); $allDone = false; break; } } if(!$allDone) { $this->normalizeUnavailable(); // recurse till clean } } public function getAvailable() { return $this->available; } public function getUnavailable() { return $this->unavailable; } public function vdump($_x) { // echo "
";
//        print_r($_x);
//        echo "

"; } }