[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * Defines calendar class to manage recurrence rule (rrule) during ical imports. 19 * 20 * @package core_calendar 21 * @copyright 2014 onwards Ankit Agarwal 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace core_calendar; 26 defined('MOODLE_INTERNAL') || die(); 27 require_once($CFG->dirroot . '/calendar/lib.php'); 28 29 /** 30 * Defines calendar class to manage recurrence rule (rrule) during ical imports. 31 * 32 * Please refer to RFC 2445 {@link http://www.ietf.org/rfc/rfc2445.txt} for detail explanation of the logic. 33 * Here is a basic extract from it to explain various params:- 34 * recur = "FREQ"=freq *( 35 * ; either UNTIL or COUNT may appear in a 'recur', 36 * ; but UNTIL and COUNT MUST NOT occur in the same 'recur' 37 * ( ";" "UNTIL" "=" enddate ) / 38 * ( ";" "COUNT" "=" 1*DIGIT ) / 39 * ; the rest of these keywords are optional, 40 * ; but MUST NOT occur more than once 41 * ( ";" "INTERVAL" "=" 1*DIGIT ) / 42 * ( ";" "BYSECOND" "=" byseclist ) / 43 * ( ";" "BYMINUTE" "=" byminlist ) / 44 * ( ";" "BYHOUR" "=" byhrlist ) / 45 * ( ";" "BYDAY" "=" bywdaylist ) / 46 * ( ";" "BYMONTHDAY" "=" bymodaylist ) / 47 * ( ";" "BYYEARDAY" "=" byyrdaylist ) / 48 * ( ";" "BYWEEKNO" "=" bywknolist ) / 49 * ( ";" "BYMONTH" "=" bymolist ) / 50 * ( ";" "BYSETPOS" "=" bysplist ) / 51 * ( ";" "WKST" "=" weekday ) / 52 * ( ";" x-name "=" text ) 53 * ) 54 * 55 * freq = "SECONDLY" / "MINUTELY" / "HOURLY" / "DAILY" 56 * / "WEEKLY" / "MONTHLY" / "YEARLY" 57 * enddate = date 58 * enddate =/ date-time ;An UTC value 59 * byseclist = seconds / ( seconds *("," seconds) ) 60 * seconds = 1DIGIT / 2DIGIT ;0 to 59 61 * byminlist = minutes / ( minutes *("," minutes) ) 62 * minutes = 1DIGIT / 2DIGIT ;0 to 59 63 * byhrlist = hour / ( hour *("," hour) ) 64 * hour = 1DIGIT / 2DIGIT ;0 to 23 65 * bywdaylist = weekdaynum / ( weekdaynum *("," weekdaynum) ) 66 * weekdaynum = [([plus] ordwk / minus ordwk)] weekday 67 * plus = "+" 68 * minus = "-" 69 * ordwk = 1DIGIT / 2DIGIT ;1 to 53 70 * weekday = "SU" / "MO" / "TU" / "WE" / "TH" / "FR" / "SA" 71 * ;Corresponding to SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, 72 * ;FRIDAY, SATURDAY and SUNDAY days of the week. 73 * bymodaylist = monthdaynum / ( monthdaynum *("," monthdaynum) ) 74 * monthdaynum = ([plus] ordmoday) / (minus ordmoday) 75 * ordmoday = 1DIGIT / 2DIGIT ;1 to 31 76 * byyrdaylist = yeardaynum / ( yeardaynum *("," yeardaynum) ) 77 * yeardaynum = ([plus] ordyrday) / (minus ordyrday) 78 * ordyrday = 1DIGIT / 2DIGIT / 3DIGIT ;1 to 366 79 * bywknolist = weeknum / ( weeknum *("," weeknum) ) 80 * weeknum = ([plus] ordwk) / (minus ordwk) 81 * bymolist = monthnum / ( monthnum *("," monthnum) ) 82 * monthnum = 1DIGIT / 2DIGIT ;1 to 12 83 * bysplist = setposday / ( setposday *("," setposday) ) 84 * setposday = yeardaynum 85 * 86 * @package core_calendar 87 * @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com> 88 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 89 */ 90 class rrule_manager { 91 92 /** const string Frequency constant */ 93 const FREQ_YEARLY = 'yearly'; 94 95 /** const string Frequency constant */ 96 const FREQ_MONTHLY = 'monthly'; 97 98 /** const string Frequency constant */ 99 const FREQ_WEEKLY = 'weekly'; 100 101 /** const string Frequency constant */ 102 const FREQ_DAILY = 'daily'; 103 104 /** const string Frequency constant */ 105 const FREQ_HOURLY = 'hourly'; 106 107 /** const string Frequency constant */ 108 const FREQ_MINUTELY = 'everyminute'; 109 110 /** const string Frequency constant */ 111 const FREQ_SECONDLY = 'everysecond'; 112 113 /** const string Day constant */ 114 const DAY_MONDAY = 'Monday'; 115 116 /** const string Day constant */ 117 const DAY_TUESDAY = 'Tuesday'; 118 119 /** const string Day constant */ 120 const DAY_WEDNESDAY = 'Wednesday'; 121 122 /** const string Day constant */ 123 const DAY_THURSDAY = 'Thursday'; 124 125 /** const string Day constant */ 126 const DAY_FRIDAY = 'Friday'; 127 128 /** const string Day constant */ 129 const DAY_SATURDAY = 'Saturday'; 130 131 /** const string Day constant */ 132 const DAY_SUNDAY = 'Sunday'; 133 134 /** const int For forever repeating events, repeat for this many years */ 135 const TIME_UNLIMITED_YEARS = 10; 136 137 /** @var string string representing the recurrence rule */ 138 protected $rrule; 139 140 /** @var string Frequency of event */ 141 protected $freq; 142 143 /** @var int defines a timestamp value which bounds the recurrence rule in an inclusive manner.*/ 144 protected $until = 0; 145 146 /** @var int Defines the number of occurrences at which to range-bound the recurrence */ 147 protected $count = 0; 148 149 /** @var int This rule part contains a positive integer representing how often the recurrence rule repeats */ 150 protected $interval = 1; 151 152 /** @var array List of second rules */ 153 protected $bysecond = array(); 154 155 /** @var array List of Minute rules */ 156 protected $byminute = array(); 157 158 /** @var array List of hour rules */ 159 protected $byhour = array(); 160 161 /** @var array List of day rules */ 162 protected $byday = array(); 163 164 /** @var array List of monthday rules */ 165 protected $bymonthday = array(); 166 167 /** @var array List of yearday rules */ 168 protected $byyearday = array(); 169 170 /** @var array List of weekno rules */ 171 protected $byweekno = array(); 172 173 /** @var array List of month rules */ 174 protected $bymonth = array(); 175 176 /** @var array List of setpos rules */ 177 protected $bysetpos = array(); 178 179 /** @var array week start rules */ 180 protected $wkst; 181 182 /** 183 * Constructor for the class 184 * 185 * @param string $rrule Recurrence rule 186 */ 187 public function __construct($rrule) { 188 $this->rrule = $rrule; 189 } 190 191 /** 192 * Parse the recurrence rule and setup all properties. 193 */ 194 public function parse_rrule() { 195 $rules = explode(';', $this->rrule); 196 if (empty($rules)) { 197 return; 198 } 199 foreach ($rules as $rule) { 200 $this->parse_rrule_property($rule); 201 } 202 } 203 204 /** 205 * Parse a property of the recurrence rule. 206 * 207 * @param string $prop property string with type-value pair 208 * @throws \moodle_exception 209 */ 210 protected function parse_rrule_property($prop) { 211 list($property, $value) = explode('=', $prop); 212 switch ($property) { 213 case 'FREQ' : 214 $this->set_frequency($value); 215 break; 216 case 'UNTIL' : 217 $this->until = strtotime($value); 218 break; 219 CASE 'COUNT' : 220 $this->count = intval($value); 221 break; 222 CASE 'INTERVAL' : 223 $this->interval = intval($value); 224 break; 225 CASE 'BYSECOND' : 226 $this->bysecond = explode(',', $value); 227 break; 228 CASE 'BYMINUTE' : 229 $this->byminute = explode(',', $value); 230 break; 231 CASE 'BYHOUR' : 232 $this->byhour = explode(',', $value); 233 break; 234 CASE 'BYDAY' : 235 $this->byday = explode(',', $value); 236 break; 237 CASE 'BYMONTHDAY' : 238 $this->bymonthday = explode(',', $value); 239 break; 240 CASE 'BYYEARDAY' : 241 $this->byyearday = explode(',', $value); 242 break; 243 CASE 'BYWEEKNO' : 244 $this->byweekno = explode(',', $value); 245 break; 246 CASE 'BYMONTH' : 247 $this->bymonth = explode(',', $value); 248 break; 249 CASE 'BYSETPOS' : 250 $this->bysetpos = explode(',', $value); 251 break; 252 CASE 'WKST' : 253 $this->wkst = $this->get_day($value); 254 break; 255 default: 256 // We should never get here, something is very wrong. 257 throw new \moodle_exception('errorrrule', 'calendar'); 258 } 259 } 260 261 /** 262 * Sets Frequency property. 263 * 264 * @param string $freq Frequency of event 265 * @throws \moodle_exception 266 */ 267 protected function set_frequency($freq) { 268 switch ($freq) { 269 case 'YEARLY': 270 $this->freq = self::FREQ_YEARLY; 271 break; 272 case 'MONTHLY': 273 $this->freq = self::FREQ_MONTHLY; 274 break; 275 case 'WEEKLY': 276 $this->freq = self::FREQ_WEEKLY; 277 break; 278 case 'DAILY': 279 $this->freq = self::FREQ_DAILY; 280 break; 281 case 'HOURLY': 282 $this->freq = self::FREQ_HOURLY; 283 break; 284 case 'MINUTELY': 285 $this->freq = self::FREQ_MINUTELY; 286 break; 287 case 'SECONDLY': 288 $this->freq = self::FREQ_SECONDLY; 289 break; 290 default: 291 // We should never get here, something is very wrong. 292 throw new \moodle_exception('errorrrulefreq', 'calendar'); 293 } 294 } 295 296 /** 297 * Gets the day from day string. 298 * 299 * @param string $daystring Day string (MO, TU, etc) 300 * @throws \moodle_exception 301 * 302 * @return string Day represented by the parameter. 303 */ 304 protected function get_day($daystring) { 305 switch ($daystring) { 306 case 'MO': 307 return self::DAY_MONDAY; 308 break; 309 case 'TU': 310 return self::DAY_TUESDAY; 311 break; 312 case 'WE': 313 return self::DAY_WEDNESDAY; 314 break; 315 case 'TH': 316 return self::DAY_THURSDAY; 317 break; 318 case 'FR': 319 return self::DAY_FRIDAY; 320 break; 321 case 'SA': 322 return self::DAY_SATURDAY; 323 break; 324 case 'SU': 325 return self::DAY_SUNDAY; 326 break; 327 default: 328 // We should never get here, something is very wrong. 329 throw new \moodle_exception('errorrruleday', 'calendar'); 330 } 331 } 332 333 /** 334 * Create events for specified rrule. 335 * 336 * @param \calendar_event $passedevent Properties of event to create. 337 * @throws \moodle_exception 338 */ 339 public function create_events($passedevent) { 340 global $DB; 341 342 $event = clone($passedevent); 343 // If Frequency is not set, there is nothing to do. 344 if (empty($this->freq)) { 345 return; 346 } 347 348 // Delete all child events in case of an update. This should be faster than verifying if the event exists and updating it. 349 $where = "repeatid = ? AND id != ?"; 350 $DB->delete_records_select('event', $where, array($event->id, $event->id)); 351 $eventrec = $event->properties(); 352 353 switch ($this->freq) { 354 case self::FREQ_DAILY : 355 $this->create_repeated_events($eventrec, DAYSECS); 356 break; 357 case self::FREQ_WEEKLY : 358 $this->create_weekly_events($eventrec); 359 break; 360 case self::FREQ_MONTHLY : 361 $this->create_monthly_events($eventrec); 362 break; 363 case self::FREQ_YEARLY : 364 $this->create_yearly_events($eventrec); 365 break; 366 default : 367 // We should never get here, something is very wrong. 368 throw new \moodle_exception('errorrulefreq', 'calendar'); 369 370 } 371 372 } 373 374 /** 375 * Create repeated events. 376 * 377 * @param \stdClass $event Event properties to create event 378 * @param int $timediff Time difference between events in seconds 379 * @param bool $currenttime If set, the event timestart is used as the timestart for the first event, 380 * else timestart + timediff used as the timestart for the first event. Set to true if 381 * parent event is not a part of this chain. 382 */ 383 protected function create_repeated_events($event, $timediff, $currenttime = false) { 384 385 $event = clone($event); // We don't want to edit the master record. 386 $event->repeatid = $event->id; // Set parent id for all events. 387 unset($event->id); // We want new events created, not update the existing one. 388 unset($event->uuid); // uuid should be unique. 389 $count = $this->count; 390 391 // Multiply by interval if used. 392 if ($this->interval) { 393 $timediff *= $this->interval; 394 } 395 if (!$currenttime) { 396 $event->timestart += $timediff; 397 } 398 399 // Create events. 400 if ($count > 0) { 401 // Count specified, use it. 402 if (!$currenttime) { 403 $count--; // Already a parent event has been created. 404 } 405 for ($i = 0; $i < $count; $i++, $event->timestart += $timediff) { 406 unset($event->id); // It is set during creation. 407 \calendar_event::create($event, false); 408 } 409 } else { 410 // No count specified, use datetime constraints. 411 $until = $this->until; 412 if (empty($until)) { 413 // Forever event. We don't have any such concept in Moodle, hence we repeat it for a constant time. 414 $until = time() + (YEARSECS * self::TIME_UNLIMITED_YEARS); 415 } 416 for (; $event->timestart < $until; $event->timestart += $timediff) { 417 unset($event->id); // It is set during creation. 418 \calendar_event::create($event, false); 419 } 420 } 421 } 422 423 /** 424 * Create repeated events based on offsets. 425 * 426 * @param \stdClass $event 427 * @param int $secsoffset Seconds since the start of the day that this event occurs 428 * @param int $dayoffset Day offset. 429 * @param int $monthoffset Months offset. 430 * @param int $yearoffset Years offset. 431 * @param int $start timestamp to apply offsets onto. 432 * @param bool $currenttime If set, the event timestart is used as the timestart for the first event, 433 * else timestart + timediff(monthly offset + yearly offset) used as the timestart for the first 434 * event.Set to true if parent event is not a part of this chain. 435 */ 436 protected function create_repeated_events_by_offsets($event, $secsoffset, $dayoffset, $monthoffset, $yearoffset, $start, 437 $currenttime = false) { 438 439 $event = clone($event); // We don't want to edit the master record. 440 $event->repeatid = $event->id; // Set parent id for all events. 441 unset($event->id); // We want new events created, not update the existing one. 442 unset($event->uuid); // uuid should be unique. 443 $count = $this->count; 444 // First event time in this chain. 445 $event->timestart = strtotime("+$dayoffset days", $start) + $secsoffset; 446 447 if (!$currenttime) { 448 // Skip one event, since parent event is a part of this chain. 449 $event->timestart = strtotime("+$monthoffset months +$yearoffset years", $event->timestart); 450 } 451 452 // Create events. 453 if ($count > 0) { 454 // Count specified, use it. 455 if (!$currenttime) { 456 $count--; // Already a parent event has been created. 457 } 458 for ($i = 0; $i < $count; $i++) { 459 unset($event->id); // It is set during creation. 460 \calendar_event::create($event, false); 461 $event->timestart = strtotime("+$monthoffset months +$yearoffset years", $event->timestart); 462 } 463 } else { 464 // No count specified, use datetime constraints. 465 $until = $this->until; 466 if (empty($until)) { 467 // Forever event. We don't have any such concept in Moodle, hence we repeat it for a constant time. 468 $until = time() + (YEARSECS * self::TIME_UNLIMITED_YEARS ); 469 } 470 for (; $event->timestart < $until;) { 471 unset($event->id); // It is set during creation. 472 \calendar_event::create($event, false); 473 $event->timestart = strtotime("+$monthoffset months +$yearoffset years", $event->timestart); 474 475 } 476 } 477 } 478 479 /** 480 * Create repeated events based on offsets from a fixed start date. 481 * 482 * @param \stdClass $event 483 * @param int $secsoffset Seconds since the start of the day that this event occurs 484 * @param string $prefix Prefix string to add to strtotime while calculating next date for the event. 485 * @param int $monthoffset Months offset. 486 * @param int $yearoffset Years offset. 487 * @param int $start timestamp to apply offsets onto. 488 * @param bool $currenttime If set, the event timestart is used as the timestart + offset for the first event, 489 * else timestart + timediff(monthly offset + yearly offset) + offset used as the timestart for the 490 * first event, from the given fixed start time. Set to true if parent event is not a part of this 491 * chain. 492 */ 493 protected function create_repeated_events_by_offsets_from_fixedstart($event, $secsoffset, $prefix, $monthoffset, 494 $yearoffset, $start, $currenttime = false) { 495 496 $event = clone($event); // We don't want to edit the master record. 497 $event->repeatid = $event->id; // Set parent id for all events. 498 unset($event->id); // We want new events created, not update the existing one. 499 unset($event->uuid); // uuid should be unique. 500 $count = $this->count; 501 502 // First event time in this chain. 503 if (!$currenttime) { 504 // Skip one event, since parent event is a part of this chain. 505 $moffset = $monthoffset; 506 $yoffset = $yearoffset; 507 $event->timestart = strtotime("+$monthoffset months +$yearoffset years", $start); 508 $event->timestart = strtotime($prefix, $event->timestart) + $secsoffset; 509 } else { 510 $moffset = 0; 511 $yoffset = 0; 512 $event->timestart = strtotime($prefix, $event->timestart) + $secsoffset; 513 } 514 // Create events. 515 if ($count > 0) { 516 // Count specified, use it. 517 if (!$currenttime) { 518 $count--; // Already a parent event has been created. 519 } 520 for ($i = 0; $i < $count; $i++) { 521 unset($event->id); // It is set during creation. 522 \calendar_event::create($event, false); 523 $moffset += $monthoffset; 524 $yoffset += $yearoffset; 525 $event->timestart = strtotime("+$moffset months +$yoffset years", $start); 526 $event->timestart = strtotime($prefix, $event->timestart) + $secsoffset; 527 } 528 } else { 529 // No count specified, use datetime constraints. 530 $until = $this->until; 531 if (empty($until)) { 532 // Forever event. We don't have any such concept in Moodle, hence we repeat it for a constant time. 533 $until = time() + (YEARSECS * self::TIME_UNLIMITED_YEARS ); 534 } 535 for (; $event->timestart < $until;) { 536 unset($event->id); // It is set during creation. 537 \calendar_event::create($event, false); 538 $moffset += $monthoffset; 539 $yoffset += $yearoffset; 540 $event->timestart = strtotime("+$moffset months +$yoffset years", $start); 541 $event->timestart = strtotime($prefix, $event->timestart) + $secsoffset; 542 } 543 } 544 } 545 546 /** 547 * Create events for weekly frequency. 548 * 549 * @param \stdClass $event Event properties to create event 550 */ 551 protected function create_weekly_events($event) { 552 // If by day is not present, it means all days of the week. 553 if (empty($this->byday)) { 554 $this->byday = array('MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'); 555 } 556 // This much seconds after the start of the day. 557 $offset = $event->timestart - mktime(0, 0, 0, date("n", $event->timestart), date("j", $event->timestart), date("Y", 558 $event->timestart)); 559 foreach ($this->byday as $daystring) { 560 $day = $this->get_day($daystring); 561 if (date('l', $event->timestart) == $day) { 562 // Parent event is a part of this day chain. 563 $this->create_repeated_events($event, WEEKSECS, false); 564 } else { 565 // Parent event is not a part of this day chain. 566 $cpyevent = clone($event); // We don't want to change timestart of master record. 567 $cpyevent->timestart = strtotime("+$offset seconds next $day", $cpyevent->timestart); 568 $this->create_repeated_events($cpyevent, WEEKSECS, true); 569 } 570 } 571 } 572 573 /** 574 * Create events for monthly frequency. 575 * 576 * @param \stdClass $event Event properties to create event 577 */ 578 protected function create_monthly_events($event) { 579 // Either bymonthday or byday should be set. 580 if (empty($this->bymonthday) && empty($this->byday) 581 || !empty($this->bymonthday) && !empty($this->byday)) { 582 return; 583 } 584 // This much seconds after the start of the day. 585 $offset = $event->timestart - mktime(0, 0, 0, date("n", $event->timestart), date("j", $event->timestart), date("Y", 586 $event->timestart)); 587 $monthstart = mktime(0, 0, 0, date("n", $event->timestart), 1, date("Y", $event->timestart)); 588 if (!empty($this->bymonthday)) { 589 foreach ($this->bymonthday as $monthday) { 590 $dayoffset = $monthday - 1; // Number of days we want to add to the first day. 591 if ($monthday == date("j", $event->timestart)) { 592 // Parent event is a part of this day chain. 593 $this->create_repeated_events_by_offsets($event, $offset, $dayoffset, $this->interval, 0, $monthstart, 594 false); 595 } else { 596 // Parent event is not a part of this day chain. 597 $this->create_repeated_events_by_offsets($event, $offset, $dayoffset, $this->interval, 0, $monthstart, true); 598 } 599 } 600 } else { 601 foreach ($this->byday as $dayrule) { 602 $day = substr($dayrule, strlen($dayrule) - 2); // Last two chars. 603 $prefix = str_replace($day, '', $dayrule); 604 if (empty($prefix) || !is_numeric($prefix)) { 605 return; 606 } 607 $day = $this->get_day($day); 608 if ($day == date('l', $event->timestart)) { 609 // Parent event is a part of this day chain. 610 $this->create_repeated_events_by_offsets_from_fixedstart($event, $offset, "$prefix $day", $this->interval, 0, 611 $monthstart, false); 612 } else { 613 // Parent event is not a part of this day chain. 614 $this->create_repeated_events_by_offsets_from_fixedstart($event, $offset, "$prefix $day", $this->interval, 0, 615 $monthstart, true); 616 } 617 618 } 619 } 620 } 621 622 /** 623 * Create events for yearly frequency. 624 * 625 * @param \stdClass $event Event properties to create event 626 */ 627 protected function create_yearly_events($event) { 628 629 // This much seconds after the start of the month. 630 $offset = $event->timestart - mktime(0, 0, 0, date("n", $event->timestart), date("j", $event->timestart), date("Y", 631 $event->timestart)); 632 633 if (empty($this->bymonth)) { 634 // Event's month is taken if not specified. 635 $this->bymonth = array(date("n", $event->timestart)); 636 } 637 foreach ($this->bymonth as $month) { 638 if (empty($this->byday)) { 639 // If byday is not present, the rule must represent the same month as the event start date. Basically we only 640 // have to add + $this->interval number of years to get the next event date. 641 if ($month == date("n", $event->timestart)) { 642 // Parent event is a part of this month chain. 643 $this->create_repeated_events_by_offsets($event, 0, 0, 0, $this->interval, $event->timestart, false); 644 } 645 } else { 646 $dayrule = reset($this->byday); 647 $day = substr($dayrule, strlen($dayrule) - 2); // Last two chars. 648 $prefix = str_replace($day, '', $dayrule); 649 if (empty($prefix) || !is_numeric($prefix)) { 650 return; 651 } 652 $day = $this->get_day($day); 653 $monthstart = mktime(0, 0, 0, $month, 1, date("Y", $event->timestart)); 654 if ($day == date('l', $event->timestart)) { 655 // Parent event is a part of this day chain. 656 $this->create_repeated_events_by_offsets_from_fixedstart($event, $offset, "$prefix $day", 0, 657 $this->interval, $monthstart, false); 658 } else { 659 // Parent event is not a part of this day chain. 660 $this->create_repeated_events_by_offsets_from_fixedstart($event, $offset, "$prefix $day", 0, 661 $this->interval, $monthstart, true); 662 } 663 } 664 } 665 } 666 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |