/** * If the event times have changed, it checks to make sure that the resources * are still available. If not, it throws a validation exception. * * @throws ValiationException */ public function onBeforeWrite() { $changed = $this->owner->getChangedFields(); $check = array('StartDate', 'StartTime', 'EndDate', 'EndTime', 'is_all_day'); if (!array_intersect_key(array_flip($check), $changed)) { return; } foreach ($this->owner->Resources() as $resource) { if ($resource->Type == 'Unlimited') { continue; } // If this is a recurring event, then check all other non-recurring // bookings for this resource to see if any conflict. if ($this->owner->Event()->Recursion) { $bookings = $resource->Events(sprintf('"CalendarEvent"."Recursion" = 0 AND "CalendarDateTime"."ID" <> %d', $this->owner->ID), null, 'INNER JOIN "CalendarEvent" ON "CalendarEvent"."ID" = "CalendarDateTime"."EventID"'); foreach ($bookings as $booking) { $counter = $booking->getStartTimestamp(); $end = $booking->getEndTimestamp(); // Loop through each day the other booking falls on, to see // if it could cause a conflict. while ($counter < $end) { if ($this->owner->Event()->recursionHappensOn($counter)) { $this->checkResourceAvailability($resource, $counter); } $counter = sfTime::add($counter, 1, sfTime::DAY); } } } else { $this->checkResourceAvailability($resource); } } }
public function bookings($request) { $start = (int) $request->getVar('start'); $end = (int) $request->getVar('end'); $result = array(); // First load standard non-recurring events that fall between the start // and end date. $events = $this->parent->Events(sprintf('"CalendarEvent"."Recursion" = 0 AND ( "StartDate" BETWEEN \'%1$s\' AND \'%2$s\' OR "EndDate" BETWEEN \'%1$s\' AND \'%2$s\' OR ("StartDate" < \'%1$s\' AND "EndDate" > \'%2$s\') )', date('Y-m-d', $start), date('Y-m-d', $end)), null, 'INNER JOIN "CalendarEvent" ON "CalendarEvent"."ID" = "CalendarDateTime"."EventID"'); // Then load every recurring event and see if they fall between the start // and end. $recurring = $this->parent->Events(sprintf('"CalendarEvent"."Recursion" = 1 AND ("EndDate" IS NULL OR "EndDate" > \'%s\') AND ("StartDate" IS NULL OR "StartDate" < \'%s\')', date('Y-m-d', $start), date('Y-m-d', $end)), null, 'INNER JOIN "CalendarEvent" ON "CalendarEvent"."ID" = "CalendarDateTime"."EventID"'); // Now loop through each day in the specified date range, and check // each recurring date to see if it occurs on that day. Note that // recurring events always start and end on the same day. if ($recurring) { foreach ($recurring as $datetime) { $counter = $start; $days = 0; while ($counter <= $end) { if ($counter > strtotime($datetime->EndDate)) { break; } if ($datetime->Event()->recursionHappensOn($counter)) { $_datetime = clone $datetime; $_datetime->ID = -1; $_datetime->StartDate = date('Y-m-d', $counter); $_datetime->EndDate = date('Y-m-d', $counter); $events->push($_datetime); } $counter = sfTime::add($counter, 1, sfTime::DAY); $days++; } } } foreach ($events as $event) { $title = $event->EventTitle(); if ($this->parent->Type != 'Single') { $title .= " ({$event->BookingQuantity} {$this->parent->Title})"; } $result[] = array('id' => $event->ID, 'title' => $title, 'start' => $event->getStartTimestamp(), 'end' => $event->getEndTimestamp(), 'allDay' => (bool) $event->is_all_day, 'url' => Controller::join_links('admin/show', $event->EventID)); } return Convert::array2json($result); }
/** * Adds the specified number of millenia to the timestamp. * * @param timestamp * @param int * @return timestamp */ public static function addMillenium($ts = null, $num = 1) { return sfTime::add($ts, $num, sfTime::MILLENIUM); }
/** * Returns the number of this resource that are not booked during an event * time. * * @param CalendarDateTime $time * @return bool|int */ public function getAvailableForEvent($time) { if ($this->Type == 'Unlimited') { return true; } $start = $time->getStartTimestamp(); $end = $time->getEndTimestamp(); // First just get simple non-recurring bookings, often this will be // enough to check if a resource is available. $dateFilter = sprintf('"StartDate" BETWEEN \'%1$s\' AND \'%2$s\' OR "EndDate" BETWEEN \'%1$s\' AND \'%2$s\' OR ("StartDate" < \'%1$s\' AND "EndDate" > \'%2$s\')', date('Y-m-d', $start), date('Y-m-d', $end)); $filter = "\"CalendarEvent\".\"Recursion\" = 0 AND \"CalendarDateTimeID\" <> {$time->ID} AND ({$dateFilter})"; $bookings = $this->Events($filter, null, 'INNER JOIN "CalendarEvent" ON "CalendarEvent"."ID" = "CalendarDateTime"."EventID"'); $bookings = $bookings->toArray('ID'); // Since the event calendar doesn't use a proper date time storage, we // need to manually filter events again here. foreach ($bookings as $id => $booking) { if ($booking->getEndTimestamp() < $start || $booking->getStartTimestamp() > $end) { unset($bookings[$id]); } } if ($bookings && $this->Type == 'Single') { return false; } // Now also load all the recurring events, and check if they occur on // this day. $recurring = $this->Events(sprintf('"CalendarDateTimeID" <> %d AND "CalendarEvent"."Recursion" = 1 AND ("EndDate" IS NULL OR "EndDate" > \'%s\') AND ("StartDate" IS NULL OR "StartDate" < \'%s\')', $time->ID, date('Y-m-d', $start), date('Y-m-d', $end)), null, 'INNER JOIN "CalendarEvent" ON "CalendarEvent"."ID" = "CalendarDateTime"."EventID"'); // Now loop through each day this event runs on, and check if any of the // events fall on it. If they do just push them onto the bookings set. foreach ($recurring as $datetime) { $counter = $start; while ($counter <= $end) { if ($counter > strtotime($datetime->EndDate)) { break; } if ($datetime->Event()->recursionHappensOn($counter)) { $bookings[$datetime->ID] = $datetime; break; } $counter = sfTime::add($counter, 1, sfTime::DAY); } } if ($bookings && $this->Type == 'Single') { return false; } if (!count($bookings)) { return $this->Type == 'Limited' ? (int) $this->Quantity : true; } $quantity = (int) $this->Quantity; foreach ($bookings as $booking) { $quantity -= $booking->BookingQuantity; } return $quantity > 0 ? $quantity : false; }