PATH:
home
/
letacommog
/
crmleta
/
modules
/
Mobile
/
third-party
/
qCal
/
qCal
/
DateTime
<?php /** * This is a class that is used within qCal_Value_Recur to internally store a recur property * @todo The RFC says that invalid byXXX rule parts should simply be ignored. So I'm not sure if * I should be hurling exceptions at the poor user all over the place like I am in here. */ abstract class qCal_DateTime_Recur { /** * @var array An array of week days. Used throughout this class to validate input. */ protected $weekdays = array( 'MO' => 'Monday', 'TU' => 'Tuesday', 'WE' => 'Wednesday', 'TH' => 'Thursday', 'FR' => 'Friday', 'SA' => 'Saturday', 'SU' => 'Sunday', ); /** * @var qCal_Date The start date/time of the recurrence */ protected $dtstart; /** * @var string frequency of the recurrence */ protected $freq; /** * @var qCal_Date The date/time which the recurrence ends */ protected $until; /** * @var integer The amount of recurrences */ protected $count; /** * @var integer Interval of recurrence (for every 3 days, "3" would be the interval) */ protected $interval; /** * @var integer|array An integer between 0 and 59 (for multiple, set as an array) */ protected $bysecond; /** * @var integer|array An integer between 0 and 59 (or an array of integers for multiple) */ protected $byminute; /** * @var integer|array An integer or array of integers between 0 and 23 */ protected $byhour; /** * @var string If present, represents the nth occurrence of a specific day within monthly or yearly * so it can be something like +1MO (or simply 1MO) for the first monday within the month, whereas * -1MO for the last monday of the month. Or it can be simply MO to represent every monday within the month */ protected $byday; /** * @var integer|array An integer or array of integers. -31 to -1 or 1 to 31. -10 would mean the tenth to last * day of the month. [1,5,-5] would be the 1st, 5th, and 5th to last days of the month */ protected $bymonthday; /** * @var integer|array An integer or array of integers. -366 to -1 or 1 to 366. -306 represents the 306th to last * day of the year (March 1st) */ protected $byyearday; /** * @var integer|array An integer or array of integers. -53 to -1 or 1 to 53. Only valid for yearly rules. * 3 represents the third week of the year. */ protected $byweekno; /** * @var integer|array An integer or array of integers. 1 to 12. 3 would represent March */ protected $bymonth; /** * @var integer If present, it indicates the nth occurrence of the specific occurrence within the set of * events specified by this recurrence rule */ protected $bysetpos; /** * @var string Must be one of the weekdays specified above (2 char). Specifies the day on which the work week * starts. This is significant when a weekly rule has an interval greater than 1 and a byday rule part is specified. * This is also significant when in a yearly rule when a byweekno rule part is specified. Defaults to "MO" */ protected $wkst = "MO"; /** * Constructor * @param $freq string Must be one of the freqtypes specified above. * @throws qCal_Date_Exception_InvalidRecur if a frequency other than those specified above is passed in */ public function __construct($dtstart = null) { $this->dtstart = is_null($dtstart) ? null : qCal_DateTime::factory($dtstart); } /** * Specifies the date when the recurrence stops, inclusively. If not present, and there is no count specified, * then the recurrence goes on "forever". * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param $until string|qCal_Date|DateTime If time is specified, it must be UTC * @throws qCal_Date_Exception_InvalidRecur * @return self */ public function until($until = null) { if (is_null($until)) return $this->until; if ($this->count()) throw new qCal_DateTime_Exception_InvalidRecur('A recurrence count and an until date cannot both be specified'); $this->until = qCal_DateTime::factory($until); return $this; } /** * Specifies the amount of recurrences before the recurrence ends. If neither this nor "until" is specified, * the recurrence repeats "forever". * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param $count integer The amount of recurrences before it stops * @throws qCal_Date_Exception_InvalidRecur * @return self */ public function count($count = null) { if (is_null($count)) return $this->count; if ($this->until()) throw new qCal_DateTime_Exception_InvalidRecur('A recurrence count and an until date cannot both be specified'); $this->count = (integer) $count; return $this; } /** * Specifies the start of the work-week, which is Monday by default */ public function wkst($wkst = null) { if (is_null($wkst)) return $this->wkst; $abbrs = array_keys($this->weekdays); if (!in_array($wkst, $abbrs)) throw new qCal_DateTime_Exception_InvalidRecur('"' . $wkst . '" is not a valid week day, must be one of the following: ' . implode(', ', $abbrs)); $this->wkst = $wkst; // @todo I wonder if re-sorting the weekdays array would help me in any way... } /** * Specifies the interval of recurrences * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param $interval integer The interval of recurrences, for instance every "3" days * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function interval($interval = null) { if (is_null($interval)) return $this->interval; $this->interval = (integer) $interval; return $this; } /** * Specifies a rule which will happen on every nth second. * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param $second integer|array Can be an integer (or array of ints) between 0 and 59 * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function bySecond($second = null) { if (is_null($second)) return $this->bysecond; if (!is_array($second)) $second = array($second); $this->bysecond = $second; return $this; } /** * Specifies a rule which will happen on every nth minute * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param $minute integer|array Can be an integer (or array of ints) between 0 and 59 * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function byMinute($minute = null) { if (is_null($minute)) return $this->byminute; if (!is_array($minute)) $minute = array($minute); $this->byminute = $minute; return $this; } /** * Specifies a rule which will happen on every nth hour * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param $hour integer|array Can be an integer (or array of ints) between 0 and 23 * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function byHour($hour = null) { if (is_null($hour)) return $this->byhour; if (!is_array($hour)) $hour = array($hour); $this->byhour = $hour; return $this; } /** * Specifies a rule which will happen on whichever day is specified. For instance, "MO" would * mean every monday. * This is a getter as well as a setter (if no arg is supplied, it is a getter) * Sets $this->byday into an array of arrays like array('SU' => 1) for '1SU' and array('SU' => 0) for 'SU' * @param $day string|array Must be one of the 2-char week days specified above. Can be preceded by * a positive or negative integer to represent, for instance, the third monday of the month (3MO) or second to last * Sunday of the month (-2SU) * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function byDay($day = null) { if (is_null($day)) { $ret = array(); foreach ($this->byday as $val) { $num = (current($val) == 0) ? "" : current($val); $ret[] = $num . key($val); } return $ret; } if (!is_array($day)) $day = array($day); $days = array(); foreach ($day as $d) { // optional plus or minus followed by a series of digits as group 1 // two-character week day as group 2 if (preg_match('/^([+-]?[0-9]+)?(MO|TU|WE|TH|FR|SA|SU)$/', $d, $matches)) { $num = ($matches[1] == "") ? "0" : $matches[1]; $wday = $matches[2]; if (substr($num, 0, 1) == "+") { $num = substr($num, 1); } $days[] = array($wday => $num); } } $this->byday = $days; return $this; } /** * Specifies a rule which will happen on the month days specified. For instance, 23 would mean the 23rd of every month. * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param integer|array Must be between 1 and 31 or -31 to 1 (or an array of those values) * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function byMonthDay($monthday = null) { if (is_null($monthday)) return $this->bymonthday; if (!is_array($monthday)) $monthday = array($monthday); $this->bymonthday = $monthday; return $this; } /** * Specifies a rule which will happen on the nth day of the year * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param integer|array Must be between 1 and 366 or -366 to -1. * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function byYearDay($yearday = null) { if (is_null($yearday)) return $this->byyearday; if (!is_array($yearday)) $yearday = array($yearday); $this->byyearday = $yearday; return $this; } /** * Specifies a rule which will happen on the nth week of the year * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param integer|array Must be between 1 and 53 or -53 to -1. * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function byWeekNo($weekno = null) { if (is_null($weekno)) return $this->byweekno; if (!is_array($weekno)) $weekno = array($weekno); $this->byweekno = $weekno; return $this; } /** * Specifies a rule which will happen on the nth month of the year * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @param integer|array Must be between 1 and 12 * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function byMonth($month = null) { if (is_null($month)) return $this->bymonth; if (!is_array($month)) $month = array($month); $this->bymonth = $month; return $this; } /** * Indicates the nth occurrence of the specific occurrence within the set of * events specified by the rule. * This is a getter as well as a setter (if no arg is supplied, it is a getter) * @todo I don't really understand how this works... :( Figure out wtf it is for. * @throws qCal_DateTime_Exception_InvalidRecur * @return self */ public function bySetPos($setpos = null) { if (is_null($setpos)) return $this->bysetpos; $this->bysetpos = (integer) $setpos; return $this; } /** * Factory method generates the correct recur type based on the string it is passed: "yearly, weekly, etc." * @param string The frequency type of recurrence rule you want to generate * @param mixed The start date/time for the recurrence. Accepts anything qCal_Date accepts */ static public function factory($freq, $start) { $freq = ucfirst(strtolower($freq)); $className = "qCal_DateTime_Recur_" . $freq; $fileName = str_replace("_", DIRECTORY_SEPARATOR, $className) . ".php"; qCal_Loader::loadFile($fileName); $class = new $className($start); return $class; } /** * Fetches instances of the recurrence rule in the given time period. Because recurrences * could potentially go on forever, there is no way to fetch ALL instances of a recurrence rule * other than providing a date range that spans the entire length of the recurrence. * * The way this will need to work is, depending on the frequency, I will find all possible * occurrence of the rule. For instance, if this is a "monthly" rule, I'll find out which month * to start in, then find all occurrence possible. Then narrow down by the other rules I guess. * * @idea Maybe I should build classes for each of the frequency types. That way I could loop over * the object and get methods like qCal_DateTime_Recur_Monthly::isNthDay('SU') to find out what sunday * of the month it is... stuff like that... I dunno... ? * * @throws qCal_DateTime_Exception_InvalidRecur * @todo The giant switch in this method is a glaring code smell, but it works for now. I will refactor * after version 0.1 and remove the switch (probably will implement qCal_DateTime_Recur_Yearly, qCal_DateTime_Recur_Monthly, etc.) */ public function getRecurrences($start, $end) { $start = qCal_DateTime::factory($start); $end = qCal_DateTime::factory($end); if ($start->getUnixTimestamp() > $end->getUnixTimestamp()) throw new qCal_DateTime_Exception_InvalidRecur('Start date must come before end date'); if (!$this->interval) throw new qCal_DateTime_Exception_InvalidRecur('You must specify an interval'); $rules = array( 'bymonth' => array(), 'byweekno' => array(), 'byyearday' => array(), 'byday' => array(), ); // byMonth rules if (is_array($this->bymonth)) { foreach ($this->bymonth as $bymonth) { $rules['bymonth'][] = new qCal_DateTime_Recur_Rule_ByMonth($bymonth); } } // byWeekNo rules if (is_array($this->byweekno)) { foreach ($this->byweekno as $byweekno) { $rules['byweekno'][] = new qCal_DateTime_Recur_Rule_ByWeekNo($byweekno); } } // byYearDay rules if (is_array($this->byyearday)) { foreach ($this->byyearday as $byyearday) { $rules['byyearday'][] = new qCal_DateTime_Recur_Rule_ByYearDay($byyearday); } } // byMonthDay rules (these get applied to bymonth rules) if (is_array($this->bymonthday)) { foreach ($this->bymonthday as $bymonthday) { $bmdrule = new qCal_DateTime_Recur_Rule_ByMonthDay($bymonthday); foreach ($rules['bymonth'] as $bymonth) { $bymonth->attach($bmdrule); } } } // byDay rules (these get applied to bymonth rules if they exist, otherwise simply to year) if (is_array($this->byday)) { foreach ($this->byday as $byday) { $bdrule = new qCal_DateTime_Recur_Rule_ByDay($byday); if (is_array($rules['bymonth']) && !empty($rules['bymonth'])) { foreach ($rules['bymonth'] as $bymonth) { $bymonth->attach($bdrule); } } else { $rules['byday'][] = $bdrule; } } } // byHour rules (these get applied to each rule above) if (is_array($this->byhour)) { foreach ($this->byhour as $byhour) { $bhrule = new qCal_DateTime_Recur_Rule_ByHour($byhour); foreach ($rules as $type => $ruleset) { foreach ($ruleset as $rule) { $rule->attach($bhrule); } } } } // byMinute rules (these get applied to each rule above) if (is_array($this->byminute)) { foreach ($this->byminute as $byminute) { $bmrule = new qCal_DateTime_Recur_Rule_ByMinute($byminute); foreach ($rules as $type => $ruleset) { foreach ($ruleset as $rule) { $rule->attach($bmrule); } } } } // bySecond rules (these get applied to each rule above) if (is_array($this->bysecond)) { foreach ($this->bysecond as $bysecond) { $bsrule = new qCal_DateTime_Recur_Rule_BySecond($bysecond); foreach ($rules as $type => $ruleset) { foreach ($ruleset as $rule) { $rule->attach($bsrule); } } } } return $this->doGetRecurrences($rules, $start, $end); } /** * Each type of rule needs to determine its recurrences so this is left abstract * to be implemented by children. */ abstract protected function doGetRecurrences($rules, $start, $end); }
[+]
..
[-] Recur.php
[edit]
[-] Timezone.php
[edit]
[+]
Exception
[+]
Recur
[-] Period.php
[edit]
[-] Exception.php
[edit]
[-] Duration.php
[edit]