]> git.mxchange.org Git - friendica-addons.git/blob - dav/sabre-vobject/lib/Sabre/VObject/FreeBusyGenerator.php
Second part of refactoring; should be runnable again, yet not thoroughly tested
[friendica-addons.git] / dav / sabre-vobject / lib / Sabre / VObject / FreeBusyGenerator.php
1 <?php
2
3 namespace Sabre\VObject;
4
5 /**
6  * This class helps with generating FREEBUSY reports based on existing sets of
7  * objects.
8  *
9  * It only looks at VEVENT and VFREEBUSY objects from the sourcedata, and
10  * generates a single VFREEBUSY object.
11  *
12  * VFREEBUSY components are described in RFC5545, The rules for what should
13  * go in a single freebusy report is taken from RFC4791, section 7.10.
14  *
15  * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
16  * @author Evert Pot (http://www.rooftopsolutions.nl/)
17  * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
18  */
19 class FreeBusyGenerator {
20
21     /**
22      * Input objects
23      *
24      * @var array
25      */
26     protected $objects;
27
28     /**
29      * Start of range
30      *
31      * @var DateTime|null
32      */
33     protected $start;
34
35     /**
36      * End of range
37      *
38      * @var DateTime|null
39      */
40     protected $end;
41
42     /**
43      * VCALENDAR object
44      *
45      * @var Component
46      */
47     protected $baseObject;
48
49     /**
50      * Creates the generator.
51      *
52      * Check the setTimeRange and setObjects methods for details about the
53      * arguments.
54      *
55      * @param DateTime $start
56      * @param DateTime $end
57      * @param mixed $objects
58      * @return void
59      */
60     public function __construct(\DateTime $start = null, \DateTime $end = null, $objects = null) {
61
62         if ($start && $end) {
63             $this->setTimeRange($start, $end);
64         }
65
66         if ($objects) {
67             $this->setObjects($objects);
68         }
69
70     }
71
72     /**
73      * Sets the VCALENDAR object.
74      *
75      * If this is set, it will not be generated for you. You are responsible
76      * for setting things like the METHOD, CALSCALE, VERSION, etc..
77      *
78      * The VFREEBUSY object will be automatically added though.
79      *
80      * @param Component $vcalendar
81      * @return void
82      */
83     public function setBaseObject(Component $vcalendar) {
84
85         $this->baseObject = $vcalendar;
86
87     }
88
89     /**
90      * Sets the input objects
91      *
92      * You must either specify a valendar object as a strong, or as the parse
93      * Component.
94      * It's also possible to specify multiple objects as an array.
95      *
96      * @param mixed $objects
97      * @return void
98      */
99     public function setObjects($objects) {
100
101         if (!is_array($objects)) {
102             $objects = array($objects);
103         }
104
105         $this->objects = array();
106         foreach($objects as $object) {
107
108             if (is_string($object)) {
109                 $this->objects[] = Reader::read($object);
110             } elseif ($object instanceof Component) {
111                 $this->objects[] = $object;
112             } else {
113                 throw new \InvalidArgumentException('You can only pass strings or \\Sabre\\VObject\\Component arguments to setObjects');
114             }
115
116         }
117
118     }
119
120     /**
121      * Sets the time range
122      *
123      * Any freebusy object falling outside of this time range will be ignored.
124      *
125      * @param DateTime $start
126      * @param DateTime $end
127      * @return void
128      */
129     public function setTimeRange(\DateTime $start = null, \DateTime $end = null) {
130
131         $this->start = $start;
132         $this->end = $end;
133
134     }
135
136     /**
137      * Parses the input data and returns a correct VFREEBUSY object, wrapped in
138      * a VCALENDAR.
139      *
140      * @return Component
141      */
142     public function getResult() {
143
144         $busyTimes = array();
145
146         foreach($this->objects as $object) {
147
148             foreach($object->getBaseComponents() as $component) {
149
150                 switch($component->name) {
151
152                     case 'VEVENT' :
153
154                         $FBTYPE = 'BUSY';
155                         if (isset($component->TRANSP) && (strtoupper($component->TRANSP) === 'TRANSPARENT')) {
156                             break;
157                         }
158                         if (isset($component->STATUS)) {
159                             $status = strtoupper($component->STATUS);
160                             if ($status==='CANCELLED') {
161                                 break;
162                             }
163                             if ($status==='TENTATIVE') {
164                                 $FBTYPE = 'BUSY-TENTATIVE';
165                             }
166                         }
167
168                         $times = array();
169
170                         if ($component->RRULE) {
171
172                             $iterator = new RecurrenceIterator($object, (string)$component->uid);
173                             if ($this->start) {
174                                 $iterator->fastForward($this->start);
175                             }
176
177                             $maxRecurrences = 200;
178
179                             while($iterator->valid() && --$maxRecurrences) {
180
181                                 $startTime = $iterator->getDTStart();
182                                 if ($this->end && $startTime > $this->end) {
183                                     break;
184                                 }
185                                 $times[] = array(
186                                     $iterator->getDTStart(),
187                                     $iterator->getDTEnd(),
188                                 );
189
190                                 $iterator->next();
191
192                             }
193
194                         } else {
195
196                             $startTime = $component->DTSTART->getDateTime();
197                             if ($this->end && $startTime > $this->end) {
198                                 break;
199                             }
200                             $endTime = null;
201                             if (isset($component->DTEND)) {
202                                 $endTime = $component->DTEND->getDateTime();
203                             } elseif (isset($component->DURATION)) {
204                                 $duration = DateTimeParser::parseDuration((string)$component->DURATION);
205                                 $endTime = clone $startTime;
206                                 $endTime->add($duration);
207                             } elseif ($component->DTSTART->getDateType() === Property\DateTime::DATE) {
208                                 $endTime = clone $startTime;
209                                 $endTime->modify('+1 day');
210                             } else {
211                                 // The event had no duration (0 seconds)
212                                 break;
213                             }
214
215                             $times[] = array($startTime, $endTime);
216
217                         }
218
219                         foreach($times as $time) {
220
221                             if ($this->end && $time[0] > $this->end) break;
222                             if ($this->start && $time[1] < $this->start) break;
223
224                             $busyTimes[] = array(
225                                 $time[0],
226                                 $time[1],
227                                 $FBTYPE,
228                             );
229                         }
230                         break;
231
232                     case 'VFREEBUSY' :
233                         foreach($component->FREEBUSY as $freebusy) {
234
235                             $fbType = isset($freebusy['FBTYPE'])?strtoupper($freebusy['FBTYPE']):'BUSY';
236
237                             // Skipping intervals marked as 'free'
238                             if ($fbType==='FREE')
239                                 continue;
240
241                             $values = explode(',', $freebusy);
242                             foreach($values as $value) {
243                                 list($startTime, $endTime) = explode('/', $value);
244                                 $startTime = DateTimeParser::parseDateTime($startTime);
245
246                                 if (substr($endTime,0,1)==='P' || substr($endTime,0,2)==='-P') {
247                                     $duration = DateTimeParser::parseDuration($endTime);
248                                     $endTime = clone $startTime;
249                                     $endTime->add($duration);
250                                 } else {
251                                     $endTime = DateTimeParser::parseDateTime($endTime);
252                                 }
253
254                                 if($this->start && $this->start > $endTime) continue;
255                                 if($this->end && $this->end < $startTime) continue;
256                                 $busyTimes[] = array(
257                                     $startTime,
258                                     $endTime,
259                                     $fbType
260                                 );
261
262                             }
263
264
265                         }
266                         break;
267
268
269
270                 }
271
272
273             }
274
275         }
276
277         if ($this->baseObject) {
278             $calendar = $this->baseObject;
279         } else {
280             $calendar = new Component('VCALENDAR');
281             $calendar->version = '2.0';
282             $calendar->prodid = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN';
283             $calendar->calscale = 'GREGORIAN';
284         }
285
286         $vfreebusy = new Component('VFREEBUSY');
287         $calendar->add($vfreebusy);
288
289         if ($this->start) {
290             $dtstart = new Property\DateTime('DTSTART');
291             $dtstart->setDateTime($this->start,Property\DateTime::UTC);
292             $vfreebusy->add($dtstart);
293         }
294         if ($this->end) {
295             $dtend = new Property\DateTime('DTEND');
296             $dtend->setDateTime($this->start,Property\DateTime::UTC);
297             $vfreebusy->add($dtend);
298         }
299         $dtstamp = new Property\DateTime('DTSTAMP');
300         $dtstamp->setDateTime(new \DateTime('now'), Property\DateTime::UTC);
301         $vfreebusy->add($dtstamp);
302
303         foreach($busyTimes as $busyTime) {
304
305             $busyTime[0]->setTimeZone(new \DateTimeZone('UTC'));
306             $busyTime[1]->setTimeZone(new \DateTimeZone('UTC'));
307
308             $prop = new Property(
309                 'FREEBUSY',
310                 $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z')
311             );
312             $prop['FBTYPE'] = $busyTime[2];
313             $vfreebusy->add($prop);
314
315         }
316
317         return $calendar;
318
319     }
320
321 }
322