[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/calendar/classes/ -> rrule_manager.php (source)

   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  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1