public function checkReliantFields($formData, $validateStartDate, $originalStartDate = null, $update = false, $instanceId = null) { $valid = true; $start_time = $formData['add_show_start_date'] . " " . $formData['add_show_start_time']; $end_time = $formData['add_show_end_date_no_repeat'] . " " . $formData['add_show_end_time']; //have to use the timezone the user has entered in the form to check past/present $showTimezone = new DateTimeZone($formData["add_show_timezone"]); $nowDateTime = new DateTime("now", $showTimezone); $showStartDateTime = new DateTime($start_time, $showTimezone); $showEndDateTime = new DateTime($end_time, $showTimezone); if ($validateStartDate) { if ($showStartDateTime < $nowDateTime) { $this->getElement('add_show_start_time')->setErrors(array(_('Cannot create show in the past'))); $valid = false; } // if edit action, check if original show start time is in the past. CC-3864 if ($originalStartDate) { if ($originalStartDate < $nowDateTime) { $this->getElement('add_show_start_time')->setValue($originalStartDate->format("H:i")); $this->getElement('add_show_start_date')->setValue($originalStartDate->format("Y-m-d")); $this->getElement('add_show_start_time')->setErrors(array(_('Cannot modify start date/time of the show that is already started'))); $this->disableStartDateAndTime(); $valid = false; } } } // if end time is in the past, return error if ($showEndDateTime < $nowDateTime) { $this->getElement('add_show_end_time')->setErrors(array(_('End date/time cannot be in the past'))); $valid = false; } //validate duration. $duration = $showStartDateTime->diff($showEndDateTime); if ($showStartDateTime > $showEndDateTime) { $this->getElement('add_show_duration')->setErrors(array(_('Cannot have duration < 0m'))); $valid = false; } else { if ($showStartDateTime == $showEndDateTime) { $this->getElement('add_show_duration')->setErrors(array(_('Cannot have duration 00h 00m'))); $valid = false; } else { if (intval($duration->format('%d')) > 0 && (intval($duration->format('%h')) > 0 || intval($duration->format('%i')) > 0 || intval($duration->format('%s')) > 0)) { $this->getElement('add_show_duration')->setErrors(array(_('Cannot have duration greater than 24h'))); $valid = false; } } } /* Check if show is overlapping * We will only do this check if the show is valid * upto this point */ if ($valid) { //we need to know the start day of the week in show's local timezome $startDow = $showStartDateTime->format("w"); $utc = new DateTimeZone('UTC'); $showStartDateTime->setTimezone($utc); $showEndDateTime->setTimezone($utc); if ($formData["add_show_repeats"]) { //get repeating show end date if ($formData["add_show_no_end"]) { $date = Application_Model_Preference::GetShowsPopulatedUntil(); if (is_null($date)) { $populateUntilDateTime = new DateTime("now", $utc); Application_Model_Preference::SetShowsPopulatedUntil($populateUntilDateTime); } else { $populateUntilDateTime = clone $date; } } elseif (!$formData["add_show_no_end"]) { $popUntil = $formData["add_show_end_date"] . " " . $formData["add_show_end_time"]; $populateUntilDateTime = new DateTime($popUntil, $showTimezone); $populateUntilDateTime->setTimezone($utc); } //get repeat interval if ($formData["add_show_repeat_type"] == 0) { $interval = 'P7D'; } elseif ($formData["add_show_repeat_type"] == 1) { $interval = 'P14D'; } elseif ($formData["add_show_repeat_type"] == 4) { $interval = 'P21D'; } elseif ($formData["add_show_repeat_type"] == 5) { $interval = 'P28D'; } elseif ($formData["add_show_repeat_type"] == 2) { $interval = 'P1M'; } /* Check first show * Continue if the first show does not overlap */ if ($update) { $overlapping = Application_Model_Schedule::checkOverlappingShows($showStartDateTime, $showEndDateTime, $update, null, $formData["add_show_id"]); } else { $overlapping = Application_Model_Schedule::checkOverlappingShows($showStartDateTime, $showEndDateTime); } /* Check if repeats overlap with previously scheduled shows * Do this for each show day */ if (!$overlapping) { if (!isset($formData['add_show_day_check'])) { return false; } foreach ($formData["add_show_day_check"] as $day) { $repeatShowStart = clone $showStartDateTime; $repeatShowEnd = clone $showEndDateTime; $daysAdd = 0; if ($startDow !== $day) { if ($startDow > $day) { $daysAdd = 6 - $startDow + 1 + $day; } else { $daysAdd = $day - $startDow; } /* In case we are crossing daylights saving time we need * to convert show start and show end to local time before * adding the interval for the next repeating show */ $repeatShowStart->setTimezone($showTimezone); $repeatShowEnd->setTimezone($showTimezone); $repeatShowStart->add(new DateInterval("P" . $daysAdd . "D")); $repeatShowEnd->add(new DateInterval("P" . $daysAdd . "D")); //set back to UTC $repeatShowStart->setTimezone($utc); $repeatShowEnd->setTimezone($utc); } /* Here we are checking each repeating show by * the show day. * (i.e: every wednesday, then every thursday, etc.) */ while ($repeatShowStart->getTimestamp() < $populateUntilDateTime->getTimestamp()) { if ($formData['add_show_id'] == -1) { //this is a new show $overlapping = Application_Model_Schedule::checkOverlappingShows($repeatShowStart, $repeatShowEnd); /* If the repeating show is rebroadcasted we need to check * the rebroadcast dates relative to the repeating show */ if (!$overlapping && $formData['add_show_rebroadcast']) { $overlapping = self::checkRebroadcastDates($repeatShowStart, $formData, $hours, $minutes); } } else { $overlapping = Application_Model_Schedule::checkOverlappingShows($repeatShowStart, $repeatShowEnd, $update, null, $formData["add_show_id"]); if (!$overlapping && $formData['add_show_rebroadcast']) { $overlapping = self::checkRebroadcastDates($repeatShowStart, $formData, $hours, $minutes, true); } } if ($overlapping) { $valid = false; $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows'))); break 1; } else { $repeatShowStart->setTimezone($showTimezone); $repeatShowEnd->setTimezone($showTimezone); $repeatShowStart->add(new DateInterval($interval)); $repeatShowEnd->add(new DateInterval($interval)); $repeatShowStart->setTimezone($utc); $repeatShowEnd->setTimezone($utc); } } } } else { $valid = false; $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows'))); } } elseif ($formData["add_show_rebroadcast"]) { /* Check first show * Continue if the first show does not overlap */ $overlapping = Application_Model_Schedule::checkOverlappingShows($showStartDateTime, $showEndDateTime, $update, $instanceId); if (!$overlapping) { $durationToAdd = "PT" . $hours . "H" . $minutes . "M"; for ($i = 1; $i <= 10; $i++) { if (empty($formData["add_show_rebroadcast_date_absolute_" . $i])) { break; } $abs_rebroadcast_start = $formData["add_show_rebroadcast_date_absolute_" . $i] . " " . $formData["add_show_rebroadcast_time_absolute_" . $i]; $rebroadcastShowStart = new DateTime($abs_rebroadcast_start); $rebroadcastShowStart->setTimezone(new DateTimeZone('UTC')); $rebroadcastShowEnd = clone $rebroadcastShowStart; $rebroadcastShowEnd->add(new DateInterval($durationToAdd)); $overlapping = Application_Model_Schedule::checkOverlappingShows($rebroadcastShowStart, $rebroadcastShowEnd, $update, null, $formData["add_show_id"]); if ($overlapping) { $valid = false; $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows'))); break; } } } else { $valid = false; $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows'))); } } else { $overlapping = Application_Model_Schedule::checkOverlappingShows($showStartDateTime, $showEndDateTime, $update, $instanceId); if ($overlapping) { $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows'))); $valid = false; } } } return $valid; }
/** * Generate repeating show instances for a single show up to the given date. * If no date is given, use the one in the user's preferences, which is stored * automatically by FullCalendar as the furthest date in the future the user * has looked at. * * @param int $p_showId * @param string $p_date * In the format "YYYY-MM-DD HH:mm:ss" */ public static function populateShowUntil($p_showId, $p_date = NULL) { global $CC_DBC; if (is_null($p_date)) { $p_date = Application_Model_Preference::GetShowsPopulatedUntil(); if ($p_date == "") { $today_timestamp = date("Y-m-d"); Application_Model_Preference::SetShowsPopulatedUntil($today_timestamp); } } $sql = "SELECT * FROM cc_show_days WHERE show_id = {$p_showId}"; $res = $CC_DBC->GetAll($sql); foreach ($res as $row) { Show::populateShow($row["repeat_type"], $row["show_id"], $row["next_pop_date"], $row["first_show"], $row["last_show"], $row["start_time"], $row["duration"], $row["day"], $row["record"], $p_date); } }
/** * Get all the show instances in the given time range (inclusive). * * @param DateTime $start_timestamp * In UTC time. * @param DateTime $end_timestamp * In UTC time. * @param unknown_type $excludeInstance * @param boolean $onlyRecord * @return array */ public static function getShows($start_timestamp, $end_timestamp, $onlyRecord = FALSE) { //UTC DateTime object $showsPopUntil = Application_Model_Preference::GetShowsPopulatedUntil(); //if application is requesting shows past our previous populated until date, generate shows up until this point. if (is_null($showsPopUntil) || $showsPopUntil->getTimestamp() < $end_timestamp->getTimestamp()) { $service_show = new Application_Service_ShowService(); $ccShow = $service_show->delegateInstanceCreation(null, $end_timestamp, true); Application_Model_Preference::SetShowsPopulatedUntil($end_timestamp); } $sql = <<<SQL SELECT si1.starts AS starts, si1.ends AS ends, si1.record AS record, si1.rebroadcast AS rebroadcast, si2.starts AS parent_starts, si1.instance_id AS record_id, si1.show_id AS show_id, show.name AS name, show.color AS color, show.background_color AS background_color, show.linked AS linked, si1.file_id AS file_id, si1.id AS instance_id, si1.created AS created, si1.last_scheduled AS last_scheduled, si1.time_filled AS time_filled, f.soundcloud_id FROM cc_show_instances AS si1 LEFT JOIN cc_show_instances AS si2 ON si1.instance_id = si2.id LEFT JOIN cc_show AS show ON show.id = si1.show_id LEFT JOIN cc_files AS f ON f.id = si1.file_id WHERE si1.modified_instance = FALSE SQL; //only want shows that are starting at the time or later. $start_string = $start_timestamp->format("Y-m-d H:i:s"); $end_string = $end_timestamp->format("Y-m-d H:i:s"); if ($onlyRecord) { $sql .= " AND (si1.starts >= :start::TIMESTAMP AND si1.starts < :end::TIMESTAMP)"; $sql .= " AND (si1.record = 1)"; return Application_Common_Database::prepareAndExecute($sql, array(':start' => $start_string, ':end' => $end_string), 'all'); } else { $sql .= " " . <<<SQL AND ((si1.starts >= :start1::TIMESTAMP AND si1.starts < :end1::TIMESTAMP) OR (si1.ends > :start2::TIMESTAMP AND si1.ends <= :end2::TIMESTAMP) OR (si1.starts <= :start3::TIMESTAMP AND si1.ends >= :end3::TIMESTAMP)) ORDER BY si1.starts SQL; return Application_Common_Database::prepareAndExecute($sql, array('start1' => $start_string, 'start2' => $start_string, 'start3' => $start_string, 'end1' => $end_string, 'end2' => $end_string, 'end3' => $end_string), 'all'); } }
/** * * Gets the date and time shows (particularly repeating shows) * can be populated until. * * @return DateTime object */ private static function getPopulateShowUntilDateTIme() { $populateUntil = Application_Model_Preference::GetShowsPopulatedUntil(); if (is_null($populateUntil)) { $populateUntil = new DateTime("now", new DateTimeZone('UTC')); Application_Model_Preference::SetShowsPopulatedUntil($populateUntil); } return $populateUntil; }