AddShowWhen.php 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. <?php
  2. class Application_Form_AddShowWhen extends Zend_Form_SubForm
  3. {
  4. public function init()
  5. {
  6. $this->setDecorators(array(
  7. array('ViewScript', array('viewScript' => 'form/add-show-when.phtml'))
  8. ));
  9. $notEmptyValidator = Application_Form_Helper_ValidationTypes::overrideNotEmptyValidator();
  10. $dateValidator = Application_Form_Helper_ValidationTypes::overrrideDateValidator("YYYY-MM-DD");
  11. $regexValidator = Application_Form_Helper_ValidationTypes::overrideRegexValidator(
  12. "/^[0-2]?[0-9]:[0-5][0-9]$/",
  13. _("'%value%' does not fit the time format 'HH:mm'"));
  14. // Add start date element
  15. $startDate = new Zend_Form_Element_Text('add_show_start_date');
  16. $startDate->class = 'input_text';
  17. $startDate->setRequired(true)
  18. ->setLabel(_('Date/Time Start:'))
  19. ->setValue(date("Y-m-d"))
  20. ->setFilters(array('StringTrim'))
  21. ->setValidators(array(
  22. $notEmptyValidator,
  23. $dateValidator))
  24. ->setDecorators(array('ViewHelper'));
  25. $startDate->setAttrib('alt', 'date');
  26. $this->addElement($startDate);
  27. // Add start time element
  28. $startTime = new Zend_Form_Element_Text('add_show_start_time');
  29. $startTime->class = 'input_text';
  30. $startTime->setRequired(true)
  31. ->setValue('00:00')
  32. ->setFilters(array('StringTrim'))
  33. ->setValidators(array(
  34. $notEmptyValidator,
  35. $regexValidator
  36. ))->setDecorators(array('ViewHelper'));
  37. $startTime->setAttrib('alt', 'time');
  38. $this->addElement($startTime);
  39. // Add end date element
  40. $endDate = new Zend_Form_Element_Text('add_show_end_date_no_repeat');
  41. $endDate->class = 'input_text';
  42. $endDate->setRequired(true)
  43. ->setLabel(_('Date/Time End:'))
  44. ->setValue(date("Y-m-d"))
  45. ->setFilters(array('StringTrim'))
  46. ->setValidators(array(
  47. $notEmptyValidator,
  48. $dateValidator))
  49. ->setDecorators(array('ViewHelper'));
  50. $endDate->setAttrib('alt', 'date');
  51. $this->addElement($endDate);
  52. // Add end time element
  53. $endTime = new Zend_Form_Element_Text('add_show_end_time');
  54. $endTime->class = 'input_text';
  55. $endTime->setRequired(true)
  56. ->setValue('01:00')
  57. ->setFilters(array('StringTrim'))
  58. ->setValidators(array(
  59. $notEmptyValidator,
  60. $regexValidator))
  61. ->setDecorators(array('ViewHelper'));
  62. $endTime->setAttrib('alt', 'time');
  63. $this->addElement($endTime);
  64. // Add duration element
  65. $this->addElement('text', 'add_show_duration', array(
  66. 'label' => _('Duration:'),
  67. 'class' => 'input_text',
  68. 'value' => '01h 00m',
  69. 'readonly' => true,
  70. 'decorators' => array('ViewHelper')
  71. ));
  72. $timezone = new Zend_Form_Element_Select('add_show_timezone');
  73. $timezone->setRequired(true)
  74. ->setLabel(_("Timezone:"))
  75. ->setMultiOptions(Application_Common_Timezone::getTimezones())
  76. ->setValue(Application_Model_Preference::GetUserTimezone())
  77. ->setAttrib('class', 'input_select add_show_input_select')
  78. ->setDecorators(array('ViewHelper'));
  79. $this->addElement($timezone);
  80. // Add repeats element
  81. $this->addElement('checkbox', 'add_show_repeats', array(
  82. 'label' => _('Repeats?'),
  83. 'required' => false,
  84. 'decorators' => array('ViewHelper')
  85. ));
  86. }
  87. public function isWhenFormValid($formData, $validateStartDate, $originalStartDate,
  88. $update, $instanceId) {
  89. if (parent::isValid($formData)) {
  90. return self::checkReliantFields($formData, $validateStartDate,
  91. $originalStartDate, $update, $instanceId);
  92. } else {
  93. return false;
  94. }
  95. }
  96. public function checkReliantFields($formData, $validateStartDate, $originalStartDate=null, $update=false, $instanceId=null)
  97. {
  98. $valid = true;
  99. $start_time = $formData['add_show_start_date']." ".$formData['add_show_start_time'];
  100. $end_time = $formData['add_show_end_date_no_repeat']." ".$formData['add_show_end_time'];
  101. //have to use the timezone the user has entered in the form to check past/present
  102. $showTimezone = new DateTimeZone($formData["add_show_timezone"]);
  103. $nowDateTime = new DateTime("now", $showTimezone);
  104. $showStartDateTime = new DateTime($start_time, $showTimezone);
  105. $showEndDateTime = new DateTime($end_time, $showTimezone);
  106. if ($validateStartDate) {
  107. if ($showStartDateTime < $nowDateTime) {
  108. $this->getElement('add_show_start_time')->setErrors(array(_('Cannot create show in the past')));
  109. $valid = false;
  110. }
  111. // if edit action, check if original show start time is in the past. CC-3864
  112. if ($originalStartDate) {
  113. if ($originalStartDate < $nowDateTime) {
  114. $this->getElement('add_show_start_time')->setValue($originalStartDate->format("H:i"));
  115. $this->getElement('add_show_start_date')->setValue($originalStartDate->format("Y-m-d"));
  116. $this->getElement('add_show_start_time')->setErrors(array(_('Cannot modify start date/time of the show that is already started')));
  117. $this->disableStartDateAndTime();
  118. $valid = false;
  119. }
  120. }
  121. }
  122. // if end time is in the past, return error
  123. if ($showEndDateTime < $nowDateTime) {
  124. $this->getElement('add_show_end_time')->setErrors(array(_('End date/time cannot be in the past')));
  125. $valid = false;
  126. }
  127. //validate duration.
  128. $duration = $showStartDateTime->diff($showEndDateTime);
  129. if ($showStartDateTime > $showEndDateTime) {
  130. $this->getElement('add_show_duration')->setErrors(array(_('Cannot have duration < 0m')));
  131. $valid = false;
  132. }
  133. else if ($showStartDateTime == $showEndDateTime) {
  134. $this->getElement('add_show_duration')->setErrors(array(_('Cannot have duration 00h 00m')));
  135. $valid = false;
  136. }
  137. else if (intval($duration->format('%d')) > 0 &&
  138. (intval($duration->format('%h')) > 0
  139. || intval($duration->format('%i')) > 0
  140. || intval($duration->format('%s')) > 0)) {
  141. $this->getElement('add_show_duration')->setErrors(array(_('Cannot have duration greater than 24h')));
  142. $valid = false;
  143. }
  144. /* We need to know the show duration broken down into hours and minutes
  145. * They are used for checking overlapping shows and for validating
  146. * rebroadcast instances
  147. */
  148. $hours = $duration->format("%h");
  149. $minutes = $duration->format("%i");
  150. /* Check if show is overlapping
  151. * We will only do this check if the show is valid
  152. * upto this point
  153. */
  154. if ($valid) {
  155. //we need to know the start day of the week in show's local timezome
  156. $startDow = $showStartDateTime->format("w");
  157. $utc = new DateTimeZone('UTC');
  158. $showStartDateTime->setTimezone($utc);
  159. $showEndDateTime->setTimezone($utc);
  160. if ($formData["add_show_repeats"]) {
  161. //get repeating show end date
  162. if ($formData["add_show_no_end"]) {
  163. $date = Application_Model_Preference::GetShowsPopulatedUntil();
  164. if (is_null($date)) {
  165. $populateUntilDateTime = new DateTime("now", $utc);
  166. Application_Model_Preference::SetShowsPopulatedUntil($populateUntilDateTime);
  167. } else {
  168. $populateUntilDateTime = clone $date;
  169. }
  170. } elseif (!$formData["add_show_no_end"]) {
  171. $popUntil = $formData["add_show_end_date"]." ".$formData["add_show_end_time"];
  172. $populateUntilDateTime = new DateTime($popUntil, $showTimezone);
  173. $populateUntilDateTime->setTimezone($utc);
  174. }
  175. //get repeat interval
  176. if ($formData["add_show_repeat_type"] == 0) {
  177. $interval = 'P7D';
  178. } elseif ($formData["add_show_repeat_type"] == 1) {
  179. $interval = 'P14D';
  180. } elseif ($formData["add_show_repeat_type"] == 4) {
  181. $interval = 'P21D';
  182. } elseif ($formData["add_show_repeat_type"] == 5) {
  183. $interval = 'P28D';
  184. } elseif ($formData["add_show_repeat_type"] == 2 && $formData["add_show_monthly_repeat_type"] == 2) {
  185. $interval = 'P1M';
  186. } elseif ($formData["add_show_repeat_type"] == 2 && $formData["add_show_monthly_repeat_type"] == 3) {
  187. list($weekNumberOfMonth, $dayOfWeek) =
  188. Application_Service_ShowService::getMonthlyWeeklyRepeatInterval(
  189. new DateTime($start_time, $showTimezone));
  190. }
  191. /* Check first show
  192. * Continue if the first show does not overlap
  193. */
  194. if ($update) {
  195. $overlapping = Application_Model_Schedule::checkOverlappingShows(
  196. $showStartDateTime, $showEndDateTime, $update, null, $formData["add_show_id"]);
  197. } else {
  198. $overlapping = Application_Model_Schedule::checkOverlappingShows(
  199. $showStartDateTime, $showEndDateTime);
  200. }
  201. /* Check if repeats overlap with previously scheduled shows
  202. * Do this for each show day
  203. */
  204. if (!$overlapping) {
  205. if (!isset($formData['add_show_day_check'])) {
  206. return false;
  207. }
  208. foreach ($formData["add_show_day_check"] as $day) {
  209. $repeatShowStart = clone $showStartDateTime;
  210. $repeatShowEnd = clone $showEndDateTime;
  211. $daysAdd=0;
  212. if ($startDow !== $day) {
  213. if ($startDow > $day)
  214. $daysAdd = 6 - $startDow + 1 + $day;
  215. else
  216. $daysAdd = $day - $startDow;
  217. /* In case we are crossing daylights saving time we need
  218. * to convert show start and show end to local time before
  219. * adding the interval for the next repeating show
  220. */
  221. $repeatShowStart->setTimezone($showTimezone);
  222. $repeatShowEnd->setTimezone($showTimezone);
  223. $repeatShowStart->add(new DateInterval("P".$daysAdd."D"));
  224. $repeatShowEnd->add(new DateInterval("P".$daysAdd."D"));
  225. //set back to UTC
  226. $repeatShowStart->setTimezone($utc);
  227. $repeatShowEnd->setTimezone($utc);
  228. }
  229. /* Here we are checking each repeating show by
  230. * the show day.
  231. * (i.e: every wednesday, then every thursday, etc.)
  232. */
  233. while ($repeatShowStart->getTimestamp() < $populateUntilDateTime->getTimestamp()) {
  234. if ($formData['add_show_id'] == -1) {
  235. //this is a new show
  236. $overlapping = Application_Model_Schedule::checkOverlappingShows(
  237. $repeatShowStart, $repeatShowEnd);
  238. /* If the repeating show is rebroadcasted we need to check
  239. * the rebroadcast dates relative to the repeating show
  240. */
  241. if (!$overlapping && $formData['add_show_rebroadcast']) {
  242. $overlapping = self::checkRebroadcastDates(
  243. $repeatShowStart, $formData, $hours, $minutes);
  244. }
  245. } else {
  246. $overlapping = Application_Model_Schedule::checkOverlappingShows(
  247. $repeatShowStart, $repeatShowEnd, $update, null, $formData["add_show_id"]);
  248. if (!$overlapping && $formData['add_show_rebroadcast']) {
  249. $overlapping = self::checkRebroadcastDates(
  250. $repeatShowStart, $formData, $hours, $minutes, true);
  251. }
  252. }
  253. if ($overlapping) {
  254. $valid = false;
  255. $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows')));
  256. break 1;
  257. } else {
  258. if ($formData["add_show_repeat_type"] == 2 && $formData["add_show_monthly_repeat_type"] == 3) {
  259. $monthlyWeeklyStart = new DateTime($repeatShowStart->format("Y-m"),
  260. new DateTimeZone("UTC"));
  261. $monthlyWeeklyStart->add(new DateInterval("P1M"));
  262. $repeatShowStart = clone Application_Service_ShowService::getNextMonthlyWeeklyRepeatDate(
  263. $monthlyWeeklyStart,
  264. $formData["add_show_timezone"],
  265. $formData['add_show_start_time'],
  266. $weekNumberOfMonth,
  267. $dayOfWeek);
  268. $repeatShowEnd = clone $repeatShowStart;
  269. $repeatShowEnd->add(new DateInterval("PT".$hours."H".$minutes."M"));
  270. } else {
  271. $repeatShowStart->setTimezone($showTimezone);
  272. $repeatShowEnd->setTimezone($showTimezone);
  273. $repeatShowStart->add(new DateInterval($interval));
  274. $repeatShowEnd->add(new DateInterval($interval));
  275. $repeatShowStart->setTimezone($utc);
  276. $repeatShowEnd->setTimezone($utc);
  277. }
  278. }
  279. }
  280. }
  281. } else {
  282. $valid = false;
  283. $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows')));
  284. }
  285. } elseif ($formData["add_show_rebroadcast"]) {
  286. /* Check first show
  287. * Continue if the first show does not overlap
  288. */
  289. $overlapping = Application_Model_Schedule::checkOverlappingShows($showStartDateTime, $showEndDateTime, $update, $instanceId);
  290. if (!$overlapping) {
  291. $durationToAdd = "PT".$hours."H".$minutes."M";
  292. for ($i = 1; $i <= 10; $i++) {
  293. if (empty($formData["add_show_rebroadcast_date_absolute_".$i])) break;
  294. $abs_rebroadcast_start = $formData["add_show_rebroadcast_date_absolute_".$i]." ".
  295. $formData["add_show_rebroadcast_time_absolute_".$i];
  296. $rebroadcastShowStart = new DateTime($abs_rebroadcast_start);
  297. $rebroadcastShowStart->setTimezone(new DateTimeZone('UTC'));
  298. $rebroadcastShowEnd = clone $rebroadcastShowStart;
  299. $rebroadcastShowEnd->add(new DateInterval($durationToAdd));
  300. $overlapping = Application_Model_Schedule::checkOverlappingShows($rebroadcastShowStart,
  301. $rebroadcastShowEnd, $update, null, $formData["add_show_id"]);
  302. if ($overlapping) {
  303. $valid = false;
  304. $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows')));
  305. break;
  306. }
  307. }
  308. } else {
  309. $valid = false;
  310. $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows')));
  311. }
  312. } else {
  313. $overlapping = Application_Model_Schedule::checkOverlappingShows($showStartDateTime, $showEndDateTime, $update, $instanceId);
  314. if ($overlapping) {
  315. $this->getElement('add_show_duration')->setErrors(array(_('Cannot schedule overlapping shows')));
  316. $valid = false;
  317. }
  318. }
  319. }
  320. return $valid;
  321. }
  322. public function checkRebroadcastDates($repeatShowStart, $formData, $hours, $minutes, $showEdit=false) {
  323. $overlapping = false;
  324. for ($i = 1; $i <= 10; $i++) {
  325. if (empty($formData["add_show_rebroadcast_date_".$i])) break;
  326. $rebroadcastShowStart = clone $repeatShowStart;
  327. /* formData is in local time so we need to set the
  328. * show start back to local time
  329. */
  330. $rebroadcastShowStart->setTimezone(new DateTimeZone(
  331. $formData["add_show_timezone"]));
  332. $rebroadcastWhenDays = explode(" ", $formData["add_show_rebroadcast_date_".$i]);
  333. $rebroadcastWhenTime = explode(":", $formData["add_show_rebroadcast_time_".$i]);
  334. $rebroadcastShowStart->add(new DateInterval("P".$rebroadcastWhenDays[0]."D"));
  335. $rebroadcastShowStart->setTime($rebroadcastWhenTime[0], $rebroadcastWhenTime[1]);
  336. $rebroadcastShowStart->setTimezone(new DateTimeZone('UTC'));
  337. $rebroadcastShowEnd = clone $rebroadcastShowStart;
  338. $rebroadcastShowEnd->add(new DateInterval("PT".$hours."H".$minutes."M"));
  339. if ($showEdit) {
  340. $overlapping = Application_Model_Schedule::checkOverlappingShows(
  341. $rebroadcastShowStart, $rebroadcastShowEnd, true, null, $formData['add_show_id']);
  342. } else {
  343. $overlapping = Application_Model_Schedule::checkOverlappingShows(
  344. $rebroadcastShowStart, $rebroadcastShowEnd);
  345. }
  346. if ($overlapping) break;
  347. }
  348. return $overlapping;
  349. }
  350. public function disable()
  351. {
  352. $elements = $this->getElements();
  353. foreach ($elements as $element) {
  354. if ($element->getType() != 'Zend_Form_Element_Hidden') {
  355. $element->setAttrib('disabled','disabled');
  356. }
  357. }
  358. }
  359. public function disableRepeatCheckbox()
  360. {
  361. $element = $this->getElement('add_show_repeats');
  362. if ($element->getType() != 'Zend_Form_Element_Hidden') {
  363. $element->setAttrib('disabled','disabled');
  364. }
  365. }
  366. public function disableStartDateAndTime()
  367. {
  368. $elements = array($this->getElement('add_show_start_date'), $this->getElement('add_show_start_time'));
  369. foreach ($elements as $element) {
  370. if ($element->getType() != 'Zend_Form_Element_Hidden') {
  371. $element->setAttrib('disabled','disabled');
  372. }
  373. }
  374. }
  375. }