From 5743c6221e9a18094c8083575ec37164d3c18de3 Mon Sep 17 00:00:00 2001 From: Tanguy Pruvot Date: Sat, 30 Oct 2010 22:44:07 +0200 Subject: [PATCH] implement EXDATE exclusions --- blocks/SG_iCal_VEvent.php | 19 ++++++++++---- helpers/SG_iCal_Freq.php | 45 ++++++++++++++++++++-------------- helpers/SG_iCal_Parser.php | 9 +++++-- helpers/SG_iCal_Recurrence.php | 1 - 4 files changed, 47 insertions(+), 27 deletions(-) diff --git a/blocks/SG_iCal_VEvent.php b/blocks/SG_iCal_VEvent.php index 7b4fa69..c5f5eda 100755 --- a/blocks/SG_iCal_VEvent.php +++ b/blocks/SG_iCal_VEvent.php @@ -26,6 +26,7 @@ class SG_iCal_VEvent { protected $location; public $recurrence; + public $excluded; public $freq; //getFrequency() public $data; @@ -37,20 +38,28 @@ class SG_iCal_VEvent { * @param SG_iCalReader $ical */ public function __construct($data, SG_iCal $ical) { - + $this->uid = $data['uid']->getData(); unset($data['uid']); if ( isset($data['rrule']) ) { $this->recurrence = new SG_iCal_Recurrence($data['rrule']); unset($data['rrule']); + + //exclusions + if ( isset($data['exdate']) ) { + foreach ($data['exdate'] as $exdate) { + $this->excluded[] = $this->getTimestamp($exdate, $ical); + } + unset($data['exdate']); + } } if( isset($data['dtstart']) ) { $this->start = $this->getTimestamp($data['dtstart'], $ical); unset($data['dtstart']); } - + if( isset($data['dtend']) ) { $this->end = $this->getTimestamp($data['dtend'], $ical); unset($data['dtend']); @@ -59,7 +68,7 @@ class SG_iCal_VEvent { $this->end = $this->start + $dur->getDuration(); unset($data['duration']); } - + //google cal set dtend as end of initial event (duration) if ( isset($this->recurrence) ) { //if there is a recurrence rule @@ -70,7 +79,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->freq = new SG_iCal_Freq($this->recurrence->rrule, $start, $this->excluded); $until = $this->freq->lastOccurrence($this->start); } else { //forever... limit to 3 years @@ -105,7 +114,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->freq = new SG_iCal_Freq($this->recurrence->rrule, $this->start, $this->excluded); } } return $this->freq; diff --git a/helpers/SG_iCal_Freq.php b/helpers/SG_iCal_Freq.php index b70a292..3c9d484 100755 --- a/helpers/SG_iCal_Freq.php +++ b/helpers/SG_iCal_Freq.php @@ -31,6 +31,7 @@ class SG_iCal_Freq { protected $rules = array('freq'=>'yearly', 'interval'=>1); protected $start = 0; protected $freq = ''; + protected $excluded; public $cache; @@ -39,8 +40,9 @@ class SG_iCal_Freq { * @param $rule string * @param $start int Unix-timestamp (important : Need to be the start of Event) */ - public function __construct( $rule, $start ) { + public function __construct( $rule, $start, $excluded=array()) { $this->start = $start; + $this->excluded = $excluded; $rules = array(); foreach( explode(';', $rule) AS $v) { @@ -53,7 +55,6 @@ class SG_iCal_Freq { } $this->freq = strtolower($this->rules['freq']); - foreach( $this->knownRules AS $rule ) { if( isset($this->rules['by' . $rule]) ) { if( $this->isPrerule($rule, $this->freq) ) { @@ -68,13 +69,11 @@ class SG_iCal_Freq { } } - //set until, and cache + //set until if( isset($this->rules['count']) ) { $ts = $this->firstOccurrence(); - $this->cache[0] = $ts; for($i=1; $i<$this->rules['count']; $i++) { $ts = $this->findNext($ts); - $this->cache[$i] = $ts; } $this->rules['until'] = $ts; } @@ -88,10 +87,12 @@ class SG_iCal_Freq { public function getAllOccurrences() { if (empty($this->cache)) { //build cache - $i=0; $this->cache[0] = $this->start; + unset($this->cache); + $this->cache[] = $this->start; $next = $this->findNext($this->start); while ($next) { - $i++; $this->cache[$i] = $next; + //if (!in_array($next, $this->excluded)) + $this->cache[] = $next; $next = $this->findNext($next); } } @@ -106,7 +107,7 @@ class SG_iCal_Freq { */ public function previousOccurrence( $offset ) { if (!empty($this->cache)) { - $t2=$this->cache[0]; + $t2=$this->start; foreach($this->cache as $ts) { if ($ts >= $offset) return $t2; @@ -151,11 +152,9 @@ class SG_iCal_Freq { if (!empty($this->cache)) { return end($this->cache); } - $i=0; $this->cache[0] = $this->start; $ts = $next = $this->findNext($this->start); while ($next) { $ts = $next; - $i++; $this->cache[$i] = $ts; $next = $this->findNext($ts); } return $ts; @@ -185,7 +184,6 @@ class SG_iCal_Freq { * @return int */ public function findNext($offset) { - if (!empty($this->cache)) { foreach($this->cache as $ts) { if ($ts > $offset) @@ -214,10 +212,11 @@ class SG_iCal_Freq { if( $this->simpleMode ) { if( $offset < $t ) { return $t; - } - $next = $this->findStartingPoint( $t, $this->rules['interval'], false ); - if( !$this->validDate( $next ) ) { - return $this->findNext($next); + } else { + $next = $this->findStartingPoint( $t, $this->rules['interval'], false ); + if( !$this->validDate( $next ) ) { + return $this->findNext($next); + } } return $next; } @@ -250,19 +249,23 @@ class SG_iCal_Freq { } if( $offset < $this->start && $this->start < $t ) { - return $this->start; + $ts = $this->start; } else if( $found && ($t != $offset)) { if( $this->validDate( $t ) ) { if($debug) echo 'OK' . "\n"; - return $t; + $ts = $t; } else { if($debug) echo 'Invalid' . "\n"; - return $this->findNext($t); + $ts = $this->findNext($t); } } else { if($debug) echo 'Not found' . "\n"; - return $this->findNext( $this->findStartingPoint( $offset, $this->rules['interval'] ) ); + $ts = $this->findNext( $this->findStartingPoint( $offset, $this->rules['interval'] ) ); } + if ($ts && in_array($ts, $this->excluded)) + return $this->findNext($ts); + + return $ts; } /** @@ -454,6 +457,10 @@ class SG_iCal_Freq { if( isset($this->rules['until']) && $t > $this->rules['until'] ) { return false; } + + if (in_array($t, $this->excluded)) { + return false; + } if( isset($this->rules['bymonth']) ) { $months = explode(',', $this->rules['bymonth']); diff --git a/helpers/SG_iCal_Parser.php b/helpers/SG_iCal_Parser.php index ca02896..429f7ea 100755 --- a/helpers/SG_iCal_Parser.php +++ b/helpers/SG_iCal_Parser.php @@ -119,8 +119,13 @@ class SG_iCal_Parser { if( array_search($s, $sections) !== false ) { // This section is in the main section if( $section == $s ) { - // It _is_ the main section - $current_data[$s][$line->getIdent()] = $line; + // It _is_ the main section else + if ($line->getIdent() != "exdate") + $current_data[$s][$line->getIdent()] = $line; + else { + //exdate could appears more that once + $current_data[$s][$line->getIdent()][] = $line; + } } else { // Sub section $current_data[$s][$section][$line->getIdent()] = $line; diff --git a/helpers/SG_iCal_Recurrence.php b/helpers/SG_iCal_Recurrence.php index bcc05ac..a80d1db 100755 --- a/helpers/SG_iCal_Recurrence.php +++ b/helpers/SG_iCal_Recurrence.php @@ -42,7 +42,6 @@ class SG_iCal_Recurrence { 'byyearday', 'byyearno', 'bymonth', 'bysetpos' ); - /** * Creates an recurrence object with a passed in line. Parses the line. * @param object $line an SG_iCal_Line object which will be parsed to get the