Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
calendar_common.inc
1 <?php
17 /*
18 * Calendar Package Library Functions
19 *
20 * This file contains global functions that are useful throughout the calendar module
21 * (but not beyond)
22 *
23 * @author Tom Barrett <tbarrett@squiz.net>
24 * @author Luke Wright <lwright@squiz.net>
25 * @version $Revision: 1.79 $
26 * @package MySource_Matrix_Packages
27 * @subpackage calendar
28 */
29 
30 require_once SQ_FUDGE_PATH.'/general/datetime.inc';
31 require_once SQ_FUDGE_PATH.'/db_extras/db_extras.inc';
32 
34 {
35 
36 
48  function getSingleEventQueryBase($root_ids, $event_type_code='calendar_event_single', $include_exceptions=TRUE, &$bind_vars=Array())
49  {
50  $db = MatrixDAL::getDb();
51 
52  $type_codes = Calendar_Common::_getTypeDescendantsQuoted($event_type_code);
53  if ($include_exceptions) {
54  $type_codes = array_merge($type_codes, Calendar_Common::_getTypeDescendantsQuoted('calendar_event_cancellation'));
55  $type_codes = array_merge($type_codes, Calendar_Common::_getTypeDescendantsQuoted('calendar_event_modification'));
56  }
57 
58  $sql = 'SELECT a.assetid, a.type_code, a.name, t.treeid, cd.*'."\n";
59  if (!$GLOBALS['SQ_SYSTEM']->userSystemAdmin() && !$GLOBALS['SQ_SYSTEM']->userRoot()) {
60  $sql .= ', p.granted as granted';
61  }
62  $sql .= "\n".'FROM '.Calendar_Common::_getTableList()."\n";
63  $sql .= 'WHERE a.type_code IN ( '.implode(',', $type_codes).') '."\n";
64  $sql .= "\t".'AND (a.status >= '.MatrixDAL::quote(SQ_STATUS_LIVE).")\n\t";
65 
66  $sql .= ' AND '.Calendar_Common::_getTreeClause($root_ids);
67 
68  $bind_vars = Array();
69  if (!$GLOBALS['SQ_SYSTEM']->userSystemAdmin() && !$GLOBALS['SQ_SYSTEM']->userRoot()) {
70  $userids = $GLOBALS['SQ_SYSTEM']->am->getParents($GLOBALS['SQ_SYSTEM']->user->id, 'user_group', FALSE);
71  $userids[$GLOBALS['SQ_SYSTEM']->user->id] = 1;
72  $userids[$GLOBALS['SQ_SYSTEM']->am->getSystemAssetid('public_user')] = 1;
73  $user_count = 0;
74  foreach ($userids as $userid => $type) {
75  $bind_vars[$userid] = 'user'.$user_count++;
76  }
77  $userid_cond = ' AND p.userid IN (:'.implode(',:', $bind_vars).')';
78  $sql .= $userid_cond.' AND p.granted = \'1\' AND (p.permission >= '.MatrixDAL::quote(SQ_PERMISSION_WRITE).' OR (status >= '.MatrixDAL::quote(SQ_STATUS_LIVE).' AND p.permission >= '.MatrixDAL::quote(SQ_PERMISSION_READ).'))';
79  }
80 
81  return $sql;
82 
83  }//end getSingleEventQueryBase()
84 
85 
105  function getRecurringEventQueryBase($root_ids, $view, $iso, $length=NULL, $event_type='calendar_event_recurring', &$bind_vars=Array())
106  {
107  list($year,$month,$day) = sscanf(substr($iso,0,10), '%4d-%2d-%2d');
108  if (!$month) $month = 12;
109  if (!$day) $day = 1;
110  if (($view == 'period') && ($length == 0)) {
111  $view = 'day';
112  }
113 
114  $now = Calendar_Common::getDateComponents(sprintf('%04d-%02d-%02d', $year, $month, $day));
115  $wdom_list = weekday_dates_in_month($now['wday'], $month, $year);
116 
117  $db = MatrixDAL::getDb();
118 
119  $type_codes = Calendar_Common::_getTypeDescendantsQuoted($event_type);
120 
121  $sql = 'SELECT a.assetid, a.type_code, a.name, t.treeid, cd.*'."\n";
122  if (!$GLOBALS['SQ_SYSTEM']->userSystemAdmin() && !$GLOBALS['SQ_SYSTEM']->userRoot()) {
123  $sql .= ', p.granted as granted';
124  }
125  $sql .= "\nFROM ".Calendar_Common::_getTableList()." \nWHERE (a.type_code IN (".implode(',', $type_codes).")) \n\tAND (a.status >= ".MatrixDAL::quote(SQ_STATUS_LIVE).")\n";
126  $bind_vars = Array();
127  if (!$GLOBALS['SQ_SYSTEM']->userSystemAdmin() && !$GLOBALS['SQ_SYSTEM']->userRoot()) {
128  $userids = $GLOBALS['SQ_SYSTEM']->am->getParents($GLOBALS['SQ_SYSTEM']->user->id, 'user_group', FALSE);
129  $userids[$GLOBALS['SQ_SYSTEM']->user->id] = 1;
130  $userids[$GLOBALS['SQ_SYSTEM']->am->getSystemAssetid('public_user')] = 1;
131  $user_count = 0;
132  foreach ($userids as $userid => $type) {
133  $bind_vars[$userid] = 'user'.$user_count++;
134  }
135  $userid_cond = ' AND p.userid IN (:'.implode(',:', $bind_vars).')';
136  $sql .= $userid_cond.' AND p.granted = \'1\' AND (p.permission >= '.MatrixDAL::quote(SQ_PERMISSION_WRITE).' OR (status >= '.MatrixDAL::quote(SQ_STATUS_LIVE).' AND p.permission >= '.MatrixDAL::quote(SQ_PERMISSION_READ).'))';
137  }
138  $sql .= ' AND ';
139 
140  $sql_freqs = Array();
141 
142  switch ($view) {
143  case 'day' :
144  $last_day = $now['ds'];
145  $now['month_length'] = days_in_month($month, $year);
146  $now['month_start_wday'] = date('w', strtotime(sprintf('%04d-%02d-%02d', $year, $month, 1)));
147  $now['month_end_wday'] = date('w', strtotime(sprintf('%04d-%02d-%02d', $year, $month, $now['month_length'])));
148  $prev_month_length = date('t', strtotime('-1 month', $now['ts']));
149  $prev_month_start_wday = date('w', strtotime(sprintf('%04d-%02d-%02d', $year, $month, 1).' -1 month'));
150  $prev_month_end_wday = date('w', strtotime(sprintf('%04d-%02d-%02d', $year, $month, 1).' -1 day'));
151 
152  if (($now['wday'] != 0) && ($now['wday'] != 6)) {
153  $sql_freqs[] = 'frequency = '.MatrixDAL::quote('DWD');
154  } else {
155  $sql_freqs[] = 'frequency = '.MatrixDAL::quote('DWE');
156  }
157 
158  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('DED').' AND mod(('.MatrixDAL::quote($now['ds']).' - start_date_ds), period) BETWEEN 0 AND COALESCE(end_date_ds - start_date_ds,0))';
159 
160  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('WEW').' AND mod(('.MatrixDAL::quote($now['ds']).' - start_date_ds), (period*7)) BETWEEN 0 AND COALESCE(end_date_ds - start_date_ds,0))';
161 
162  $sql_freqs[] = '
163  (SUBSTR(frequency, 1, 1) = '.MatrixDAL::quote('M').') AND (
164  (
165  /* there is an instance that starts in our month */
166  (MOD('.MatrixDAL::quote($now['ms']).' - start_date_ms, period) = 0)
167  AND (
168  /* our view date is between the start and end of the instance */
169  ((frequency = '.MatrixDAL::quote('MFN').') AND (('.MatrixDAL::quote($now['mday']).' - start_date_mday) BETWEEN 0 AND (COALESCE((end_date_ds - start_date_ds), 0))))
170  OR ((frequency = '.MatrixDAL::quote('MRN').') AND ((start_date_rmday - '.MatrixDAL::quote($now['rmday']).') BETWEEN 0 AND (COALESCE((end_date_ds - start_date_ds), 0))))
171  OR ((frequency = '.MatrixDAL::quote('MFW').') AND (('.MatrixDAL::quote($now['mday']).' - (((start_date_wdom - 1) * 7) + MOD(start_date_wday + 7 - '.$now['month_start_wday'].', 7) + 1)) BETWEEN 0 AND (COALESCE((end_date_ds - start_date_ds), 0))))
172  OR ((frequency = '.MatrixDAL::quote('MRW').') AND ((((start_date_rwdom - 1) * 7) + MOD('.($now['month_end_wday'] + 7).' - start_date_wday, 7) + 1 - '.$now['rmday'].') BETWEEN 0 AND (COALESCE((end_date_ds - start_date_ds), 0))))
173  )
174  ) OR (
175  /* An instance that started in a previous month doesnt end til a subsequent month */
176  (MOD('.$now['ms'].' - start_date_ms, period) < MOD('.$now['ms'].' - end_date_ms, period))
177  ) OR (
178  /* An instance ends this month */
179  ((start_date_ms != end_date_ms) AND (MOD('.$now['ms'].' - end_date_ms, period) = 0))
180  AND (
181  /* its end is PROBABLY after our view date - we can only be ~90% sure here */
182  ((frequency = '.MatrixDAL::quote('MFN').')
183  AND ((end_date_ds - start_date_ds + 1) >= ROUND(('.MatrixDAL::quote($now['ts']).' - '.Calendar_Common::_ts2Sql('FLOOR((('.$now['year'].' * 12) + '.($now['mon']-1).' - (end_date_ms - start_date_ms)) / 12)', 'MOD('.$now['mon'].' + 10 - MOD('.($now['ms']-1).' - start_date_ms, period), 12) + 1', 'start_date_mday').') / 86400)))
184  OR ((frequency = '.MatrixDAL::quote('MRN').')
185  AND ((end_date_ds - start_date_ds + 1) >= ROUND(('.MatrixDAL::quote($now['ts']).' - '.Calendar_Common::_ts2Sql('FLOOR((('.$now['year'].' * 12) + '.($now['mon']-1).' - (end_date_ms - start_date_ms)) / 12)', 'MOD('.$now['mon'].' + 10 - MOD('.($now['ms']-1).' - start_date_ms, period), 12) + 1', '((start_date_mday + 3) - (FLOOR((start_date_mday + 3) / 31) * MOD(start_date_mday + 3, 31)))').') / 86400)))
186  OR ((frequency = '.MatrixDAL::quote('MFW').')
187  AND ((end_date_ds - start_date_ds + 1) >= ROUND(('.MatrixDAL::quote($now['ts']).' - '.Calendar_Common::_ts2Sql('FLOOR((('.$now['year'].' * 12) + '.($now['mon']-1).' - (end_date_ms - start_date_ms)) / 12)', 'MOD('.$now['mon'].' + 10 - MOD('.($now['ms']-1).' - start_date_ms, period), 12) + 1', '(7 * start_date_wdom) - (FLOOR((7 * start_date_wdom) / 31) * MOD(7 * start_date_wdom, 31))').') / 86400)))
188  OR ((frequency = '.MatrixDAL::quote('MRW').')
189  AND ((end_date_ds - start_date_ds + 1) >= ROUND(('.MatrixDAL::quote($now['ts']).' - '.Calendar_Common::_ts2Sql('FLOOR((('.$now['year'].' * 12) + '.($now['mon']-1).' - (end_date_ms - start_date_ms)) / 12)', 'MOD('.$now['mon'].' + 10 - MOD('.($now['ms']-1).' - start_date_ms, period), 12) + 1', '(31 - ((start_date_rwdom - 1) * 7))').') / 86400)))
190  )
191  ) OR (
192  /* An instance that started last month has run into our month
193  even though its original instance was contained in only one month
194  and it ends on/after our view date */
195  (MOD('.$now['ms'].' - start_date_ms, period) = 1)
196  AND (
197  ((frequency = '.MatrixDAL::quote('MFN').')
198  AND ((start_date_mday + (end_date_ds - start_date_ds)) - '.$prev_month_length.' >= '.$now['mday'].'))
199  OR ((frequency = '.MatrixDAL::quote('MFD').')
200  AND (((MOD(7 + '.$prev_month_start_wday.' - start_date_wday, 7) + 1) + ((start_date_wdom - 1) * 7) + (end_date_ds - start_date_ds)) - '.$prev_month_length.' >= '.$now['mday'].'))
201  OR ((frequency = '.MatrixDAL::quote('MRD').')
202  AND ((('.$prev_month_length.' - MOD(7 + '.$prev_month_end_wday.' - start_date_wday, 7)) + (end_date_ds - start_date_ds)) - '.$prev_month_length.' >= '.$now['mday'].'))
203  )
204  )
205  )';
206 
207  break;
208 
209  case 'week' :
210  // if we go into next week, we must put the next week's stuff into it
211  // if we go into next month, we must put the 1st week into it
212  $days_in_month = days_in_month($month,$year);
213 
214  $req_next_week = ($day % 7 != 1);
215  $req_rev_next_week = (($days_in_month - $day + 1) % 7 != 1);
216  $req_next_month = ($day + 6 > $days_in_month);
217 
218  $last_day = $now['ds'] + 6;
219 
220  $sql_freqs[] = 'frequency = '.MatrixDAL::quote('DWD');
221  $sql_freqs[] = 'frequency = '.MatrixDAL::quote('DWE');
222 
223  // note: the slightly redundant "*1.0" is so Postgres interprets it as a
224  // double instead of an int, blowing away our attempts to use floor()
225  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('DED').' AND ((FLOOR(('.MatrixDAL::quote($now['ds']-1).' - start_date_ds) / (period*1.0)) < FLOOR(('.MatrixDAL::quote($now['ds']+6).' - start_date_ds) / (period*1.0))) or mod(('.MatrixDAL::quote($now['ds']).' - start_date_ds), period) BETWEEN 0 AND COALESCE(end_date_ds - start_date_ds,0)))';
226 
227  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('WEW').' AND ((FLOOR(('.MatrixDAL::quote($now['ds']-1).' - start_date_ds)/(period*7.0)) < FLOOR(('.MatrixDAL::quote($now['ds']+6).' - start_date_ds)/(period*7.0))) OR MOD(('.MatrixDAL::quote($now['ds']).' - start_date_ds), period) BETWEEN 0 AND COALESCE(end_date_ds - start_date_ds,0)))';
228 
229  $sql_freqs_m = Array();
230 
231  // every X months on xth of the month
232  $sql_freqs_m[] = '(frequency = '.MatrixDAL::quote('MFN').' AND start_date_mday BETWEEN '.MatrixDAL::quote(intval($day)).' AND '.MatrixDAL::quote(min($day+6, $days_in_month)).')';
233 
234  // every X months on xth weekday of the month
235  $sql_freqs_m[] = '(frequency = '.MatrixDAL::quote('MFW').' AND start_date_wdom IN ( '.MatrixDAL::quote($now['wdom']).($req_next_week ? ','.MatrixDAL::quote($now['wdom']+1) : '').'))';
236 
237  // every X months on xth last day of the month
238  $sql_freqs_m[] = '(frequency = '.MatrixDAL::quote('MRN').' AND start_date_rmday BETWEEN '.MatrixDAL::quote(max($days_in_month - $day - 5, 1)).' AND '.MatrixDAL::quote(intval($days_in_month - $day + 1)).')';
239 
240  // every X months on xth last weekday of the month
241  $sql_freqs_m[] = '(frequency = '.MatrixDAL::quote('MRW').' AND start_date_rwdom IN ( '.MatrixDAL::quote($now['rwdom']).($req_rev_next_week ? ','.MatrixDAL::quote($now['rwdom']-1) : '').'))';
242 
243  $sql_freqs[] = '(('.implode("\n\t".' OR ', $sql_freqs_m).') AND (MOD('.MatrixDAL::quote($now['ms']).' - start_date_ms, period) = 0))';
244 
245  // rolling over to a new month? Oh crap :o
246  if ($req_next_month) {
247  if ($month == 12) {
248  $new_month = 1;
249  $new_year = $year + 1;
250  } else {
251  $new_month = $month + 1;
252  $new_year = $year;
253  }
254 
255  $req_rev_next_week = (($day + 28) > days_in_month($new_month, $new_year));
256  $wdom_list = weekday_dates_in_month($now['wday'], $new_month, $new_year);
257  $days_in_new_month = days_in_month($new_month,$new_year);
258 
259  // wipe the table clean
260  $sql_freqs_m = Array();
261 
262  $sql_freqs_m[] = '(frequency = '.MatrixDAL::quote('MFN').' AND start_date_mday BETWEEN '.MatrixDAL::quote(1).' AND '.MatrixDAL::quote($day+6-$days_in_month).')';
263 
264  // every X months on xth weekday of the month - it's always going to
265  // be the first week of a new month
266  $sql_freqs_m[] = '(frequency = '.MatrixDAL::quote('MFW').' AND start_date_wdom = 1)';
267 
268  // every X months on xth last day of the month
269  $sql_freqs_m[] = '(frequency = '.MatrixDAL::quote('MRN').' AND start_date_rmday BETWEEN '.MatrixDAL::quote($days_in_month * 2 - $day - 5).' AND '.MatrixDAL::quote(intval($days_in_month)).')';
270 
271  // every X months on xth last weekday of the month
272  $sql_freqs_m[] = '(frequency = '.MatrixDAL::quote('MRW').' AND start_date_rwdom IN ( '.MatrixDAL::quote(count($wdom_list)).($req_rev_next_week ? ','.MatrixDAL::quote(count($wdom_list)-1) : '').'))';
273 
274  $sql_freqs[] = '(('.implode("\n\t".' OR ', $sql_freqs_m).') AND (MOD('.MatrixDAL::quote($now['ms']+1).' - start_date_ms, period) = 0))';
275  }
276 
277  $sql_freqs[] = '(frequency IN ('.MatrixDAL::quote('MFN').', '.MatrixDAL::quote('MRN').') AND (end_date_ds - start_date_ds >= '.$day.'))';
278 
279  $sql_freqs[] = '(frequency IN ('.MatrixDAL::quote('MFW').', '.MatrixDAL::quote('MRW').') AND (end_date_ds - start_date_ds >= 1 + ((start_date_rwdom-1) * 7)))';
280 
281  break;
282 
283  case 'month' :
284  $last_day = $now['ds'] + days_in_month($month,$year) - 1;
285 
286  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('DWD').')';
287  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('DWE').')';
288 
289  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('DED').' AND (FLOOR(('.MatrixDAL::quote($now['ds']-1).' - start_date_ds)/period) < FLOOR(('.MatrixDAL::quote($last_day).' - start_date_ds)/period)))';
290 
291  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('WEW').' AND period = 1)';
292 
293  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('WEW').' AND (floor(('.MatrixDAL::quote($now['ds']-1).' - start_date_ds)/(period*7)) < FLOOR('.MatrixDAL::quote($last_day).' - start_date_ds)/(period*7)))';
294 
295  // all monthly views can be lumped together on this one
296  $sql_freqs[] = '(frequency LIKE '.MatrixDAL::quote('M%').' AND (MOD(('.MatrixDAL::quote($now['ms']).' - start_date_ms), period) = 0))';
297 
298  $iso = $year.'-'.sprintf('%02d', $month).'-01';
299 
300  break;
301 
302  case 'year' :
303  $last_day = $now['ds']+364+is_leap_year($year);
304 
305  $sql_freqs[] = 'frequency = '.MatrixDAL::quote('DWD');
306  $sql_freqs[] = 'frequency = '.MatrixDAL::quote('DWE');
307 
308  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('DED').' AND (FLOOR(('.MatrixDAL::quote($now['ds']-1).' - start_date_ds)/period) < FLOOR(('.MatrixDAL::quote($last_day).' - start_date_ds)/period)))';
309 
310  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('WEW').' AND period = 1)';
311 
312  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('WEW').' AND (FLOOR(('.MatrixDAL::quote($now['ds']-1).' - start_date_ds)/(period*7)) < FLOOR(('.MatrixDAL::quote($last_day).' - start_date_ds)/(period*7))))';
313 
314  // all monthly views can be lumped together on this one
315  // but we need to do something like the 'every day' type thing to work out
316  // whether an occurrence will happen this year
317  $sql_freqs[] = '(frequency LIKE '.MatrixDAL::quote('M%').' AND (FLOOR(('.($year * 12).' - start_date_ms) / period) < FLOOR(('.(($year + 1) * 12).' - start_date_ms) / period)))';
318  break;
319 
320  case 'period' :
321  $last_date = date('Y-m-d', strtotime("$iso 00:00:00 +$length days") - strtotime('1970-01-01 00:00:00 Z'));
322  $last_date_components = Calendar_Common::getDateComponents($last_date);
323  $last_day = $last_date_components['ds'];
324 
325  // GENERIC MATCES
326  $sql_freqs[] = '(
327  (start_date_ds BETWEEN '.$now['ds'].' AND '.$last_date_components['ds'].')
328  OR
329  (end_date_ds BETWEEN '.$now['ds'].' AND '.$last_date_components['ds'].')
330  )';
331 
332  // DAILY-RECURRING
333  $sql_freqs[] = '(
334  (frequency = '.MatrixDAL::quote('DED').')
335  AND
336  (
337  (period <= '.$length.')
338  OR
339  (FLOOR(('.$now['ds'].' - start_date_ds) / period) < FLOOR(('.$last_date_components['ds'].' - start_date_ds) / period))
340  OR
341  (floor(('.$now['ds'].' - end_date_ds) / period) < FLOOR(('.$last_date_components['ds'].' - end_date_ds) / period))
342  )
343  )';
344  if (($length > 2) || !in_array($now['wday'], Array(0, 6)) || !in_array($last_date_components['wday'], Array(0, 6))) {
345  // the period includes a weekday
346  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('DWD').')';
347  }
348  if (($length > 5) || in_array($now['wday'], Array(0, 6)) || in_array($last_date_components['wday'], Array(0, 6)) || ($last_date_components['wday'] < $now['wday'])) {
349  // the period includes a weekend day
350  $sql_freqs[] = '(frequency = '.MatrixDAL::quote('DWE').')';
351  }
352 
353  // WEEKLY-RECURRING
354  $sql_freqs[] = '(
355  (frequency = '.MatrixDAL::quote('WEW').')
356  AND
357  (
358  ((period * 7) <= '.$length.')
359  OR
360  (FLOOR(('.($now['ds']-1).' - start_date_ds) / (period * 7)) < FLOOR(('.$last_date_components['ds'].' - start_date_ds) / (period * 7)))
361  OR
362  (FLOOR(('.($now['ds']-1).' - end_date_ds) / (period * 7)) < FLOOR(('.$last_date_components['ds'].' - end_date_ds) / (period * 7)))
363  )
364  )';
365 
366  // MONTHLY-RECURRING
367  $monthly_conditions = Array();
368  if ($last_date_components['ms'] == $now['ms']) {
369  // we are within one month
370 
371  // get MFN and MRN events
372  $monthly_conditions[] = '((frequency = '.MatrixDAL::quote('MFN').') AND (((MOD('.$now['ms'].' - start_date_ms, period) = 0) AND (start_date_mday BETWEEN '.$now['mday'].' AND '.$last_date_components['mday'].')) OR ((MOD('.$now['ms'].' - end_date_ms, period) = 0) AND (end_date_mday BETWEEN '.$now['mday'].' AND '.$last_date_components['mday'].'))))';
373  $monthly_conditions[] = '((frequency = '.MatrixDAL::quote('MRN').') AND ((start_date_rwdom BETWEEN '.$last_date_components['rwdom'].' AND '.$now['rwdom'].') OR (end_date_rwdom BETWEEN '.$last_date_components['rwdom'].' AND '.$now['rwdom'].')))';
374 
375  // get MFW events
376  $mfw_conditions = Array();
377  if ($last_date_components['wdom'] == $now['wdom']) {
378  // we are within one month-week
379 
380  // double check these
381  $mfw_conditions[] = '((MOD('.$now['ms'].' - start_date_ms, period) = 0)
382  AND (start_date_wdom = '.$now['wdom'].')
383  AND (start_date_mday - (7 * (start_date_wdom - 1)) BETWEEN '.($now['mday'] - (7 * ($now['wdom'] - 1))).' AND '.($last_date_components['mday'] - (7 * ($last_date_components['wdom'] - 1))).'))';
384  $mfw_conditions[] = '((MOD('.$now['ms'].' - end_date_ms, period) = 0)
385  AND (end_date_wdom = '.$now['wdom'].')
386  AND (end_date_mday - (7 * (end_date_wdom - 1)) BETWEEN '.($now['mday'] - (7 * ($now['wdom'] - 1))).' AND '.($last_date_components['mday'] - (7 * ($last_date_components['wdom'] - 1))).'))';
387 
388  } else {
389  // we start and end in different month-weeks
390 
391  // want to know if an event starts or ends late enough in the start week
392  $mfw_conditions[] = '(((start_date_wdom = '.$now['wdom'].') AND (start_date_mday - ((start_date_wdom - 1) * 7) >= '.($now['mday'] - (($now['wdom'] - 1) * 7)).')) OR (((end_date_wdom = '.$now['wdom'].') AND (end_date_mday - ((end_date_wdom - 1) * 7) >= '.($now['mday'] - (($now['wdom'] - 1) * 7)).'))))';
393 
394  // or early enough in the end week
395  $mfw_conditions[] = '(((start_date_wdom = '.$last_date_components['wdom'].') AND (start_date_mday - ((start_date_wdom - 1) * 7) <= '.($last_date_components['mday'] - (($last_date_components['wdom'] - 1) * 7)).')) OR (((end_date_wdom = '.$last_date_components['wdom'].') AND (end_date_mday - ((end_date_wdom - 1) * 7) <= '.($last_date_components['mday'] - (($last_date_components['wdom'] - 1) * 7)).'))))';
396 
397  // or covers the whole thing
398  $mfw_conditions[] = '((start_date_wdom <= '.$now['wdom'].') AND (end_date_wdom >= '.$last_date_components['wdom'].') AND (start_date_mday - ((start_date_wdom - 1) * 7) < '.($now['mday'] - (($now['wdom'] - 1) * 7)).') AND (end_date_mday - ((end_date_wdom - 1) * 7) > '.($last_date_components['mday'] - (($last_date_components['wdom'] - 1) * 7)).'))';
399 
400  if ($last_date_components['wdom'] - $now['wdom'] != 1) {
401  // we have intervening weeks
402  // we want to know if any event started or ended in the intervening weeks
403  $mfw_conditions[] = '((frequency = '.MatrixDAL::quote('MFW').') AND ((start_date_wdom BETWEEN '.($now['wdom'] + 1).' AND '.($last_date_components['wdom'] - 1).') OR (end_date_wdom BETWEEN '.($now['wdom'] + 1).' AND '.($last_date_components['wdom'] - 1).')))';
404  }
405  }
406  $monthly_conditions[] = '((frequency = '.MatrixDAL::quote('MFW').') AND ('.implode(' OR ', $mfw_conditions)."\n\n ))";
407 
408  // get MRW events
409  $mrw_conditions = Array();
410  if ($last_date_components['rwdom'] == $now['rwdom']) {
411  // we are within one reverse-month-week
412 
413  $mrw_conditions[] = '((MOD('.$now['ms'].' - start_date_ms, period) = 0)
414  AND (start_date_rwdom = '.$now['rwdom'].')
415  AND (start_date_rmday - (7 * (start_date_rwdom - 1)) BETWEEN '.($now['rmday'] - (7 * ($now['rwdom'] - 1))).' AND '.($last_date_components['rmday'] - (7 * ($last_date_components['rwdom'] - 1))).'))';
416  $mrw_conditions[] = '((MOD('.$now['ms'].' - end_date_ms, period) = 0)
417  AND (end_date_rwdom = '.$now['rwdom'].')
418  AND (end_date_rmday - (7 * (end_date_rwdom - 1)) BETWEEN '.($now['rmday'] - (7 * ($now['rwdom'] - 1))).' AND '.($last_date_components['rmday'] - (7 * ($last_date_components['rwdom'] - 1))).'))';
419  } else {
420  // we start and end in different reverse-month-weeks
421 
422  // want to know if an event starts or ends late enough in the start week
423  $mrw_conditions[] = '(((start_date_rwdom = '.$now['rwdom'].') AND (start_date_rmday - ((start_date_rwdom - 1) * 7) >= '.($now['rmday'] - (($now['rwdom'] - 1) * 7)).')) OR (((end_date_rwdom = '.$now['rwdom'].') AND (end_date_rmday - ((end_date_rwdom - 1) * 7) <= '.($now['rmday'] - (($now['rwdom'] - 1) * 7)).'))))';
424 
425  // or early enough in the end week
426  $mrw_conditions[] = '(((start_date_rwdom = '.$last_date_components['rwdom'].') AND (start_date_rmday - ((start_date_rwdom - 1) * 7) <= '.($last_date_components['rmday'] - (($last_date_components['rwdom'] - 1) * 7)).')) OR (((end_date_rwdom = '.$last_date_components['rwdom'].') AND (end_date_rmday - ((end_date_rwdom - 1) * 7) >= '.($last_date_components['rmday'] - (($last_date_components['rwdom'] - 1) * 7)).'))))';
427 
428  // or covers the whole thing
429  $mrw_conditions[] = '((start_date_rwdom >= '.$now['rwdom'].') AND (end_date_rwdom <= '.$last_date_components['rwdom'].') AND (start_date_rmday - ((start_date_rwdom - 1) * 7) > '.($now['rmday'] - (($now['rwdom'] - 1) * 7)).') AND (end_date_rmday - ((end_date_rwdom - 1) * 7) < '.($last_date_components['rmday'] - (($last_date_components['rwdom'] - 1) * 7)).'))';
430 
431  if ($last_date_components['rwdom'] - $now['rwdom'] != 1) {
432  // we have intervening weeks
433  // we want to know if any event started or ended in the intervening weeks
434  $mrw_conditions[] = '((start_date_rwdom BETWEEN '.($now['rwdom'] - 1).' AND '.($last_date_components['rwdom'] + 1).') OR (end_date_rwdom BETWEEN '.($now['rwdom'] - 1).' AND '.($last_date_components['rwdom'] + 1).'))';
435  }
436  }
437  $monthly_conditions[] = '((frequency = '.MatrixDAL::quote('MRW').') AND ('.implode(' OR ', $mrw_conditions).'))';
438 
439  // get month events that cover the whole of our month
440  $sql_freqs[] = '(
441  /* begin month options */
442  (frequency LIKE '.MatrixDAL::quote('M%').')
443  AND (
444  (
445  (end_date_ms IS NOT NULL)
446  AND (end_date_ms - start_date_ms >= 3)
447  AND MOD('.$now['ms'].' - start_date_ms, period)
448  BETWEEN 1 AND (end_date_ms - start_date_ms - 1)
449  ) OR (
450  (
451  MOD('.$now['ms'].' - start_date_ms, period) = 0
452  OR MOD('.$now['ms'].' - end_date_ms, period) = 0
453  ) AND (
454  '.implode("\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t OR ", $monthly_conditions).'
455  )
456  )
457  )
458  /* end month options */
459  )';
460  } else {
461  // start and end are in different months
462 
463  // we want to see if the start or end is late enough in the first month
464  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MFN').') AND (((MOD('.$now['ms'].' - start_date_ms, period) = 0) AND (start_date_mday >= '.$now['mday'].')) OR ((MOD('.$now['ms'].' - end_date_ms, period) = 0) AND (end_date_mday >= '.$now['mday'].'))))';
465 
466  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MRN').') AND (((MOD('.$now['ms'].' - start_date_ms, period) = 0) AND (start_date_rmday <= '.$now['rmday'].')) OR ((MOD('.$now['ms'].' - end_date_ms, period) = 0) AND (end_date_rmday <= '.$now['rmday'].'))))';
467 
468  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MFW').') AND (MOD('.$now['ms'].' - start_date_ms, period) = 0) AND ((start_date_wdom > '.$now['wdom'].') OR (((start_date_wdom = '.$now['wdom'].') AND (start_date_mday - ((start_date_wdom - 1) * 7) >= '.($now['mday'] - (($now['wdom'] - 1) * 7)).')))))';
469 
470  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MFW').') AND (MOD('.$now['ms'].' - end_date_ms, period) = 0) AND ((end_date_wdom > '.$now['wdom'].') OR (((end_date_wdom = '.$now['wdom'].') AND (end_date_mday - ((end_date_wdom - 1) * 7) >= '.($now['mday'] - (($now['wdom'] - 1) * 7)).')))))';
471 
472  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MRW').') AND (MOD('.$now['ms'].' - start_date_ms, period) = 0) AND ((start_date_rwdom < '.$now['rwdom'].') OR (((start_date_rwdom = '.$now['rwdom'].') AND (start_date_rmday - ((start_date_rwdom - 1) * 7) <= '.($now['rmday'] - (($now['rwdom'] - 1) * 7)).')))))';
473 
474  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MRW').') AND (MOD('.$now['ms'].' - end_date_ms, period) = 0) AND ((end_date_rwdom > '.$now['rwdom'].') OR (((end_date_rwdom = '.$now['rwdom'].') AND (end_date_rmday - ((end_date_rwdom - 1) * 7) <= '.($now['rmday'] - (($now['rwdom'] - 1) * 7)).')))))';
475 
476  // or early enough in the last month
477  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MFN').') AND (((MOD('.$last_date_components['ms'].' - start_date_ms, period) = 0) AND (start_date_mday <= '.$last_date_components['mday'].')) OR ((MOD('.$last_date_components['ms'].' - end_date_ms, period) = 0) AND (end_date_mday <= '.$last_date_components['mday'].'))))';
478 
479  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MRN').') AND (((MOD('.$last_date_components['ms'].' - start_date_ms, period) = 0) AND (start_date_rmday >= '.$last_date_components['rmday'].')) OR ((MOD('.$last_date_components['ms'].' - end_date_ms, period) = 0) AND (end_date_rmday >= '.$last_date_components['rmday'].'))))';
480 
481  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MFW').') AND (MOD('.$now['ms'].' - start_date_ms, period) = 0) AND ((start_date_wdom < '.$now['wdom'].') OR (((start_date_wdom = '.$now['wdom'].') AND (start_date_mday - ((start_date_wdom - 1) * 7) <= '.($now['mday'] - (($now['wdom'] - 1) * 7)).')))))';
482 
483  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MFW').') AND (MOD('.$now['ms'].' - end_date_ms, period) = 0) AND ((end_date_wdom < '.$now['wdom'].') OR (((end_date_wdom = '.$now['wdom'].') AND (end_date_mday - ((end_date_wdom - 1) * 7) <= '.($now['mday'] - (($now['wdom'] - 1) * 7)).')))))';
484 
485  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MRW').') AND (MOD('.$now['ms'].' - start_date_ms, period) = 0) AND ((start_date_rwdom > '.$now['rwdom'].') OR (((start_date_rwdom = '.$now['rwdom'].') AND (start_date_rmday - ((start_date_rwdom - 1) * 7) >= '.($now['rmday'] - (($now['rwdom'] - 1) * 7)).')))))';
486 
487  $sql_freqs[] = '((frequency = '.MatrixDAL::quote('MRW').') AND (MOD('.$now['ms'].' - end_date_ms, period) = 0) AND ((end_date_rwdom > '.$now['rwdom'].') OR (((end_date_rwdom = '.$now['rwdom'].') AND (end_date_rmday - ((end_date_rwdom - 1) * 7) <= '.($now['rmday'] - (($now['rwdom'] - 1) * 7)).')))))';
488 
489  if ($last_date_components['ms'] - $now['ms'] > 1) {
490  // we have intervening months, so we want to see if the event starts or ends in one of them
491  $sql_freqs[] = '((frequency LIKE '.MatrixDAL::quote('M%').') AND ((MOD('.$last_date_components['ms'].' - start_date_ms, period) BETWEEN 1 AND '.($last_date_components['ms'] - $now['ms'] - 1).') OR (MOD('.$last_date_components['ms'].' - end_date_ms, period) BETWEEN 1 AND '.($last_date_components['ms'] - $now['ms'] - 1).')))';
492  }
493  }//end else
494 
495  break;
496 
497  }//end switch on $view
498  $sql .= "(/* begin sql freqs */\n\n".implode("\n\n\nOR\n\n\n ", $sql_freqs)."\n/* end sql freqs */\n)\n\n";
499 
500  // stop date
501  $sql .= ' AND ('.$last_day.' >= start_date_ds)';
502  $sql .= ' AND (stop_date = '.MatrixDAL::quote('----------').' OR stop_date >= '.MatrixDAL::quote($iso).')';
503 
504  $sql .= ' AND '.Calendar_Common::_getTreeClause($root_ids);
505 
506  return $sql;
507 
508  }//end getRecurringEventQueryBase()
509 
510 
521  function condenseResultTreeids($raw)
522  {
523  $res = Array();
524  foreach ($raw as $r) {
525  if (!isset($res[$r['assetid']])) {
526  $r['treeid'] = Array($r['treeid']);
527  $res[$r['assetid']] = $r;
528  } else {
529  $res[$r['assetid']]['treeid'][] = $r['treeid'];
530  }
531  }
532  return $res;
533 
534  }//end condenseResultTreeids()
535 
536 
553  function &expandEventList(&$events, $first_day, $last_day, $day_start_time='00:00', $day_end_time='23:59')
554  {
555  $res = Array();
556  foreach (array_keys($events) as $key) {
557  $event =& $events[$key];
558  $recurring_descandants = $GLOBALS['SQ_SYSTEM']->am->getTypeDescendants('calendar_event_recurring');
559  if (($event['type_code'] == 'calendar_event_recurring') || in_array($event['type_code'], $recurring_descandants)) {
560  Calendar_Common::_expandRecurringEvent($res, $event, $key, $first_day, $last_day, $day_start_time, $day_end_time);
561  } else {
562  Calendar_Common::_expandSingleEvent($res, $event, $key, $first_day, $last_day, $day_start_time, $day_end_time);
563  }
564  }
565  return $res;
566 
567  }//end expandEventList()
568 
569 
581  function processExceptions(&$res)
582  {
583  $db = MatrixDAL::getDb();
584  $exception_ids = Array();
585  foreach ($res as $id => $details) {
586  if (in_array($details['type_code'], Array('calendar_event_cancellation', 'calendar_event_modification'))) {
587  $id_bits = explode(':', $id);
588  $real_id = $id_bits[0];
589  $exception_ids[] = MatrixDAL::quote($real_id);
590  }
591  }
592  if (empty($exception_ids)) return FALSE;
593 
594  $exception_links = Array();
595  try {
596  $query = MatrixDAL::preparePdoQuery('SELECT majorid, minorid FROM '.SQ_TABLE_RUNNING_PREFIX.'ast_lnk WHERE minorid IN ('.implode(', ', $exception_ids).')');
597  $exception_links = MatrixDAL::executePdoGrouped($query);
598  } catch (Exception $e) {
599  throw new Exception($e->getMessage());
600  }
601 
602  // if there are no event modification or event cancalletions found
603  // it is safe to return back from here as we dont need to remove
604  // any of the events
605  if (empty($exception_links)) return FALSE;
606 
607  // so guess we have found some event modification or cancellation
608  // lets deal with them Matrix style B-)
609  $events_n_exceptions = Array();
610 
611  foreach ($exception_links as $event => $exceptions) {
612  foreach ($exceptions as $index => $exception) {
613  $exception_event = $GLOBALS['SQ_SYSTEM']->am->getAsset($exception[0]);
614  $events_n_exceptions[$event][] = $exception_event;
615  }
616  }
617 
618  foreach ($events_n_exceptions as $event_id => $exceptions) {
619  foreach ($exceptions as $i => $exception) {
620  foreach ($res as $key => $details) {
621  $id = explode(':', $key);
622  $id = $id[0];
623  if ($event_id == $id) {
624  // get the start date of the calendar_event_modification
625  // or calendar_event_cancellation (exception)
626  // and compare it with the instance we have
627  // because we need to just cancel/modify that occurance
628  // and not all of the occurance of that particular event
629  $exception_date = $exception->attr('start_date');
630  if (strpos($exception_date, date('Y-m-d', $details['start_date_ts'])) !== FALSE) {
631  unset($res[$key]);
632  }
633  }
634  // also if we are ourselves the cancellation event
635  // unset ouselves
636  if ($details['type_code'] == 'calendar_event_cancellation') {
637  unset($res[$key]);
638  }
639  }
640  }
641  }
642 
643  }//end processExceptions()
644 
645 
655  function compareStartDates($a, $b)
656  {
657  return ($a['start_date_ts'] < $b['start_date_ts']) ? -1 : 1;
658 
659  }//end compareStartDates()
660 
661 
671  function compareEventLengths($a, $b)
672  {
673  return ($b['end_date_ts'] - $b['start_date_ts']) - ($a['end_date_ts'] - $a['start_date_ts']);
674 
675  }//end compareEventLengths()
676 
677 
687  function getDateComponents($iso, $prefix='')
688  {
689  // we represent end-of-day as '24:00:00' as per ISO 8601, but strtotime()
690  // doesn't recognise it. Fudge a little by flagging it, getting *start* of
691  // day, then adding a day to the timestamp and setting hours to 24
692  if ($iso_24h = (iso8601_time_component($iso) == '24:00:00')) {
693  $iso = substr($iso,0,10).' 00:00:00'; // make it legit, fix it later
694  }
695 
696  // we can build most of our info from the getdate() function
697  if (($ts = strtotime($iso)) != FALSE) {
698  $this_date = getdate($ts);
699  $this_date['yday']++; // to make it 1-based
700 
701  // unset word based dates
702  unset($this_date['weekday']);
703  unset($this_date['month']);
704 
705  // move timestamp field to a string-based key instead of [0]
706  $this_date['ts'] = strtotime($iso.' Z') - strtotime('1970-01-01 00:00:00 Z');
707  unset($this_date[0]);
708 
709  // add 'day-count stamp'
710  $this_date['ds'] = Calendar_Common::_getDayStamp($iso);
711 
712  // 24:00:00 ISO time
713  if ($iso_24h) {
714  $this_date['ts'] += 86400;
715  $this_date['hours'] = 24;
716  }
717 
718  } else {
719  // we have to do this manually..... great
720  $this_date = Array();
721 
722  list($this_date['year'], $this_date['mon'], $this_date['mday'], $this_date['hours'], $this_date['minutes'], $this_date['seconds']) = sscanf($iso, '%4s-%2s-%2s %2s:%2s:%2s');
723 
724  // any dashed out sections should be nulled out instead
725  foreach (array_keys($this_date) as $iso_part) {
726  if ($this_date[$iso_part] == str_repeat('-', ($iso_part == 'year' ? 4 : 2))) {
727  $this_date[$iso_part] = NULL;
728  }
729  }
730 
731  $date_only_ts = strtotime(substr($iso,0,10));
732 
733  // forward day-of-year and weekday can only work with valid date
734  if (is_null($this_date['mday']) || is_null($this_date['mon']) || is_null($this_date['year']) || ($date_only_ts == 1)) {
735  $this_date['wday'] = NULL;
736  $this_date['yday'] = NULL;
737  $this_date['ts'] = NULL;
738  $this_date['ds'] = NULL;
739  } else {
740  if (is_null($this_date['hours']) && (!is_null($this_date['minutes']) || !is_null($this_date['seconds']))) {
741  // hours null in the middle of the time - no valid time
742  $this_date['ts'] = NULL;
743  } else if (is_null($this_date['minutes']) && !is_null($this_date['seconds'])) {
744  // minutes null in the middle of the time - no valid time
745  $this_date['ts'] = NULL;
746  } else {
747  // make a best guess on timestamp, setting all blanks to 0
748  $this_date['ts'] = strtotime(substr($iso,0,10).' '.str_replace('-','0',substr($iso,11)).' Z') - strtotime('1970-01-01 00:00:00 Z');
749  }
750 
751  // we can do these in any case
752  $this_date['ds'] = Calendar_Common::_getDayStamp($iso);
753  $this_date['wday'] = date('w', $date_only_ts);
754  $this_date['yday'] = date('z', $date_only_ts) + 1;
755  }
756 
757  }//end else
758 
759  // add 'month-stamp' column which can be used to easily check
760  // 'x monthly' stuff which can't be done easily with T/S alone
761  if (is_null($this_date['mon']) || is_null($this_date['year'])) {
762  $this_date['ms'] = NULL;
763  } else {
764  $this_date['ms'] = Calendar_Common::_getMonthStamp($iso);
765  }
766 
767  if (is_null($this_date['mday']) || is_null($this_date['mon']) || is_null($this_date['year'])) {
768  $this_date['ryday'] = NULL;
769  $this_date['rmday'] = NULL;
770  $this_date['wdom'] = NULL;
771  $this_date['rwdom'] = NULL;
772  } else {
773  // reverse day-of-year and reverse day-of-month [1-based]
774  $this_date['ryday'] = 365 + (is_leap_year($this_date['year']) ? 1 : 0) - $this_date['yday'] + 1;
775  $this_date['rmday'] = days_in_month($this_date['mon'], $this_date['year']) - $this_date['mday'] + 1;
776 
777  // weekday of month, reverse thereof [both 1-based]
778  $wdom = weekday_dates_in_month($this_date['wday'], $this_date['mon'], $this_date['year']);
779 
780  $this_date['wdom'] = array_search($this_date['mday'], $wdom) + 1;
781  $this_date['rwdom'] = count($wdom) - $this_date['wdom'] + 1;
782  }
783 
784  // now dump them into the array we were passed in the first place
785  $res = Array();
786  foreach (array_keys($this_date) as $iso_part) {
787  $res[$prefix.$iso_part] = is_null($this_date[$iso_part]) ? NULL : intval($this_date[$iso_part]);
788  }
789  return $res;
790 
791  }//end getDateComponents()
792 
793 
800  function _getTableList()
801  {
802  $base = ($GLOBALS['SQ_SYSTEM']->userSystemAdmin() || $GLOBALS['SQ_SYSTEM']->userRoot()) ? SQ_TABLE_RUNNING_PREFIX.'ast a' : '('.SQ_TABLE_RUNNING_PREFIX.'ast a JOIN '.SQ_TABLE_RUNNING_PREFIX.'vw_ast_perm p ON a.assetid = p.assetid)';
803  return '('.$base.' JOIN ('.SQ_TABLE_RUNNING_PREFIX.'ast_lnk l JOIN '.SQ_TABLE_RUNNING_PREFIX.'ast_lnk_tree t ON l.linkid = t.linkid) ON l.minorid = a.assetid) JOIN '.SQ_TABLE_RUNNING_PREFIX.'cal_date_val cd ON a.assetid = cd.assetid';
804 
805  }//end _getTableList()
806 
807 
821  function _ts2Sql($y, $m, $d, $h='00', $i='00', $s='00')
822  {
823  switch (MatrixDAL::getDbType()) {
824  case 'pgsql':
825  // can only subtract dates because subtracting timestamps results
826  // in an INTERVAL data type, which can't be converted. Only DATE
827  // subtraction returns an integer.
828  // Add the hours, minutes and seconds manually afterwards
829  $sql = "(86400 * (DATE (($y) || '-' || ($m) || '-' || ($d)) - DATE '1970-01-01') + ($h) * 3600 + ($i) * 60 + ($s))";
830  break;
831 
832  case 'oci':
833  // Subtracting datetimes in Oracle gives a fractional number of
834  // days - I haven't had any problems yet but if rounding errors
835  // occur then might have to go with similar to above
836  $sql = '(86400 * ('.db_extras_todate(MatrixDAL::getDbType(), "(($y) || '-' || ($m) || '-' || ($d) || ' ' || ($h) || ':' || ($i) || ':' || ($s))", FALSE).' - '.db_extras_todate(MatrixDAL::getDbType(), '1970-01-01 00:00:00').'))';
837  break;
838  }
839 
840  return $sql;
841 
842  }//end _ts2Sql()
843 
844 
853  function _getTreeClause($root_ids)
854  {
855  $treeids = $GLOBALS['SQ_SYSTEM']->am->getAssetTreeids($root_ids);
856  $db = MatrixDAL::getDb();
857  $tree_options = Array();
858  foreach ($treeids as $assetid => $treeids) {
859  foreach ($treeids as $treeid) {
860  $tree_options[] .= '(t.treeid LIKE '.MatrixDAL::quote($treeid[0].'%').')';
861  }
862  }
863  return '('.implode(' OR ', $tree_options).')';
864 
865  }//end _getTreeClause()
866 
867 
883  function _expandSingleEvent(&$result_list, &$event, $assetid, $first_day, $last_day, $day_start_time, $day_end_time)
884  {
885  list($day_start_hours, $day_start_minutes) = sscanf($day_start_time, '%02d:%02d');
886  list($day_end_hours, $day_end_minutes) = sscanf($day_end_time, '%02d:%02d');
887  $day_start_dts = ($day_start_hours * 60) + $day_start_minutes;
888  $day_end_dts = ($day_end_hours * 60) + $day_end_minutes;
889 
890  $event_start_date = sprintf('%04d-%02d-%02d %02d:%02d:00', $event['start_date_year'], $event['start_date_mon'], $event['start_date_mday'], $event['start_date_hours'], $event['start_date_minutes']);
891  $event_start_dts = ($event['start_date_hours'] * 60) + $event['start_date_minutes'];
892 
893  $i = 0;
894 
895  if (!is_null($event['end_date_ds'])) {
896  // end date is specified
897  $event_end_date = sprintf('%04d-%02d-%02d %02d:%02d:00', $event['end_date_year'], $event['end_date_mon'], $event['end_date_mday'], $event['end_date_hours'], $event['end_date_minutes']);
898  $event_end_dts = (($event['end_date_hours'] * 60) + $event['end_date_minutes']);
899 
900  if ($event['start_date_ds'] != $event['end_date_ds']) {
901  // covers multiple days
902  $event['expanded'] = 1;
903 
904  if (($first_day <= substr($event_start_date, 0, 10)) && ($event_start_dts < $day_end_dts)) {
905  // insert first day
906  $result_list[$assetid.':'.$i] = Array();
907  for (reset($event); NULL !== ($k = key($event)); next($event)) {
908  $result_list[$assetid.':'.$i][$k] = $event[$k];
909  }
910 
911  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
912  Calendar_Common::getDateComponents($event_start_date, 'start_date_'),
913  Calendar_Common::getDateComponents(substr($event_start_date, 0, 10).' 24:00:00', 'end_date_'));
914 
915  $i++;
916  }
917 
918  // insert intermediate days
919  $inter_date = date('Y-m-d', strtotime(max(add_days_to_iso($event_start_date, 1), $first_day)));
920  $last_inter_date = min($last_day, add_days_to_iso($event_end_date, -1));
921  while ($inter_date <= $last_inter_date) {
922  $result_list[$assetid.':'.$i] = Array();
923  for (reset($event); NULL !== ($k = key($event)); next($event)) {
924  $result_list[$assetid.':'.$i][$k] = $event[$k];
925  }
926 
927  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
928  Calendar_Common::getDateComponents($inter_date.' 00:00:00', 'start_date_'),
929  Calendar_Common::getDateComponents($inter_date.' 24:00:00', 'end_date_'));
930 
931  $inter_date = add_days_to_iso($inter_date, 1);
932  $i++;
933  }
934 
935  if ((substr($event_end_date, 0, 10) <= $last_day) && ($event_end_dts > $day_start_dts)) {
936  // insert the last day
937  $result_list[$assetid.':'.$i] = Array();
938  for (reset($event); NULL !== ($k = key($event)); next($event)) {
939  $result_list[$assetid.':'.$i][$k] = $event[$k];
940  }
941 
942  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
943  Calendar_Common::getDateComponents(substr($event_end_date, 0, 10).' 00:00:00', 'start_date_'),
944  Calendar_Common::getDateComponents($event_end_date, 'end_date_'));
945 
946  }
947  $i++;
948 
949  } else {
950  // covers a single day only
951  if (($event_end_dts < $day_start_dts) || ($event_start_dts > $day_end_dts)) {
952  // ended too early or started too late to be shown
953  return;
954  }
955  $start_time = gmmktime(0, 0, 0, $event['start_date_mon'], $event['start_date_mday'], $event['start_date_year']);
956  $result_list[$assetid.':'.$i] = Array();
957  for (reset($event); NULL !== ($k = key($event)); next($event)) {
958  $result_list[$assetid.':'.$i][$k] = $event[$k];
959  }
960 
961  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
962  Calendar_Common::getDateComponents($event_start_date, 'start_date_'),
963  Calendar_Common::getDateComponents($event_end_date, 'end_date_'));
964 
965  $i++;
966  }
967  } else {
968  // end date is not specified - must be just a date or a point in time
969  if (!is_null($event['start_date_hours'])) {
970  // the time is specified
971  if (($event_start_dts < $day_start_dts) || ($event_start_dts > $day_end_dts)) {
972  // the time is too early or late in the day to be shown
973  return;
974  }
975  }
976  $start_time = gmmktime(0, 0, 0, $event['start_date_mon'], $event['start_date_mday'], $event['start_date_year']);
977  $result_list[$assetid.':'.$i] = Array();
978  for (reset($event); NULL !== ($k = key($event)); next($event)) {
979  $result_list[$assetid.':'.$i][$k] = $event[$k];
980  }
981 
982  if (!is_null($event['start_date_hours'])) {
983  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
984  Calendar_Common::getDateComponents($event_start_date, 'start_date_'),
985  Calendar_Common::getDateComponents($event_start_date, 'end_date_'));
986  } else {
987  // when this timestamp was cached, it was calculated with the UTC standard, so respect this when converting it back
988  $start_date = gmdate('Y-m-d', $start_time);
989  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
990  Calendar_Common::getDateComponents($start_date.' 00:00:00', 'start_date_'),
991  Calendar_Common::getDateComponents($start_date.' 24:00:00', 'end_date_'));
992  }
993 
994  $i++;
995 
996  }
997 
998  }//end _expandSingleEvent()
999 
1000 
1016  function _expandRecurringEvent(&$result_list, &$event, $assetid, $first_day, $last_day, $day_start_time, $day_end_time)
1017  {
1018  require_once dirname(__FILE__).'/../calendar_events/calendar_event_recurring/calendar_event_recurring.inc';
1019  $GLOBALS['SQ_SYSTEM']->am->includeAsset('calendar_event_recurring');
1020 
1021  $event['expanded'] = 1;
1022 
1023  $day_start_bits = explode(':', $day_start_time);
1024  $day_start_dts = ($day_start_bits[0] * 60) + $day_start_bits[1];
1025  $day_end_bits = explode(':', $day_end_time);
1026  $day_end_dts = ($day_end_bits[0] * 60) + $day_end_bits[1];
1027 
1028  $no_evt_end_date_ds = is_null($event['end_date_ds']) || empty($event['end_date_ds']);
1029  $no_evt_start_date_hours = is_null($event['start_date_hours']) || empty($event['start_date_hours']);
1030  $no_evt_end_date_hours = is_null($event['end_date_hours']) || empty($event['end_date_hours']);
1031  $no_evt_start_date_hours = is_null($event['start_date_hours']) || empty($event['start_date_hours']);
1032 
1033  $event_start_date = sprintf('%04d-%02d-%02d %02d:%02d:00', $event['start_date_year'], $event['start_date_mon'], $event['start_date_mday'], $event['start_date_hours'], $event['start_date_minutes']);
1034  $event_end_date = $no_evt_end_date_ds ? NULL : sprintf('%04d-%02d-%02d %02d:%02d:00', $event['end_date_year'], $event['end_date_mon'], $event['end_date_mday'], $event['end_date_hours'], $event['end_date_minutes']);
1035 
1036  $event_start_dts = $no_evt_start_date_hours ? NULL : (($event['start_date_hours'] * 60) + $event['start_date_minutes']);
1037  $event_end_dts = $no_evt_end_date_hours ? NULL : (($event['end_date_hours'] * 60) + $event['end_date_minutes']);
1038 
1039  // dispose of one case immediately
1040  if ($no_evt_end_date_ds && !$no_evt_start_date_hours) {
1041  // this is a single point in time
1042  if (($event_start_dts < $day_start_dts) || ($event_start_dts > $day_end_dts)) {
1043  // it occurs too early or late in the day
1044  return;
1045  }
1046  }
1047 
1048  // figure out the effective stop date
1049  if (($event['stop_date'] != '----------') && ($event['stop_date'] < $last_day)) {
1050  // stop date is before last day
1051  $event_last_day = $event['stop_date'];
1052  } else {
1053  // stop date is after last day
1054  $event_last_day = $last_day;
1055  }
1056 
1057  // find the earliest potentially-relevant occurrence
1058  switch ($event['frequency']{0}) {
1059  case 'D':
1060  $first_occur = add_days_to_iso($first_day, -$event['period']);
1061  break;
1062 
1063  case 'W':
1064  $first_occur = add_days_to_iso($first_day, -$event['period']*7);
1065  break;
1066 
1067  case 'M':
1068  $first_occur = add_months_to_iso($first_day, -$event['period']).'-'.date('d', strtotime($first_day));
1069  break;
1070 
1071  }
1072  // if multiple day event, subtract a further <event length> days so it catches those
1073  // events occurring before last recurrence but long enough to extend into this period
1074  if (!is_null($event['end_date_ds'])) {
1075  $first_occur = add_days_to_iso($first_day, -($event['end_date_ds']-$event['start_date_ds']));
1076  }
1077  $next_occur = Calendar_Event_Recurring::getFirstOccurrenceAfter($first_occur, $event_start_date, $event['frequency'], $event['period'], $event_last_day);
1078 
1079  // process instances until we get to the end of the period
1080  $i = 0;
1081 
1082  while (($next_occur !== FALSE) && (substr($next_occur, 0, 10) <= $last_day)) {
1083 
1084  $next_occur_ds = Calendar_Common::_getDayStamp($next_occur);
1085  // days between occurrences
1086  $difference = $next_occur_ds - $event['start_date_ds'];
1087 
1088  if (!$no_evt_end_date_ds) {
1089  // end date is specified
1090  if ($event['start_date_ds'] != $event['end_date_ds']) {
1091 
1092  // multiple day
1093  $start_time = gmmktime(0, 0, 0, $event['start_date_mon'], $event['start_date_mday'], $event['start_date_year'])+$difference*86400;
1094  $start_date = date('Y-m-d', $start_time);
1095 
1096  $end_time = gmmktime(0, 0, 0, $event['end_date_mon'], $event['end_date_mday'], $event['end_date_year'])+$difference*86400;
1097  $end_date = date('Y-m-d', $end_time);
1098 
1099  if (($start_date >= $first_day) && ($start_date <= $last_day) && (is_null($event_start_dts) || ($event_start_dts <= $day_end_dts))) {
1100  // add the first day
1101  $result_list[$assetid.':'.$i] = Array();
1102  for (reset($event); NULL !== ($k = key($event)); next($event)) {
1103  $result_list[$assetid.':'.$i][$k] = $event[$k];
1104  }
1105 
1106  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
1107  Calendar_Common::getDateComponents($event_start_date.' +'.$difference.' days', 'start_date_'),
1108  Calendar_Common::getDateComponents($start_date.' 24:00:00', 'end_date_'));
1109 
1110  $i++;
1111 
1112  }
1113 
1114  // add the intervening days
1115  for ($inter_time = $start_time + 86400; $inter_time < $end_time; $inter_time += 86400) {
1116  $inter_date = date('Y-m-d', $inter_time);
1117  if (($inter_date >= $first_day) && ($inter_date <= $last_day)) {
1118 
1119  $result_list[$assetid.':'.$i] = Array();
1120  for (reset($event); NULL !== ($k = key($event)); next($event)) {
1121  $result_list[$assetid.':'.$i][$k] = $event[$k];
1122  }
1123 
1124  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
1125  Calendar_Common::getDateComponents($inter_date.' 00:00:00', 'start_date_'),
1126  Calendar_Common::getDateComponents($inter_date.' 24:00:00', 'end_date_'));
1127 
1128  $result_list[$assetid.':'.$i]['partition_start'] = $day_start_time;
1129 
1130  $i++;
1131  }
1132  }
1133 
1134  if (($end_date >= $first_day) && ($end_date <= $last_day) && (is_null($event_end_dts) || ($event_end_dts > $day_start_dts))) {
1135  // add the last day
1136  $result_list[$assetid.':'.$i] = Array();
1137  for (reset($event); NULL !== ($k = key($event)); next($event)) {
1138  $result_list[$assetid.':'.$i][$k] = $event[$k];
1139  }
1140 
1141  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
1142  Calendar_Common::getDateComponents($end_date.' 00:00:00', 'start_date_'),
1143  Calendar_Common::getDateComponents($event_end_date.' +'.$difference.' days', 'end_date_'));
1144 
1145  $result_list[$assetid.':'.$i]['partition_start'] = $day_start_time;
1146 
1147  $i++;
1148  }
1149 
1150  } else {
1151 
1152  // fully-specified but falls within a single day
1153  $start_time = gmmktime(0, 0, 0, $event['start_date_mon'], $event['start_date_mday'], $event['start_date_year'])+$difference*86400;
1154  $start_date = date('Y-m-d', $start_time);
1155  if (($start_date >= $first_day) && ($start_date <= $last_day) &&
1156  (is_null($event_start_dts) ||
1157  (($event_start_dts >= $day_start_dts) && ($event_start_dts < $day_end_dts)) ||
1158  (($event_end_dts <= $day_end_dts) && ($event_end_dts > $day_start_dts)) ||
1159  (($event_start_dts < $day_start_dts) && ($event_end_dts > $day_end_dts))
1160  )
1161  ) {
1162  $result_list[$assetid.':'.$i] = Array();
1163  for (reset($event); NULL !== ($k = key($event)); next($event)) {
1164  $result_list[$assetid.':'.$i][$k] = $event[$k];
1165  }
1166 
1167  $event_date_components = array_merge(Calendar_Common::getDateComponents($event_start_date.' +'.$difference.' days', 'start_date_'),
1168  Calendar_Common::getDateComponents($event_end_date.' +'.$difference.' days', 'end_date_')
1169  );
1170 
1171  // If there is not a time specified, this event will be shown in the "all-day" row.
1172  // Null values need to be preserved for the time for this to occur
1173  $date_vars = Array(
1174  'start_date_hours', 'start_date_minutes', 'start_date_seconds',
1175  'end_date_hours', 'end_date_minutes', 'end_date_seconds',
1176  );
1177 
1178  foreach ($date_vars as $date_var) {
1179  if (is_null($event[$date_var]) || empty($event[$date_var])) {
1180  $event_date_components[$date_var] = NULL;
1181  }
1182  }
1183 
1184  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i], $event_date_components);
1185 
1186  // Free memory
1187  $event_date_components = NULL;
1188 
1189  $i++;
1190  }
1191  }//end else
1192 
1193  } else {
1194 
1195  // end date not specified, so it's either just a date or a point in time
1196  $start_time = gmmktime(0, 0, 0, $event['start_date_mon'], $event['start_date_mday'], $event['start_date_year'])+$difference*86400;
1197  $start_date = date('Y-m-d', $start_time);
1198 
1199  if (($start_date >= $first_day) && ($start_date <= $last_day)) {
1200  $result_list[$assetid.':'.$i] = Array();
1201  for (reset($event); NULL !== ($k = key($event)); next($event)) {
1202  $result_list[$assetid.':'.$i][$k] = $event[$k];
1203  }
1204 
1205  if (!is_null($event['start_date_hours'])) {
1206  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
1207  Calendar_Common::getDateComponents($event_start_date.' +'.$difference.' days', 'start_date_'),
1208  Calendar_Common::getDateComponents($event_start_date.' +'.$difference.' days', 'end_date_'));
1209  } else {
1210  $result_list[$assetid.':'.$i] = array_merge($result_list[$assetid.':'.$i],
1211  Calendar_Common::getDateComponents($start_date.' 00:00:00', 'start_date_'),
1212  Calendar_Common::getDateComponents($start_date.' 24:00:00', 'end_date_'));
1213  }
1214 
1215  $i++;
1216  }
1217 
1218  }
1219  // get the next occurrence
1220  $next_occur = Calendar_Event_Recurring::getFirstOccurrenceAfter(add_days_to_iso($next_occur, 1), $event_start_date, $event['frequency'], $event['period'], $event_last_day);
1221 
1222  }//end while
1223 
1224  }//end _expandRecurringEvent()
1225 
1226 
1235  function _getDayStamp($value)
1236  {
1237  if (is_numeric($value)) {
1238  // timestamp
1239  return floor($value / 86400);
1240  } else {
1241  // iso format
1242  $value = strtotime(substr($value, 0, 10).' 00:00:00 Z') - strtotime('1970-01-01 00:00:00 Z');
1243  return floor($value / 86400);
1244  }
1245 
1246  }//end _getDayStamp()
1247 
1248 
1257  function _getMonthStamp($value)
1258  {
1259  if (is_numeric($value)) {
1260  // convert timestamp to ISO
1261  $value = ts_iso8601($value);
1262  }
1263  list($year, $month) = sscanf($value, '%04d-%02d');
1264  return ($year * 12) + $month;
1265 
1266  }//end _getMonthStamp()
1267 
1268 
1278  function _getTypeDescendantsQuoted($type_code)
1279  {
1280  // only needed because of quote()
1281  $db =MatrixDAL::getDb();
1282 
1283  $type_codes = $GLOBALS['SQ_SYSTEM']->am->getTypeDescendants($type_code);
1284  $type_codes[] = $type_code;
1285 
1286  foreach ($type_codes as $tc_key => $tc_value) {
1287  $type_codes[$tc_key] = MatrixDAL::quote($tc_value);
1288  }
1289 
1290  return $type_codes;
1291 
1292  }//end _getTypeDescendantsQuoted()
1293 
1294 
1305  function limitRecurringEventInstances($events, $instances)
1306  {
1307  $frequency_threshold = $GLOBALS['SQ_SYSTEM']->getUserPrefs('calendar_event_recurring', 'SQ_CALENDAR_EVENTS_FREQUENCY');
1308 
1309  if ($frequency_threshold <= 0) {
1310  return $instances;
1311  }
1312  $GLOBALS['SQ_SYSTEM']->am->includeAsset('calendar_event_recurring');
1313 
1314  $limit_events = Array();
1315  foreach($events as $event) {
1316  $recurring_descandants = $GLOBALS['SQ_SYSTEM']->am->getTypeDescendants('calendar_event_recurring');
1317  if (($event['type_code'] == 'calendar_event_recurring') || in_array($event['type_code'], $recurring_descandants)) {
1318  $event_frequency = Calendar_Event_Recurring::getEventFrequency($event);
1319  if ($event_frequency < $frequency_threshold) {
1320  $limit_events[$event['assetid']] = 1;
1321  }
1322  }//end if
1323  }//end foreach
1324 
1325  // If the events frequnecy is less than the defined frequency threshold,
1326  // remove all the instances but the first one
1327  foreach($instances as $key => $instance) {
1328 
1329  if (isset($limit_events[$instance['assetid']]) && $key != $instance['assetid'].':0') {
1330  unset($instances[$key]);
1331  }
1332  }//end foreach
1333 
1334  return $instances;
1335 
1336  }//end limitRecurringEventInstances()
1337 
1338 
1351  function getWholeEventInstances($events, $first_day, $last_day, $day_start_time='00:00', $day_end_time='23:59')
1352  {
1353  $frequency_limit = $GLOBALS['SQ_SYSTEM']->getUserPrefs('calendar_event_recurring', 'SQ_CALENDAR_EVENTS_FREQUENCY');
1354 
1355  $multi_date_event = Array();
1356  foreach ($events as $key => $event) {
1357  $assetid = $event['assetid'];
1358  }
1359 
1360  $res = Array();
1361  foreach ($events as $key => $event) {
1362  $assetid = $event['assetid'];
1363  $recurring_descandants = $GLOBALS['SQ_SYSTEM']->am->getTypeDescendants('calendar_event_recurring');
1364  if (($event['type_code'] == 'calendar_event_recurring') || in_array($event['type_code'], $recurring_descandants)) {
1365  Calendar_Common::_getRecurringEventWholeInstances($res, $event, $assetid, $first_day, $last_day, $day_start_time, $day_end_time, $frequency_limit);
1366  } else {
1367  Calendar_Common::_getSingleEventWholeInstance($res, $event, $assetid, $first_day, $last_day, $day_start_time, $day_end_time);
1368  }
1369  }
1370 
1371  return $res;
1372 
1373  }//end expandEventList()
1374 
1375 
1391  function _getSingleEventWholeInstance(&$result_list, &$event, $assetid, $limit_start_day, $limit_end_day, $limit_start_time, $limit_end_time)
1392  {
1393  if (empty($limit_start_day ) || empty($limit_end_day)) {
1394  return;
1395  }
1396 
1397  // Event start time data
1398  $start_day = $event['start_date_year'].'-'.$event['start_date_mon'].'-'.$event['start_date_mday'];
1399  $start_time = (is_null($event['start_date_hours']) ? '00' : $event['start_date_hours']).':'.(is_null($event['start_date_minutes']) ? '00' : $event['start_date_minutes']).':00';
1400  $start_ts = strtotime($start_day.' '.$start_time);
1401  $start_time_offset = ((is_null($event['start_date_hours']) ? 0 : $event['start_date_hours'])*3600)+((is_null($event['start_date_minutes']) ? 0 : $event['start_date_minutes'])*60);
1402 
1403  // Event end time data
1404  if (!is_null($event['end_date_year'])) {
1405  $end_day = $event['end_date_year'].'-'.$event['end_date_mon'].'-'.$event['end_date_mday'];
1406  $end_time = (is_null($event['end_date_hours']) ? '23' : $event['end_date_hours']).':'.(is_null($event['end_date_minutes']) ? '59' : $event['end_date_minutes']).':00';
1407  if (strpos($end_time,'24:') !== FALSE) $end_time = '23:59:00';
1408  $end_ts = strtotime($end_day.' '.$end_time);
1409  } else {
1410  $end_day = $start_day;
1411  $end_time = '23:59:00';
1412  $end_ts = $start_ts;
1413  }
1414 
1415  $limit_start_ts = strtotime($limit_start_day.' '.$limit_start_time);
1416  $limit_end_ts = strtotime($limit_end_day.' '.$limit_end_time);
1417 
1418  // Check that the event is within the given limit
1419  if (($start_ts >= $limit_start_ts && $start_ts <= $limit_end_ts ) || ($start_ts <= $limit_start_ts && $end_ts >= $limit_start_ts )) {
1420 
1421  $type_code = $event['type_code'];
1422  $result = Array();
1423 
1424  $result[$event['assetid'].':start_date_ts='.$start_ts.',end_date_ts='.$end_ts.',type_code='.$type_code] = $start_ts;
1425 
1426  $result_list = array_merge($result_list, $result);
1427  }//end if
1428 
1429  }//end _getSingleEventWholeInstance()
1430 
1431 
1448  function _getRecurringEventWholeInstances(&$result_list, $event, $assetid, $first_day, $last_day, $day_start_time, $day_end_time, $frequency_threshold)
1449  {
1450  // Event start time data (first instance)
1451  $start_day = $event['start_date_year'].'-'.str_pad($event['start_date_mon'],2,'0',STR_PAD_LEFT).'-'.str_pad($event['start_date_mday'],2,'0',STR_PAD_LEFT);
1452  $start_time = (is_null($event['start_date_hours']) ? '00' : $event['start_date_hours']).':'.(is_null($event['start_date_minutes']) ? '00' : $event['start_date_minutes']).':00';
1453 
1454  // Event end time data (first instance)
1455  if (!is_null($event['end_date_year'])) {
1456  $end_day = $event['end_date_year'].'-'.str_pad($event['end_date_mon'],2,'0',STR_PAD_LEFT).'-'.str_pad($event['end_date_mday'],2,'0',STR_PAD_LEFT);
1457  $end_time = (is_null($event['end_date_hours']) ? '23' : $event['end_date_hours']).':'.(is_null($event['end_date_minutes']) ? '59' : $event['end_date_minutes']).':00';
1458  if (strpos($end_time,'24:') !== FALSE) $end_time = '23:59:00';
1459  } else {
1460  $end_day = $start_day;
1461  $end_time = '23:59:00';
1462  }
1463 
1464  $event_period_ts = strtotime($end_day.' '.$end_time) - strtotime($start_day.' '.$start_time);
1465  if ($event_period_ts < 0) return;
1466 
1467  $GLOBALS['SQ_SYSTEM']->am->includeAsset('calendar_event_recurring');
1468 
1469  $after = $first_day;
1470  $type_code = $event['type_code'];
1471  $event_frequency = Calendar_Event_Recurring::getEventFrequency($event);
1472 
1473  // Event runs untill
1474  $stop_day = $event['stop_date'] == '----------' ? $last_day : $event['stop_date'];
1475 
1476  do {
1477  $next_occurance = Calendar_Event_Recurring::getFirstOccurrenceAfter($after, $start_day, $event['frequency'], $event['period'], $stop_day);
1478  if ($next_occurance > $last_day) break;
1479 
1480  if ($next_occurance) {
1481  $i_start_ts = strtotime($next_occurance.' '.$start_time);
1482  $i_end_ts = $i_start_ts+$event_period_ts;
1483  $result_list[$assetid.':start_date_ts='.$i_start_ts.',end_date_ts='.$i_end_ts.',type_code='.$type_code] = $i_start_ts;
1484 
1485  // Based on recurring event frequency set, put only one instance for given recurring event
1486  if ($event_frequency < $frequency_threshold) {
1487  break;
1488  }
1489 
1490  $after = add_days_to_iso($next_occurance);
1491  }
1492  } while($next_occurance);
1493 
1494  }//end _getRecurringEventWholeInstances()
1495 
1496 }//end class
1497 ?>