From 1ae7b2978ebb6e339024a57d17ec6d305645cbc4 Mon Sep 17 00:00:00 2001 From: Tanguy Pruvot Date: Sun, 31 Oct 2010 20:06:16 +0100 Subject: [PATCH] RDATE support --- README | 27 +++++++++++++++-- blocks/SG_iCal_VEvent.php | 59 +++++++++++++++++++++++++------------- helpers/SG_iCal_Freq.php | 42 ++++++++++++++++++++------- helpers/SG_iCal_Parser.php | 2 +- 4 files changed, 96 insertions(+), 34 deletions(-) diff --git a/README b/README index 4235ffc..8c14257 100644 --- a/README +++ b/README @@ -1,7 +1,8 @@ A simple and fast iCal parser. +------------------------------------------------------------------------------- http://github.com/tpruvot/PHP-iCal - -About this fork (forked at v0.5.0 from http://github.com/fangel/SG-iCalendar) +fork from http://github.com/fangel/SG-iCalendar +------------------------------------------------------------------------------- A simple example : $ical = new SG_iCalReader( "./basic.ics" ); @@ -15,8 +16,14 @@ To check unit tests with phpunit, goto tests/ directory and : phpunit AllTests phpunit helpers/FreqTest -Changelog : +------------------------------------------------------------------------------- +CHANGELOG : +------------------------------------------------------------------------------- +current (31 oct 2010) + + ical RDATE support (added dates in a range) + + RDATE and EXDATE arrays support + 0.7.0-tpr (30 oct 2010) + ical EXDATE support (excluded dates in a range) + $event->isWholeDay() @@ -29,3 +36,17 @@ Changelog : + Support of Recurrent events in query Between() * various fixes on actual (5) issues +------------------------------------------------------------------------------- +TODO : +------------------------------------------------------------------------------- + +These iCal keywords are not supported for the moment : + - RECURRENCE-ID : to move one event from a recurrence + - EXRULE : to exclude multiple days by a complex rule + +Also, multiple RRULE could be specified for an event, +but that is not the case for most calendar applications + +------------------------------------------------------------------------------- +To get more information about ical format and rules : +see http://www.ietf.org/rfc/rfc2445.txt diff --git a/blocks/SG_iCal_VEvent.php b/blocks/SG_iCal_VEvent.php index 434655d..0e6c084 100755 --- a/blocks/SG_iCal_VEvent.php +++ b/blocks/SG_iCal_VEvent.php @@ -17,17 +17,23 @@ class SG_iCal_VEvent { const DEFAULT_CONFIRMED = true; protected $uid; + protected $start; protected $end; - protected $laststart; - protected $lastend; + protected $summary; protected $description; protected $location; - public $recurrence; - public $excluded; - public $freq; //getFrequency() + protected $laststart; + protected $lastend; + + public $recurrence; //RRULE + public $recurex; //EXRULE + public $excluded; //EXDATE(s) + public $added; //RDATE(s) + + public $freq; //getFrequency() SG_iCal_Freq public $data; @@ -47,6 +53,11 @@ class SG_iCal_VEvent { unset($data['rrule']); } + if ( isset($data['exrule']) ) { + $this->recurex = new SG_iCal_Recurrence($data['exrule']); + unset($data['exrule']); + } + if( isset($data['dtstart']) ) { $this->start = $this->getTimestamp($data['dtstart'], $ical); unset($data['dtstart']); @@ -68,13 +79,21 @@ class SG_iCal_VEvent { //exclusions if ( isset($data['exdate']) ) { foreach ($data['exdate'] as $exdate) { - //$this->excluded[] = $this->getTimestamp($exdate, $ical); foreach ($exdate->getDataAsArray() as $ts) { $this->excluded[] = strtotime($ts); } } unset($data['exdate']); } + //additions + if ( isset($data['rdate']) ) { + foreach ($data['rdate'] as $rdate) { + foreach ($rdate->getDataAsArray() as $ts) { + $this->added[] = strtotime($ts); + } + } + unset($data['rdate']); + } $until = $this->recurrence->getUntil(); $count = $this->recurrence->getCount(); @@ -83,7 +102,7 @@ class SG_iCal_VEvent { //ok.. } elseif ($count) { //if count is set, then figure out the last occurrence and set that as the end date - $this->freq = new SG_iCal_Freq($this->recurrence->rrule, $start, $this->excluded); + $this->getFrequency(); $until = $this->freq->lastOccurrence($this->start); } else { //forever... limit to 3 years @@ -118,7 +137,7 @@ class SG_iCal_VEvent { public function getFrequency() { if (! isset($this->freq)) { if ( isset($this->recurrence) ) { - $this->freq = new SG_iCal_Freq($this->recurrence->rrule, $this->start, $this->excluded); + $this->freq = new SG_iCal_Freq($this->recurrence->rrule, $this->start, $this->excluded, $this->added); } } return $this->freq; @@ -176,6 +195,18 @@ class SG_iCal_VEvent { } } + /** + * Returns true if duration is multiple of 86400 + * @return bool + */ + public function isWholeDay() { + $dur = $this->getDuration(); + if ($dur > 0 && ($dur % 86400) == 0) { + return true; + } + return false; + } + /** * Returns the timestamp for the beginning of the event * @return int @@ -208,18 +239,6 @@ class SG_iCal_VEvent { return $this->end - $this->start; } - /** - * Returns true if duration is multiple of 86400 - * @return bool - */ - public function isWholeDay() { - $dur = $this->getDuration(); - if ($dur > 0 && ($dur % 86400) == 0) { - return true; - } - return false; - } - /** * Returns the given property of the event. * @param string $prop diff --git a/helpers/SG_iCal_Freq.php b/helpers/SG_iCal_Freq.php index 69a4801..abb48c0 100755 --- a/helpers/SG_iCal_Freq.php +++ b/helpers/SG_iCal_Freq.php @@ -33,17 +33,20 @@ class SG_iCal_Freq { protected $freq = ''; protected $excluded; //EXDATE + protected $added; //RDATE - public $cache; + protected $cache; // getAllOccurrences() /** * Constructs a new Freqency-rule * @param $rule string * @param $start int Unix-timestamp (important : Need to be the start of Event) + * @param $excluded array of int (timestamps), see EXDATE documentation + * @param $added array of int (timestamps), see RDATE documentation */ - public function __construct( $rule, $start, $excluded=array()) { + public function __construct( $rule, $start, $excluded=array(), $added=array()) { $this->start = $start; - $this->excluded = $excluded; + $this->excluded = array(); $rules = array(); foreach( explode(';', $rule) AS $v) { @@ -72,15 +75,31 @@ class SG_iCal_Freq { //set until, and cache if( isset($this->rules['count']) ) { - $ts = $this->start; - $cache[0] = $ts; + + $cache[$ts] = $ts = $this->start; for($n=1; $n < $this->rules['count']; $n++) { $ts = $this->findNext($ts); - $cache[$n] = $ts; + $cache[$ts] = $ts; } $this->rules['until'] = $ts; - $this->cache = $cache; + + //EXDATE + if (!empty($excluded)) { + foreach($excluded as $ts) { + unset($cache[$ts]); + } + } + //RDATE + if (!empty($added)) { + $cache = $cache + $added; + asort($cache); + } + + $this->cache = array_values($cache); } + + $this->excluded = $excluded; + $this->added = $added; } @@ -91,12 +110,15 @@ class SG_iCal_Freq { public function getAllOccurrences() { if (empty($this->cache)) { //build cache - $n=0; $cache[$n] = $this->start; - $next = $this->findNext($this->start); + $next = $this->firstOccurrence(); while ($next) { - $n++; $cache[$n] = $next; + $cache[] = $next; $next = $this->findNext($next); } + if (!empty($this->added)) { + $cache = $cache + $this->added; + asort($cache); + } $this->cache = $cache; } return $this->cache; diff --git a/helpers/SG_iCal_Parser.php b/helpers/SG_iCal_Parser.php index 2ddd99a..5a68576 100755 --- a/helpers/SG_iCal_Parser.php +++ b/helpers/SG_iCal_Parser.php @@ -93,7 +93,7 @@ class SG_iCal_Parser { */ private static function _Parse( $content, SG_iCal $ical ) { $main_sections = array('vevent', 'vjournal', 'vtodo', 'vtimezone', 'vcalendar'); - $array_idents = array('exdate'); + $array_idents = array('exdate','rdate'); $sections = array(); $section = ''; $current_data = array();