ccShow = CcShowQuery::create()->findPk($showId); } if (isset($showData['add_show_repeats']) && $showData['add_show_repeats']) { $this->repeatType = $showData['add_show_repeat_type']; if ($showData['add_show_repeat_type'] == 2) { $this->repeatType = $showData['add_show_monthly_repeat_type']; } } else { $this->repeatType = -1; } $this->isRecorded = (isset($showData['add_show_record']) && $showData['add_show_record']) ? 1 : 0; $this->isRebroadcast = (isset($showData['add_show_rebroadcast']) && $showData['add_show_rebroadcast']) ? 1 : 0; $this->isUpdate = $isUpdate; $this->instanceIdsForScheduleUpdates = []; $this->newInstanceIdsCreated = []; } public function editRepeatingShowInstance($showData) { $service_user = new Application_Service_UserService(); $currentUser = $service_user->getCurrentUser(); $showData['add_show_duration'] = $this->formatShowDuration( $showData['add_show_duration'] ); $con = Propel::getConnection(); $con->beginTransaction(); try { if (!$currentUser->isAdminOrPM()) { throw new Exception('Permission denied'); } $showId = $showData['add_show_id']; // UPDATE SCHEDULE START TIME // get the ccShow object to which this instance belongs // so we can get the original start date and time $this->ccShow = CcShowQuery::create() ->findPk($showId); // DateTime in shows's local time $newStartDateTime = new DateTime( $showData['add_show_start_date'] . ' ' . $showData['add_show_start_time'], new DateTimeZone($showData['add_show_timezone']) ); $ccShowInstanceOrig = CcShowInstancesQuery::create() ->findPk($showData['add_show_instance_id']); // convert original start time into the show's local timezone $origLocalStartDateTime = $ccShowInstanceOrig->getLocalStartDateTime(); $diff = $this->calculateShowStartDiff( $newStartDateTime, $origLocalStartDateTime ); if ($diff != 0) { Application_Service_SchedulerService::updateScheduleStartTime( [$showData['add_show_instance_id']], $diff ); } // UPDATE SCHEDULE START TIME ENDS /* * In the case where an instance is being edited for a second * (or third, fourth, etc.) time we need to delete the old * cc_show_day record * * Since we don't store the cc_show_day ids we need to use the * original start time from cc_show_instances, convert it to the show's * local timezone, and find the record in cc_show_days * * *** There is a flaw here: We have to assume the show timezone has * *** not changed (make timezone readonly??) */ $origCcShowDay = CcShowDaysQuery::create() ->filterByDbShowId($showId) ->filterByDbRepeatType(-1) ->filterByDbFirstShow($origLocalStartDateTime->format('Y-m-d')) ->filterByDbStartTime($origLocalStartDateTime->format('H:i:s')) ->delete(); /* * Set the new cc_show_day record * Associates it with the current show_id and sets it to non-repeating */ $this->setCcShowDays($showData); /* * We need to find the new show day rule we just created by passing * in the first show and start time in case multiple single * instances have been edited out of the repeating sequence. */ $showDay = CcShowDaysQuery::create() ->filterByDbShowId($showId) ->filterByDbRepeatType(-1) ->filterByDbFirstShow($showData['add_show_start_date']) ->filterByDbStartTime($showData['add_show_start_time'] . ':00') ->findOne(); $ccShowInstance = $this->createNonRepeatingInstance( $showDay, $this->getPopulateShowUntilDateTIme() ); // update cc_schedule with the new instance id $con = Propel::getConnection(CcShowInstancesPeer::DATABASE_NAME); $selectCriteria = new Criteria(); $selectCriteria->add(CcSchedulePeer::INSTANCE_ID, $showData['add_show_instance_id']); $updateCriteria = new Criteria(); $updateCriteria->add(CcSchedulePeer::INSTANCE_ID, $ccShowInstance->getDbId()); BasePeer::doUpdate($selectCriteria, $updateCriteria, $con); $ccShowInstance->updateDbTimeFilled($con); $ccShowInstance->updateScheduleStatus($con); $ccShowInstance ->setDbDescription($showData['add_show_instance_description']) ->save(); // delete the edited instance from the repeating sequence $ccShowInstanceOrig ->setDbModifiedInstance(true) ->setDbDescription($showData['add_show_instance_description']) ->save(); $con->commit(); Application_Model_RabbitMq::PushSchedule(); } catch (Exception $e) { $con->rollback(); Logging::info('EXCEPTION: Show update failed.'); Logging::info($e->getMessage()); } } /** * If a user is editing a show we need to store the original timezone and * start time in case the show's timezone is changed and we are crossing * over DST. */ private function storeOrigLocalShowInfo() { if ($this->ccShow->isRepeating()) { $this->origCcShowDay = clone $this->ccShow->getFirstRepeatingCcShowDay(); $this->origShowRepeatStatus = true; } else { $this->origCcShowDay = clone $this->ccShow->getFirstCcShowDay(); $this->origShowRepeatStatus = false; } $this->oldShowTimezone = $this->origCcShowDay->getDbTimezone(); $origStartTime = explode(':', $this->origCcShowDay->getDbStartTime()); $this->localShowStartHour = $origStartTime[0]; $this->localShowStartMin = $origStartTime[1]; } public function addUpdateShow($showData) { $service_user = new Application_Service_UserService(); $currentUser = $service_user->getCurrentUser(); $showData['add_show_duration'] = $this->formatShowDuration( $showData['add_show_duration'] ); $con = Propel::getConnection(); $con->beginTransaction(); try { if (!$currentUser->isAdminOrPM()) { throw new Exception('Permission denied'); } // update ccShow $this->setCcShow($showData); $daysAdded = []; if ($this->isUpdate) { $showId = $this->ccShow->getDbId(); // Only delete the previous logo if a new one is being uploaded if (array_key_exists('add_show_logo_name', $showData) && $showData['add_show_logo_name'] !== '') { if (!Rest_ShowImageController::deleteShowImagesFromStor($showId)) { throw new Exception('Error deleting show images'); } } if (!$this->ccShow->getCcShowDayss()->isEmpty()) { $this->storeOrigLocalShowInfo(); } $daysAdded = $this->delegateInstanceCleanup($showData); $this->deleteRebroadcastInstances(); $this->deleteCcShowHosts(); if ($this->isRebroadcast) { // delete entry in cc_show_rebroadcast $this->deleteCcShowRebroadcasts(); } $this->storeInstanceIds(); } // update ccShowDays $this->setCcShowDays($showData); // update ccShowRebroadcasts $this->setCcShowRebroadcasts($showData); // update ccShowHosts $this->setCcShowHosts($showData); // create new ccShowInstances $this->delegateInstanceCreation($daysAdded); if ($this->isUpdate) { /* If the show is repeating and the start date changes we need * to ignore that difference when re-calculating schedule start times. * Otherwise it might calculate a difference of a week, for example. */ if ( $this->ccShow->isRepeating() && $this->origCcShowDay->getLocalStartDateAndTime()->format('Y-m-d') != $showData['add_show_start_date'] ) { $showData['add_show_start_date'] = $this->origCcShowDay->getLocalStartDateAndTime()->format('Y-m-d'); } $this->adjustSchedule($showData); } $con->commit(); Application_Model_RabbitMq::PushSchedule(); } catch (Exception $e) { $con->rollback(); $this->isUpdate ? $action = 'update' : $action = 'creation'; Logging::info('EXCEPTION: Show ' . $action . ' failed.'); Logging::info($e->getMessage()); } // Added to pass along to the RESTful ShowImageController return $this->ccShow->getDbId(); } /** * Returns an array of instance ids that already exist * We need this if a show is being updated so we can separate the * instances that already exist and any new instances that * get created (by adding a new repeat show day). */ private function storeInstanceIds() { $instances = $this->ccShow->getFutureCcShowInstancess(); foreach ($instances as $instance) { $this->instanceIdsForScheduleUpdates[] = $instance->getDbId(); } } /** * Adjusts the items in cc_schedule to reflect the * new (if one) start and end time of the show getting updated. * * @param mixed $showData */ private function adjustSchedule($showData) { $con = Propel::getConnection(CcSchedulePeer::DATABASE_NAME); $this->updateScheduleStartEndTimes($showData); $ccShowInstances = $this->ccShow->getFutureCcShowInstancess(); foreach ($ccShowInstances as $instance) { $instance->updateScheduleStatus($con); } } /** * Receives a cc_show id and determines whether to create a * single show instance or repeating show instances. * * @param null|mixed $daysAdded * @param null|mixed $end * @param mixed $fillInstances */ public function delegateInstanceCreation($daysAdded = null, $end = null, $fillInstances = false) { $populateUntil = $this->getPopulateShowUntilDateTIme(); if (is_null($this->ccShow)) { $ccShowDays = $this->getShowDaysInRange($populateUntil, $end); } else { if ($this->ccShow->isRepeating()) { $ccShowDays = $this->ccShow->getRepeatingCcShowDays(); } else { // $ccShowDays = $this->ccShow->getCcShowDayss(); /* Cannot use the above statement to get the cc_show_days * object because it's getting the old object before the * show was edited. clearInstancePool() didn't work. */ $ccShowDays = CcShowDaysQuery::create() ->filterByDbShowId($this->ccShow->getDbId()) ->find(); } } if (!is_null($end)) { $populateUntil = $end; } /* In case the user is moving forward in the calendar and there are * linked shows in the schedule we need to keep track of each cc_show * so we know which shows need to be filled with content */ $ccShows = []; foreach ($ccShowDays as $day) { $this->ccShow = $day->getCcShow(); $this->isRecorded = $this->ccShow->isRecorded(); $this->isRebroadcast = $this->ccShow->isRebroadcast(); $show_id = $day->getDbShowId(); if (!isset($ccShows[$show_id])) { $ccShows[$show_id] = $day->getccShow(); } // keep track of the new show instances getting created // so we can fill their schedule after if (!isset($this->newInstanceIdsCreated[$show_id])) { $this->newInstanceIdsCreated[$show_id] = []; } switch ($day->getDbRepeatType()) { case NO_REPEAT: $this->createNonRepeatingInstance($day, $populateUntil); break; case REPEAT_WEEKLY: $this->createWeeklyRepeatInstances( $day, $populateUntil, REPEAT_WEEKLY, new DateInterval('P7D'), $daysAdded ); break; case REPEAT_BI_WEEKLY: $this->createWeeklyRepeatInstances( $day, $populateUntil, REPEAT_BI_WEEKLY, new DateInterval('P14D'), $daysAdded ); break; case REPEAT_TRI_WEEKLY: $this->createWeeklyRepeatInstances( $day, $populateUntil, REPEAT_TRI_WEEKLY, new DateInterval('P21D'), $daysAdded ); break; case REPEAT_QUAD_WEEKLY: $this->createWeeklyRepeatInstances( $day, $populateUntil, REPEAT_QUAD_WEEKLY, new DateInterval('P28D'), $daysAdded ); break; case REPEAT_MONTHLY_MONTHLY: $this->createMonthlyRepeatInstances($day, $populateUntil); break; case REPEAT_MONTHLY_WEEKLY: $this->createMonthlyRepeatInstances($day, $populateUntil); break; } } foreach ($ccShows as $ccShow) { if (($this->isUpdate || $fillInstances) && $ccShow->isLinked()) { Application_Service_SchedulerService::fillLinkedInstances( $ccShow, $this->newInstanceIdsCreated[$ccShow->getDbId()] ); } } /*if (isset($this->linkedShowContent)) { Application_Service_SchedulerService::fillPreservedLinkedShowContent( $this->ccShow, $this->linkedShowContent); }*/ return $this->ccShow; } private function getShowDaysInRange($start, $end) { $endTimeString = $end->format(DEFAULT_TIMESTAMP_FORMAT); if (!is_null($start)) { $startTimeString = $start->format(DEFAULT_TIMESTAMP_FORMAT); } else { $today_timestamp = new DateTime('now', new DateTimeZone('UTC')); $startTimeString = $today_timestamp->format(DEFAULT_TIMESTAMP_FORMAT); } $c = new Criteria(); $c->add(CcShowDaysPeer::FIRST_SHOW, $endTimeString, Criteria::LESS_THAN); $c->addAnd(CcShowDaysPeer::LAST_SHOW, $startTimeString, Criteria::GREATER_THAN); $c->addAnd(CcShowDaysPeer::REPEAT_TYPE, -1, Criteria::NOT_EQUAL); $c->addOr(CcShowDaysPeer::LAST_SHOW, null, Criteria::ISNULL); return CcShowDaysPeer::doSelect($c); } public static function formatShowDuration($duration) { $hPos = strpos($duration, 'h'); $mPos = strpos($duration, 'm'); $hValue = 0; $mValue = 0; if ($hPos !== false) { $hValue = trim(substr($duration, 0, $hPos)); } if ($mPos !== false) { $hPos = $hPos === false ? 0 : $hPos + 1; $mValue = trim(substr($duration, $hPos, -1)); } return $hValue . ':' . $mValue; } /** * Deletes all the cc_show_days entries for a specific show * that is currently being edited. They will get recreated with * the new show day specs. */ private function deleteCcShowDays() { CcShowDaysQuery::create()->filterByDbShowId($this->ccShow->getDbId())->delete(); } private function deleteRebroadcastInstances() { $sql = <<<'SQL' DELETE FROM cc_show_instances WHERE starts > :timestamp::TIMESTAMP AND show_id = :showId AND rebroadcast = 1; SQL; Application_Common_Database::prepareAndExecute($sql, [ ':showId' => $this->ccShow->getDbId(), ':timestamp' => gmdate(DEFAULT_TIMESTAMP_FORMAT), ], 'execute'); } private function deleteAllShowDays($showId) { CcShowDaysQuery::create() ->filterByDbShowId($showId) ->delete(); } /** * TODO: This function is messy. Needs refactoring. * * When editing a show we may need to perform some actions to reflect the new specs: * - Delete some show instances * - Update duration * - Update start and end time * * @param $showData edit show form values in raw form */ private function delegateInstanceCleanup($showData) { $showId = $this->ccShow->getDbId(); $daysAdded = []; // CcShowDay object if ($this->ccShow->isRepeating()) { $currentShowDay = $this->ccShow->getFirstRepeatingCcShowDay(); // all cc_show_days $ccShowDays = $this->ccShow->getRepeatingCcShowDays(); } else { $currentShowDay = $this->ccShow->getFirstCcShowDay(); // all cc_show_days $ccShowDays = $this->ccShow->getCcShowDayss(); } // new end date in the show's timezone (from the select box) $endDateTime = $this->calculateEndDate($showData); // repeat option was toggled if ($showData['add_show_repeats'] != $currentShowDay->isRepeating()) { $this->deleteAllRepeatInstances($currentShowDay, $showId); if (!$showData['add_show_repeats']) { $this->deleteAllShowDays($showId); } // if repeat option was checked we need to treat the current show day // as a new show day so the repeat instances get created properly // in createWeeklyRepeatInstances() if ($showData['add_show_repeats']) { array_push($daysAdded, $currentShowDay->getDbDay()); } } if ($showData['add_show_repeats']) { $localShowStart = $currentShowDay->getLocalStartDateAndTime(); // if the start date changes, these are the repeat types // that require show instance deletion $deleteRepeatTypes = [ REPEAT_BI_WEEKLY, REPEAT_TRI_WEEKLY, REPEAT_QUAD_WEEKLY, REPEAT_MONTHLY_MONTHLY, REPEAT_MONTHLY_WEEKLY, ]; if ( in_array($this->repeatType, $deleteRepeatTypes) && $showData['add_show_start_date'] != $localShowStart->format('Y-m-d') ) { // Start date has changed when repeat type is bi-weekly or monthly. // This screws up the repeating positions of show instances, so // we need to delete them (CC-2351) $this->deleteAllInstances($showId); } $currentRepeatType = $currentShowDay->getDbRepeatType(); // only delete instances if the show being edited was already repeating // and the repeat type changed if ($currentRepeatType != -1 && $this->repeatType != $currentRepeatType) { $this->deleteAllInstances($showId); $this->deleteAllShowDays($showId); // when repeating by day of the month (1st, 2nd, etc.) we do not store the repeat week days } elseif ($currentRepeatType != 2) { // repeat type is the same, check if the days of the week are the same $repeatingDaysChanged = false; $showDays = []; foreach ($ccShowDays as $day) { $showDays[] = $day->getDbDay(); } if (count($showData['add_show_day_check']) == count($showDays)) { // same number of days checked, lets see if they are the same numbers $intersect = array_intersect($showData['add_show_day_check'], $showDays); if (count($intersect) != count($showData['add_show_day_check'])) { $repeatingDaysChanged = true; } } else { $repeatingDaysChanged = true; } if ($repeatingDaysChanged) { $daysRemoved = array_diff($showDays, $showData['add_show_day_check']); $newDays = array_diff($showData['add_show_day_check'], $showDays); foreach ($newDays as $newDay) { array_push($daysAdded, $newDay); } if (count($daysRemoved) > 0) { // delete repeating show instances for the repeating // days that were removed /*if ($this->ccShow->isLinked()) { $this->preserveLinkedShowContent(); }*/ $this->deleteRemovedShowDayInstances( $daysRemoved, $ccShowDays, $showId ); } } if ( $showData['add_show_start_date'] != $localShowStart->format('Y-m-d') || $showData['add_show_start_time'] != $localShowStart->format('H:i') ) { // start date has been pushed forward so we need to delete // any instances of this show scheduled before the new start date if ($showData['add_show_start_date'] > $localShowStart->format('Y-m-d')) { $this->deleteInstancesBeforeDate($showData['add_show_start_date'], $showId); } } } // get the endate from the past for this show. // check if this is null if "no end" $currentShowEndDateTime = $this->getRepeatingEndDate(); if ($endDateTime && $currentShowEndDateTime != $endDateTime) { $endDate = clone $endDateTime; $endDate->setTimezone(new DateTimeZone('UTC')); // show's "No End" option was toggled // or the end date comes earlier if (is_null($currentShowEndDateTime) || ($endDateTime < $currentShowEndDateTime)) { // "No End" option was unchecked so we need to delete the // repeat instances that are scheduled after the new end date // OR // end date was pushed back so we have to delete any // instances of this show scheduled after the new end date $this->deleteInstancesFromDate($endDate->format('Y-m-d'), $showId); } } } return $daysAdded; } /*private function preserveLinkedShowContent() { // Get show content from any future linked instance. It doesn't // matter which instance since content is the same in all. // $ccShowInstance = $this->ccShow->getFutureCcShowInstancess()->getFirst(); if (!$ccShowInstance) { return; } $ccSchedules = CcScheduleQuery::create() ->filterByDbInstanceId($ccShowInstance->getDbId()) ->find(); if (!$ccSchedules->isEmpty()) { $this->linkedShowContent = $ccSchedules; } }*/ // returns a DateTime of the current show end date set to the timezone of the show. public function getRepeatingEndDate() { $sql = <<<'SQL' SELECT last_show, timezone FROM cc_show_days WHERE show_id = :showId ORDER BY last_show DESC LIMIT 1 SQL; $query = Application_Common_Database::prepareAndExecute( $sql, ['showId' => $this->ccShow->getDbId()], 'single' ); $date = null; if ($query !== false && isset($query['last_show'])) { $date = new DateTime( $query['last_show'], new DateTimeZone($query['timezone']) ); } return $date; } private function deleteInstancesFromDate($endDate, $showId) { $sql = <<<'SQL' DELETE FROM cc_show_instances WHERE date(starts) >= :endDate::DATE AND starts > :timestamp::TIMESTAMP AND show_id = :showId SQL; Application_Common_Database::prepareAndExecute($sql, [ ':endDate' => $endDate, ':timestamp' => gmdate(DEFAULT_TIMESTAMP_FORMAT), ':showId' => $showId, ], 'execute'); } private function deleteInstancesBeforeDate($newStartDate, $showId) { $sql = <<<'SQL' DELETE FROM cc_show_instances WHERE date(starts) < :newStartDate::DATE AND starts > :timestamp::TIMESTAMP AND show_id = :showId SQL; Application_Common_Database::prepareAndExecute($sql, [ ':newStartDate' => $newStartDate, ':timestamp' => gmdate(DEFAULT_TIMESTAMP_FORMAT), ':showId' => $showId, ], 'execute'); } /** * Enter description here ... * * @param $daysRemoved array of days (days of the week) removed * (days of the week are represented numerically * 0=>sunday, 1=>monday, 2=>tuesday, etc.) * @param $showDays array of ccShowDays objects * @param mixed $showId */ private function deleteRemovedShowDayInstances($daysRemoved, $showDays, $showId) { $daysRemovedUTC = []; // convert the start day of the week to UTC foreach ($showDays as $showDay) { if (in_array($showDay->getDbDay(), $daysRemoved)) { $showDay->reload(); $startDay = $showDay->getUTCStartDateAndTime(); $daysRemovedUTC[] = $startDay->format('w'); } } foreach ($daysRemoved as $day) { // delete the cc_show_day entries as well CcShowDaysQuery::create() ->filterByDbShowId($showId) ->filterByDbDay($day) ->delete(); } $uncheckedDays = pg_escape_string(implode(',', $daysRemovedUTC)); $sql = << :timestamp::TIMESTAMP AND show_id = :showId SQL; Application_Common_Database::prepareAndExecute( $sql, [ ':timestamp' => gmdate(DEFAULT_TIMESTAMP_FORMAT), ':showId' => $showId, ], 'execute' ); } public function deleteShow($instanceId, $singleInstance = false) { $service_user = new Application_Service_UserService(); $currentUser = $service_user->getCurrentUser(); $con = Propel::getConnection(); $con->beginTransaction(); try { if (!$currentUser->isAdminOrPM()) { throw new Exception('Permission denied'); } $ccShowInstance = CcShowInstancesQuery::create() ->findPk($instanceId); if (!$ccShowInstance) { throw new Exception('Could not find show instance'); } // Delete show images $showId = $ccShowInstance->getDbShowId(); if (!$singleInstance && !Rest_ShowImageController::deleteShowImagesFromStor($showId)) { throw new Exception('Error deleting show images'); } if ($singleInstance) { $ccShowInstances = [$ccShowInstance]; } else { $ccShowInstances = CcShowInstancesQuery::create() ->filterByDbShowId($showId) ->filterByDbStarts($ccShowInstance->getDbStarts(), Criteria::GREATER_EQUAL) ->find(); } if (gmdate(DEFAULT_TIMESTAMP_FORMAT) <= $ccShowInstance->getDbEnds()) { $this->deleteShowInstances($ccShowInstances, $showId); } else { throw new Exception('Cannot delete a show instance in the past'); } Application_Model_StoredFile::updatePastFilesIsScheduled(); Application_Model_RabbitMq::PushSchedule(); $con->commit(); return $showId; } catch (Exception $e) { $con->rollback(); Logging::info('Delete show instance failed'); Logging::info($e->getMessage()); return false; } } public function deleteShowInstances($ccShowInstances, $showId) { foreach ($ccShowInstances as $ccShowInstance) { $instanceId = $ccShowInstance->getDbId(); $ccShowInstance ->setDbModifiedInstance(true) ->save(); // delete the rebroadcasts of the removed recorded show if ($ccShowInstance->isRecorded()) { CcShowInstancesQuery::create() ->filterByDbOriginalShow($instanceId) ->delete(); } // delete all files scheduled in cc_schedules table CcScheduleQuery::create() ->filterByDbInstanceId($instanceId) ->delete(); } if ($this->checkToDeleteCcShow($showId)) { CcShowQuery::create() ->filterByDbId($showId) ->delete(); // There is only one cc_show_instance if the user selects 'Delete This Instance' // There is more than one cc_show_instance if the user selects 'Delete This // Instance and All Following'. We only need to set the last_show value // when 'Delete This Instance and All Following' has been selected } elseif (count($ccShowInstances) > 1) { $this->setLastRepeatingShowDate($showId); } } private function setLastRepeatingShowDate($showId) { $ccShowInstances = CcShowInstancesQuery::create() ->filterByDbShowId($showId) ->filterByDbModifiedInstance(false) ->filterByDbRebroadcast(0) ->orderByDbStarts() ->find(); /* We need to update the last_show in cc_show_days so the instances * don't get recreated as the user moves forward in the calendar */ $lastShowDays = []; // get the show's timezone $ccShow = CcShowQuery::create()->findPk($showId); if ($ccShow->isRepeating()) { $showTimezone = $ccShow->getFirstRepeatingCcShowDay()->getDbTimezone(); } else { $showTimezone = $ccShow->getFirstCcShowDay()->getDbTimezone(); } /* Creates an array where the key is the day of the week (monday, * tuesday, etc.) and the value is the last show date for each * day of the week. We will use this array to update the last_show * for each cc_show_days entry of a cc_show */ foreach ($ccShowInstances as $instance) { $instanceStartDT = $instance->getDbStarts(null); $instanceStartDT->setTimezone(new DateTimeZone($showTimezone)); $lastShowDays[$instanceStartDT->format('w')] = $instanceStartDT; } foreach ($lastShowDays as $dayOfWeek => $lastShowStartDT) { $ccShowDay = CcShowDaysQuery::create() ->filterByDbShowId($showId) ->filterByDbDay($dayOfWeek) ->filterByDbRepeatType(-1, Criteria::NOT_EQUAL) ->findOne(); if (isset($ccShowDay)) { $lastShowStartDT->setTimeZone(new DateTimeZone( $ccShowDay->getDbTimezone() )); $lastShowEndDT = Application_Service_CalendarService::addDeltas( $lastShowStartDT, 1, 0 ); $ccShowDay ->setDbLastShow($lastShowEndDT->format('Y-m-d')) ->save(); } } // NOTE: Some cc_show_day records may not get updated because there may not be an instance // left on one of the repeating days so we have to find the entries where the last_show is // still null $showDays = CcShowDaysQuery::create() ->filterByDbShowId($showId) ->filterByDbRepeatType(0, Criteria::GREATER_EQUAL) ->filterByDbLastShow(null) ->find(); foreach ($showDays as $showDay) { $showDay->setDbLastShow($showDay->getDbFirstShow())->save(); } } private function checkToDeleteCcShow($showId) { // check if there are any non deleted show instances remaining. $ccShowInstances = CcShowInstancesQuery::create() ->filterByDbShowId($showId) ->filterByDbModifiedInstance(false) ->filterByDbRebroadcast(0) ->orderByDbStarts() ->find(); if ($ccShowInstances->isEmpty()) { return true; } return false; } private function deleteAllInstances($showId) { $sql = <<<'SQL' DELETE FROM cc_show_instances WHERE starts > :timestamp::TIMESTAMP AND show_id = :showId SQL; Application_Common_Database::prepareAndExecute( $sql, [ ':timestamp' => gmdate(DEFAULT_TIMESTAMP_FORMAT), ':showId' => $showId, ], 'execute' ); } private function deleteAllRepeatInstances($currentShowDay, $showId) { $firstShow = $currentShowDay->getUTCStartDateAndTime(); $sql = <<<'SQL' DELETE FROM cc_show_instances WHERE starts > :timestamp::TIMESTAMP AND show_id = :showId AND starts != :firstShow SQL; Application_Common_Database::prepareAndExecute( $sql, [ ':timestamp' => gmdate(DEFAULT_TIMESTAMP_FORMAT), ':showId' => $showId, ':firstShow' => $firstShow->format(DEFAULT_TIMESTAMP_FORMAT), ], 'execute' ); } /** * Determines what the show end date should be based on * the form data. * * @param $showData add/edit show form data * * @return DateTime object in user's local timezone */ private function calculateEndDate($showData) { // if no end return null if ($showData['add_show_no_end']) { $endDate = null; } // if the show is repeating & ends, then return the end date elseif ($showData['add_show_repeats']) { $endDate = new DateTime( $showData['add_show_end_date'], new DateTimeZone($showData['add_show_timezone']) ); $endDate->add(new DateInterval('P1D')); } // the show doesn't repeat, so add one day to the start date. else { $endDate = new DateTime( $showData['add_show_start_date'], new DateTimeZone($showData['add_show_timezone']) ); $endDate->add(new DateInterval('P1D')); } return $endDate; } private function updateScheduleStartEndTimes($showData) { $showId = $this->ccShow->getDbId(); // DateTime in show's local time $newStartDateTime = new DateTime( $showData['add_show_start_date'] . ' ' . $showData['add_show_start_time'], new DateTimeZone($showData['add_show_timezone']) ); $diff = $this->calculateShowStartDiff( $newStartDateTime, $this->origCcShowDay->getLocalStartDateAndTime() ); Application_Service_SchedulerService::updateScheduleStartTime( $this->instanceIdsForScheduleUpdates, $diff ); } /** * Returns the difference in seconds between a show's new and * old start time. * * @param $newStartDateTime DateTime object * @param $oldStartDateTime DateTime object */ private function calculateShowStartDiff($newStartDateTime, $oldStartDateTime) { return $newStartDateTime->getTimestamp() - $oldStartDateTime->getTimestamp(); } /** * Updates the start and end time for cc_show_instances. * * @param mixed $diff */ private function updateInstanceStartEndTime($diff) { $sql = <<<'SQL' UPDATE cc_show_instances SET starts = starts + :diff1::INTERVAL, ends = ends + :diff2::INTERVAL WHERE show_id = :showId AND starts > :timestamp::TIMESTAMP SQL; Application_Common_Database::prepareAndExecute( $sql, [ ':diff1' => $diff, ':diff2' => $diff, ':showId' => $this->ccShow->getDbId(), ':timestamp' => gmdate(DEFAULT_TIMESTAMP_FORMAT), ], 'execute' ); } /** * Enter description here ... * * @param ccShowDays $showDay * @param DateTime $showStartDate user's local time * @param mixed $instanceId */ private function createRebroadcastInstances($showDay, $showStartDate, $instanceId) { $currentUtcTimestamp = gmdate(DEFAULT_TIMESTAMP_FORMAT); $showId = $this->ccShow->getDbId(); $sql = 'SELECT * FROM cc_show_rebroadcast WHERE show_id=:show_id'; $rebroadcasts = Application_Common_Database::prepareAndExecute( $sql, [':show_id' => $showId], 'all' ); foreach ($rebroadcasts as $rebroadcast) { $days = explode(' ', $rebroadcast['day_offset']); $time = explode(':', $rebroadcast['start_time']); $offset = ['days' => $days[0], 'hours' => $time[0], 'mins' => $time[1]]; [$utcStartDateTime, $utcEndDateTime] = $this->createUTCStartEndDateTime( $showStartDate, $showDay->getDbDuration(), $offset ); if ($utcStartDateTime->format(DEFAULT_TIMESTAMP_FORMAT) > $currentUtcTimestamp) { $ccShowInstance = new CcShowInstances(); $ccShowInstance->setDbShowId($showId); $ccShowInstance->setDbStarts($utcStartDateTime); $ccShowInstance->setDbEnds($utcEndDateTime); $ccShowInstance->setDbRecord(0); $ccShowInstance->setDbRebroadcast(1); $ccShowInstance->setDbOriginalShow($instanceId); $ccShowInstance->save(); } } } /** * Sets a single cc_show_instance table row. * * @param mixed $showDay * @param mixed $populateUntil */ private function createNonRepeatingInstance($showDay, $populateUntil) { // DateTime object $start = $showDay->getLocalStartDateAndTime(); [$utcStartDateTime, $utcEndDateTime] = $this->createUTCStartEndDateTime( $start, $showDay->getDbDuration() ); if ($utcStartDateTime->getTimestamp() < $populateUntil->getTimestamp()) { $ccShowInstance = new CcShowInstances(); if ($this->isUpdate) { // use original cc_show_day object to get the current cc_show_instance $origStartDateTime = new DateTime( $this->origCcShowDay->getDbFirstShow() . ' ' . $this->origCcShowDay->getDbStartTime(), new DateTimeZone($this->origCcShowDay->getDbTimezone()) ); $origStartDateTime->setTimezone(new DateTimeZone('UTC')); $ccShowInstance = $this->getInstance($origStartDateTime); if (!$ccShowInstance) { throw new Exception('Could not find show instance with start time: ' . $origStartDateTime->format(DEFAULT_TIMESTAMP_FORMAT)); } } $ccShowInstance->setDbShowId($this->ccShow->getDbId()); $ccShowInstance->setDbStarts($utcStartDateTime); $ccShowInstance->setDbEnds($utcEndDateTime); $ccShowInstance->setDbRecord($showDay->getDbRecord()); $ccShowInstance->save(); if ($this->isRebroadcast) { $this->createRebroadcastInstances($showDay, $start, $ccShowInstance->getDbId()); } } return $ccShowInstance; } /** * Sets multiple cc_show_instances table rows. * * @param unknown_type $showDay * @param unknown_type $populateUntil * @param unknown_type $repeatInterval * @param mixed $repeatType * @param null|mixed $daysAdded */ private function createWeeklyRepeatInstances( $showDay, $populateUntil, $repeatType, $repeatInterval, $daysAdded = null ) { $show_id = $showDay->getDbShowId(); $first_show = $showDay->getDbFirstShow(); // non-UTC $last_show = $showDay->getDbLastShow(); // non-UTC $duration = $showDay->getDbDuration(); $day = $showDay->getDbDay(); $record = $showDay->getDbRecord(); $timezone = $showDay->getDbTimezone(); // DateTime local $start = $this->getNextRepeatingPopulateStartDateTime($showDay); if (is_null($repeatInterval) && $repeatType == REPEAT_MONTHLY_WEEKLY) { $repeatInterval = self::getMonthlyWeeklyRepeatInterval($start, $timezone); } // DatePeriod in user's local time $datePeriod = $this->getDatePeriod( $start, $timezone, $last_show, $repeatInterval, $populateUntil ); if ($last_show) { $utcLastShowDateTime = new DateTime($last_show, new DateTimeZone($timezone)); $utcLastShowDateTime->setTimezone(new DateTimeZone('UTC')); } else { $utcLastShowDateTime = null; } $previousDate = clone $start; foreach ($datePeriod as $date) { [$utcStartDateTime, $utcEndDateTime] = $this->createUTCStartEndDateTime( $date, $duration ); /* * Make sure start date is less than populate until date AND * last show date is null OR start date is less than last show date */ if ( $utcStartDateTime <= $populateUntil && (is_null($utcLastShowDateTime) || $utcStartDateTime < $utcLastShowDateTime) ) { $lastCreatedShow = clone $utcStartDateTime; /* There may not always be an instance when editing a show * This will be the case when we are adding a new show day to * a repeating show */ if ($this->isUpdate) { if ($this->hasInstance($utcStartDateTime)) { $ccShowInstance = $this->getInstance($utcStartDateTime); $newInstance = false; } else { $newInstance = true; $ccShowInstance = new CcShowInstances(); } } else { $newInstance = true; $ccShowInstance = new CcShowInstances(); } /* When editing the start/end time of a repeating show, we don't want to * change shows that are in the past so we check the end time. */ if ($newInstance || $ccShowInstance->getDbEnds() > gmdate(DEFAULT_TIMESTAMP_FORMAT)) { $ccShowInstance->setDbShowId($show_id); $ccShowInstance->setDbStarts($utcStartDateTime); $ccShowInstance->setDbEnds($utcEndDateTime); $ccShowInstance->setDbRecord($record); $ccShowInstance->save(); } if ($newInstance) { array_push($this->newInstanceIdsCreated[$show_id], $ccShowInstance->getDbId()); } if ($this->isRebroadcast) { $this->createRebroadcastInstances($showDay, $date, $ccShowInstance->getDbId()); } } $previousDate = clone $date; } /* We need to set the next populate date for repeat shows so when a user * moves forward in the calendar we know when to start generating new * show instances. * If $utcStartDateTime is not set then we know zero new shows were * created and we shouldn't update the next populate date. */ if (isset($lastCreatedShow)) { /* Set UTC to local time before setting the next repeat date. If we don't * the next repeat date might be scheduled for the following day * THIS MUST BE IN THE TIMEZONE THE SHOW WAS CREATED IN */ $lastCreatedShow->setTimezone(new DateTimeZone($timezone)); $nextDate = $lastCreatedShow->add($repeatInterval); $this->setNextRepeatingShowDate($nextDate->format('Y-m-d'), $day, $show_id); } } private function createMonthlyRepeatInstances($showDay, $populateUntil) { $show_id = $showDay->getDbShowId(); $first_show = $showDay->getDbFirstShow(); // non-UTC $last_show = $showDay->getDbLastShow(); // non-UTC $duration = $showDay->getDbDuration(); $day = $showDay->getDbDay(); $record = $showDay->getDbRecord(); $timezone = $showDay->getDbTimezone(); // DateTime local $start = $this->getNextRepeatingPopulateStartDateTime($showDay); if (isset($last_show)) { $end = new DateTime($last_show, new DateTimeZone($timezone)); } else { $end = $populateUntil; } // We will only need this if the repeat type is MONTHLY_WEEKLY [$weekNumberOfMonth, $dayOfWeek] = self::getMonthlyWeeklyRepeatInterval( new DateTime($first_show, new DateTimeZone($timezone)) ); $this->repeatType = $showDay->getDbRepeatType(); if ($last_show) { $utcLastShowDateTime = new DateTime($last_show, new DateTimeZone($timezone)); $utcLastShowDateTime->setTimezone(new DateTimeZone('UTC')); } else { $utcLastShowDateTime = null; } while ($start->getTimestamp() < $end->getTimestamp()) { [$utcStartDateTime, $utcEndDateTime] = $this->createUTCStartEndDateTime( $start, $duration ); /* * Make sure start date is less than populate until date AND * last show date is null OR start date is less than last show date */ if ( $utcStartDateTime->getTimestamp() <= $populateUntil->getTimestamp() && (is_null($utcLastShowDateTime) || $utcStartDateTime->getTimestamp() < $utcLastShowDateTime->getTimestamp()) ) { $lastCreatedShow = clone $utcStartDateTime; /* There may not always be an instance when editing a show * This will be the case when we are adding a new show day to * a repeating show */ if ($this->isUpdate && $this->hasInstance($utcStartDateTime)) { $ccShowInstance = $this->getInstance($utcStartDateTime); $newInstance = false; } else { $newInstance = true; $ccShowInstance = new CcShowInstances(); } /* When editing the start/end time of a repeating show, we don't want to * change shows that started in the past. So check the start time. */ if ($newInstance || $ccShowInstance->getDbStarts() > gmdate(DEFAULT_TIMESTAMP_FORMAT)) { $ccShowInstance->setDbShowId($show_id); $ccShowInstance->setDbStarts($utcStartDateTime); $ccShowInstance->setDbEnds($utcEndDateTime); $ccShowInstance->setDbRecord($record); $ccShowInstance->save(); } if ($newInstance) { array_push($this->newInstanceIdsCreated[$show_id], $ccShowInstance->getDbId()); } if ($this->isRebroadcast) { $this->createRebroadcastInstances($showDay, $start, $ccShowInstance->getDbId()); } } if ($this->repeatType == REPEAT_MONTHLY_WEEKLY) { $monthlyWeeklyStart = new DateTime( $utcStartDateTime->format('Y-m'), new DateTimeZone('UTC') ); $monthlyWeeklyStart->add(new DateInterval('P1M')); $start = self::getNextMonthlyWeeklyRepeatDate( $monthlyWeeklyStart, $timezone, $showDay->getDbStartTime(), $weekNumberOfMonth, $dayOfWeek ); } else { $start = $this->getNextMonthlyMonthlyRepeatDate( $start, $timezone, $showDay->getDbStartTime() ); } } $this->setNextRepeatingShowDate($start->format('Y-m-d'), $day, $show_id); } /** * i.e. last thursday of each month * i.e. second monday of each month. * * @param string $showStart */ public static function getMonthlyWeeklyRepeatInterval($showStart) { $start = clone $showStart; $dayOfMonth = $start->format('j'); $dayOfWeek = $start->format('l'); $yearAndMonth = $start->format('Y-m'); $firstDayOfWeek = strtotime($dayOfWeek . ' ' . $yearAndMonth); // if $dayOfWeek is Friday, what number of the month does // the first Friday fall on $numberOfFirstDayOfWeek = date('j', $firstDayOfWeek); $weekCount = 0; while ($dayOfMonth >= $numberOfFirstDayOfWeek) { ++$weekCount; $dayOfMonth -= 7; } switch ($weekCount) { case 1: $weekNumberOfMonth = 'first'; break; case 2: $weekNumberOfMonth = 'second'; break; case 3: $weekNumberOfMonth = 'third'; break; case 4: $weekNumberOfMonth = 'fourth'; break; case 5: $weekNumberOfMonth = 'fifth'; break; } /* return DateInterval::createFromDateString( $weekNumberOfMonth." ".$dayOfWeek." of next month"); */ return [$weekNumberOfMonth, $dayOfWeek]; } /** * Enter description here ... * * @param $start user's local time * @param mixed $timezone * @param mixed $startTime */ private function getNextMonthlyMonthlyRepeatDate($start, $timezone, $startTime) { $dt = new DateTime($start->format('Y-m'), new DateTimeZone($timezone)); do { $dt->add(new DateInterval('P1M')); } while (!checkdate($dt->format('m'), $start->format('d'), $dt->format('Y'))); $dt->setDate($dt->format('Y'), $dt->format('m'), $start->format('d')); $startTime = explode(':', $startTime); $hours = isset($startTime[0]) ? $startTime[0] : '00'; $minutes = isset($startTime[1]) ? $startTime[1] : '00'; $seconds = isset($startTime[2]) ? $startTime[2] : '00'; $dt->setTime($hours, $minutes, $seconds); return $dt; } /** * Returns a DateTime object of when the next repeating show that repeats * monthly, by day of the week (i.e. every fourth Tuesday) should be created. * * @param DateTime $start * $start only has the year and month of the next show * @param string $timezone * @param string (i.e. '14:30' $startTime * @param string (i.e. 'first', 'second') $weekNumberOfMonth * @param string (i.e. 'Monday') $dayOfWeek */ public static function getNextMonthlyWeeklyRepeatDate( $start, $timezone, $startTime, $weekNumberOfMonth, $dayOfWeek ) { $dt = new DateTime($start->format('Y-m'), new DateTimeZone($timezone)); $tempDT = clone $dt; $fifthWeekExists = false; do { $nextDT = date_create($weekNumberOfMonth . ' ' . $dayOfWeek . ' of ' . $tempDT->format('F') . ' ' . $tempDT->format('Y')); $nextDT->setTimezone(new DateTimeZone($timezone)); /* We have to check if the next date is in the same month in case * the repeat day is in the fifth week of the month. * If it's not in the same month we know that a fifth week of * the next month does not exist. So let's skip it. */ if ($tempDT->format('F') == $nextDT->format('F')) { $fifthWeekExists = true; } $tempDT->add(new DateInterval('P1M')); } while (!$fifthWeekExists); $dt = $nextDT; $startTime = explode(':', $startTime); $hours = isset($startTime[0]) ? $startTime[0] : '00'; $minutes = isset($startTime[1]) ? $startTime[1] : '00'; $seconds = isset($startTime[2]) ? $startTime[2] : '00'; $dt->setTime($hours, $minutes, $seconds); return $dt; } private function getNextRepeatingPopulateStartDateTime($showDay) { $nextPopDate = $showDay->getDbNextPopDate(); $startTime = $showDay->getDbStartTime(); if (isset($nextPopDate)) { return new DateTime($nextPopDate . ' ' . $startTime, new DateTimeZone($showDay->getDbTimezone())); } return new DateTime($showDay->getDbFirstShow() . ' ' . $startTime, new DateTimeZone($showDay->getDbTimezone())); } /** * Create a DatePeriod object in the user's local time * It will get converted to UTC before the show instance gets created. * * @param mixed $start * @param mixed $timezone * @param mixed $lastShow * @param mixed $repeatInterval * @param mixed $populateUntil */ private function getDatePeriod($start, $timezone, $lastShow, $repeatInterval, $populateUntil) { if (isset($lastShow)) { $endDatePeriod = new DateTime($lastShow, new DateTimeZone($timezone)); } else { $endDatePeriod = $populateUntil; } return new DatePeriod($start, $repeatInterval, $endDatePeriod); } private function hasInstance($starts) { return $this->getInstance($starts) ? true : false; } /** * Attempts to retrieve the cc_show_instance belonging to a cc_show * that starts at $starts. We have to pass in the start * time in case the show is repeating. * * Returns the instance if one was found (one that is not a recording * and modified instance is false (has not been deleted)) * * @param mixed $starts */ private function getInstance($starts) { $temp = clone $starts; $temp->setTimezone(new DateTimeZone($this->oldShowTimezone)); $temp->setTime($this->localShowStartHour, $this->localShowStartMin); $temp->setTimezone(new DateTimeZone('UTC')); $ccShowInstance = CcShowInstancesQuery::create() ->filterByDbStarts($temp->format(DEFAULT_TIMESTAMP_FORMAT), Criteria::EQUAL) ->filterByDbShowId($this->ccShow->getDbId(), Criteria::EQUAL) // ->filterByDbModifiedInstance(false, Criteria::EQUAL) ->filterByDbRebroadcast(0, Criteria::EQUAL) ->limit(1) ->find(); if ($ccShowInstance->isEmpty()) { return false; } return $ccShowInstance[0]; } private function hasCcShowDay($repeatType, $day) { return $this->getCcShowDay($repeatType, $day) ? true : false; } private function getCcShowDay($repeatType, $day) { $ccShowDay = CcShowDaysQuery::create() ->filterByDbShowId($this->ccShow->getDbId()) ->filterByDbDay($day) ->filterByDbRepeatType($repeatType) ->limit(1) ->find(); if ($ccShowDay->isEmpty()) { return false; } return $ccShowDay[0]; } /** * Sets the fields for a cc_show table row. * * @param mixed $showData */ public function setCcShow($showData) { if (!$this->isUpdate) { $ccShow = new CcShow(); } else { $ccShow = CcShowQuery::create()->findPk($showData['add_show_id']); } $ccShow->setDbName($showData['add_show_name']); $ccShow->setDbDescription($showData['add_show_description']); $ccShow->setDbUrl($showData['add_show_url']); $ccShow->setDbGenre($showData['add_show_genre']); $ccShow->setDbColor($showData['add_show_color']); $ccShow->setDbBackgroundColor($showData['add_show_background_color']); $ccShow->setDbLiveStreamUsingAirtimeAuth($showData['cb_airtime_auth'] == 1); $ccShow->setDbLiveStreamUsingCustomAuth($showData['cb_custom_auth'] == 1); $ccShow->setDbLiveStreamUser($showData['custom_username']); $ccShow->setDbLiveStreamPass($showData['custom_password']); $ccShow->setDbHasAutoPlaylist($showData['add_show_has_autoplaylist'] == 1); $ccShow->setDbAutoPlaylistRepeat($showData['add_show_autoplaylist_repeat'] == 1); // added to prevent errors with insert due to a lack of data if ($showData['add_show_autoplaylist_id'] != '') { $ccShow->setDbAutoPlaylistId($showData['add_show_autoplaylist_id']); } $ccShow->setDbOverrideIntroPlaylist($showData['add_show_intro_playlist_id'] != 0); if ($showData['add_show_intro_playlist_id'] != '') { $ccShow->setDbIntroPlaylistId($showData['add_show_intro_playlist_id']); } $ccShow->setDbOverrideOutroPlaylist($showData['add_show_outro_playlist_id'] != 0); if ($showData['add_show_outro_playlist_id'] != '') { $ccShow->setDbOutroPlaylistId($showData['add_show_outro_playlist_id']); } // Here a user has edited a show and linked it. // We need to grab the existing show instances ids and fill their content // with the content from the show instance that was clicked on to edit the show. // We do this because linked show instances need to have the same content in each. if ($this->isUpdate && (!$ccShow->getDbLinked() && $showData['add_show_linked'])) { $existingShowInstanceIds = $ccShow->getFutureInstanceIds(new Criteria()); Application_Service_SchedulerService::fillLinkedInstances($ccShow, $existingShowInstanceIds, $showData['add_show_instance_id']); } $ccShow->setDbLinked($showData['add_show_linked']); $ccShow->save(); $this->ccShow = $ccShow; } /** * Sets the fields for a cc_show_days table row. * * @param mixed $showData */ private function setCcShowDays($showData) { $showId = $this->ccShow->getDbId(); $startDateTime = new DateTime( $showData['add_show_start_date'] . ' ' . $showData['add_show_start_time'], new DateTimeZone($showData['add_show_timezone']) ); $endDateTime = $this->calculateEndDate($showData); if (!is_null($endDateTime)) { $endDate = $endDateTime->format('Y-m-d'); } else { $endDate = null; } // Our calculated start DOW must be used for non repeating since a day has not been selected. // For all repeating shows, only the selected days of the week will be repeated on. $startDow = $startDateTime->format('w'); if (!$showData['add_show_repeats']) { $showData['add_show_day_check'] = [$startDow]; } // Don't set day for monthly repeat type, it's invalid if ($showData['add_show_repeats'] && $showData['add_show_repeat_type'] == 2) { if ($this->isUpdate) { $showDay = CcShowDaysQuery::create() ->filterByDbShowId($showId) ->filterByDbRepeatType($this->origCcShowDay->getDbRepeatType()) ->findOne(); if (!$showDay) { // repeat type changed so we have to create a new show_day rule $showDay = new CcShowDays(); } } else { $showDay = new CcShowDays(); } $showDay->setDbFirstShow($startDateTime->format('Y-m-d')); $showDay->setDbLastShow($endDate); $showDay->setDbStartTime($startDateTime->format('H:i:s')); $showDay->setDbTimezone($showData['add_show_timezone']); $showDay->setDbDuration($showData['add_show_duration']); $showDay->setDbRepeatType($this->repeatType); $showDay->setDbShowId($showId); $showDay->setDbRecord($this->isRecorded); // in case we are editing a show we need to set this to the first show // so when editing, the date period iterator will start from the beginning $showDay->setDbNextPopDate($startDateTime->format('Y-m-d')); $showDay->save(); } else { foreach ($showData['add_show_day_check'] as $day) { $daysAdd = 0; $startDateTimeClone = clone $startDateTime; if ($startDow !== $day) { if ($startDow > $day) { $daysAdd = 6 - $startDow + 1 + $day; } else { $daysAdd = $day - $startDow; } $startDateTimeClone->add(new DateInterval('P' . $daysAdd . 'D')); } if (is_null($endDate) || $startDateTimeClone->getTimestamp() <= $endDateTime->getTimestamp()) { if ($this->isUpdate) { if ( $this->origCcShowDay->getDbRepeatType() == 2 || $this->origCcShowDay->getDbRepeatType() == 3 ) { $day = null; } elseif (!$this->origShowRepeatStatus) { // keep current show day to use for updating cc_show_day rule $keepDay = $day; $day = $this->origCcShowDay->getDbDay(); } $showDay = CcShowDaysQuery::create() ->filterByDbShowId($showId) ->filterByDbRepeatType($this->origCcShowDay->getDbRepeatType()) ->filterByDbDay($day) ->findOne(); if (!$showDay) { // if no show day object was found it is because a new // repeating day of the week was added OR the repeat // type has changed $showDay = new CcShowDays(); } if (isset($keepDay)) { $day = $keepDay; } } else { $showDay = new CcShowDays(); } $showDay->setDbFirstShow($startDateTimeClone->format('Y-m-d')); $showDay->setDbLastShow($endDate); $showDay->setDbStartTime($startDateTimeClone->format('H:i')); $showDay->setDbTimezone($showData['add_show_timezone']); $showDay->setDbDuration($showData['add_show_duration']); $showDay->setDbDay($day); $showDay->setDbRepeatType($this->repeatType); $showDay->setDbShowId($showId); $showDay->setDbRecord($this->isRecorded); // in case we are editing a show we need to set this to the first show // so when editing, the date period iterator will start from the beginning $showDay->setDbNextPopDate($startDateTimeClone->format('Y-m-d')); $showDay->save(); } } } } /** * Deletes all the cc_show_rebroadcast entries for a specific show * that is currently being edited. They will get recreated with * the new show specs. */ private function deleteCcShowRebroadcasts() { CcShowRebroadcastQuery::create()->filterByDbShowId($this->ccShow->getDbId())->delete(); } /** * Sets the fields for a cc_show_rebroadcast table row. * * @param mixed $showData */ private function setCcShowRebroadcasts($showData) { $showId = $this->ccShow->getDbId(); if (($this->isRecorded && $showData['add_show_rebroadcast']) && ($this->repeatType != -1)) { for ($i = 1; $i <= MAX_REBROADCAST_DATES; ++$i) { if ($showData['add_show_rebroadcast_date_' . $i]) { $showRebroad = new CcShowRebroadcast(); $showRebroad->setDbDayOffset($showData['add_show_rebroadcast_date_' . $i]); $showRebroad->setDbStartTime($showData['add_show_rebroadcast_time_' . $i]); $showRebroad->setDbShowId($showId); $showRebroad->save(); } } } elseif ($this->isRecorded && $showData['add_show_rebroadcast'] && ($this->repeatType == -1)) { for ($i = 1; $i <= MAX_REBROADCAST_DATES; ++$i) { if ($showData['add_show_rebroadcast_date_absolute_' . $i]) { $rebroadcastDate = new DateTime($showData["add_show_rebroadcast_date_absolute_{$i}"]); $startDate = new DateTime($showData['add_show_start_date']); $offsetDays = $startDate->diff($rebroadcastDate); $showRebroad = new CcShowRebroadcast(); $showRebroad->setDbDayOffset($offsetDays->format('%a days')); $showRebroad->setDbStartTime($showData['add_show_rebroadcast_time_absolute_' . $i]); $showRebroad->setDbShowId($showId); $showRebroad->save(); } } } } /** * Deletes all the cc_show_hosts entries for a specific show * that is currently being edited. They will get recreated with * the new show specs. */ private function deleteCcShowHosts() { CcShowHostsQuery::create()->filterByDbShow($this->ccShow->getDbId())->delete(); } /** * Sets the fields for a cc_show_hosts table row. * * @param mixed $showData */ private function setCcShowHosts($showData) { if (is_array($showData['add_show_hosts'])) { foreach ($showData['add_show_hosts'] as $host) { $showHost = new CcShowHosts(); $showHost->setDbShow($this->ccShow->getDbId()); $showHost->setDbHost($host); $showHost->save(); } } } /** * 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; } /** * Enter description here ... * * @param DateTime $showStart user's local time * @param string $duration time interval (h)h:(m)m(:ss) * @param array $offset (days, hours, mins) used for rebroadcast shows * * @return array of 2 DateTime objects, start/end time of the show in UTC */ private function createUTCStartEndDateTime($showStart, $duration, $offset = null) { $startDateTime = clone $showStart; $timezone = $startDateTime->getTimezone(); if (isset($offset)) { // $offset["hours"] and $offset["mins"] represents the start time // of a rebroadcast show $startDateTime = new DateTime($startDateTime->format('Y-m-d') . ' ' . $offset['hours'] . ':' . $offset['mins'], $timezone); $startDateTime->add(new DateInterval("P{$offset['days']}D")); } $endDateTime = clone $startDateTime; $duration = explode(':', $duration); [$hours, $mins] = array_slice($duration, 0, 2); $endDateTime->add(new DateInterval("PT{$hours}H{$mins}M")); $startDateTime->setTimezone(new DateTimeZone('UTC')); $endDateTime->setTimezone(new DateTimeZone('UTC')); return [$startDateTime, $endDateTime]; } /** * Show instances for repeating shows only get created up * until what is visible on the calendar. We need to set the * date for when the next repeating show instance should be created * as the user browses the calendar further. * * @param mixed $nextDate * @param mixed $day * @param mixed $showId */ private function setNextRepeatingShowDate($nextDate, $day, $showId) { $nextInfo = explode(' ', $nextDate); $repeatInfo = CcShowDaysQuery::create() ->filterByDbShowId($showId) ->filterByDbDay($day) ->filterByDbRepeatType(-1, Criteria::NOT_EQUAL) ->findOne(); $repeatInfo->setDbNextPopDate($nextInfo[0]) ->save(); } }