]> git.mxchange.org Git - friendica-addons.git/blob - dav/SabreDAV/lib/Sabre/VObject/Component/VCalendar.php
Move friendica-specific parts into an own subdirectory
[friendica-addons.git] / dav / SabreDAV / lib / Sabre / VObject / Component / VCalendar.php
1 <?php
2
3 /**
4  * The VCalendar component
5  *
6  * This component adds functionality to a component, specific for a VCALENDAR.
7  * 
8  * @package Sabre
9  * @subpackage VObject
10  * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
11  * @author Evert Pot (http://www.rooftopsolutions.nl/) 
12  * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
13  */
14 class Sabre_VObject_Component_VCalendar extends Sabre_VObject_Component {
15
16     /**
17      * Returns a list of all 'base components'. For instance, if an Event has 
18      * a recurrence rule, and one instance is overridden, the overridden event 
19      * will have the same UID, but will be excluded from this list.
20      *
21      * VTIMEZONE components will always be excluded. 
22      *
23      * @param string $componentName filter by component name 
24      * @return array 
25      */
26     public function getBaseComponents($componentName = null) {
27
28         $components = array();
29         foreach($this->children as $component) {
30
31             if (!$component instanceof Sabre_VObject_Component)
32                 continue;
33
34             if (isset($component->{'RECURRENCE-ID'})) 
35                 continue;
36
37             if ($componentName && $component->name !== strtoupper($componentName)) 
38                 continue;
39
40             if ($component->name === 'VTIMEZONE')
41                 continue;
42
43             $components[] = $component;
44
45         }
46
47         return $components;
48
49     }
50
51     /**
52      * If this calendar object, has events with recurrence rules, this method 
53      * can be used to expand the event into multiple sub-events.
54      *
55      * Each event will be stripped from it's recurrence information, and only 
56      * the instances of the event in the specified timerange will be left 
57      * alone.
58      *
59      * In addition, this method will cause timezone information to be stripped, 
60      * and normalized to UTC.
61      *
62      * This method will alter the VCalendar. This cannot be reversed.
63      *
64      * This functionality is specifically used by the CalDAV standard. It is 
65      * possible for clients to request expand events, if they are rather simple 
66      * clients and do not have the possibility to calculate recurrences.
67      *
68      * @param DateTime $start
69      * @param DateTime $end 
70      * @return void
71      */
72     public function expand(DateTime $start, DateTime $end) {
73
74         $newEvents = array();
75
76         foreach($this->select('VEVENT') as $key=>$vevent) {
77
78             if (isset($vevent->{'RECURRENCE-ID'})) {
79                 unset($this->children[$key]);
80                 continue;
81             } 
82
83
84             if (!$vevent->rrule) {
85                 unset($this->children[$key]);
86                 if ($vevent->isInTimeRange($start, $end)) {
87                     $newEvents[] = $vevent;
88                 }
89                 continue;
90             }
91
92             $uid = (string)$vevent->uid;
93             if (!$uid) {
94                 throw new LogicException('Event did not have a UID!');
95             }
96
97             $it = new Sabre_VObject_RecurrenceIterator($this, $vevent->uid);
98             $it->fastForward($start);
99
100             while($it->valid() && $it->getDTStart() < $end) {
101
102                 if ($it->getDTEnd() > $start) {
103
104                     $newEvents[] = $it->getEventObject();
105
106                 }
107                 $it->next();
108
109             }
110             unset($this->children[$key]);
111
112         }
113
114         foreach($newEvents as $newEvent) {
115
116             foreach($newEvent->children as $child) {
117                 if ($child instanceof Sabre_VObject_Property_DateTime &&
118                     $child->getDateType() == Sabre_VObject_Property_DateTime::LOCALTZ) {
119                         $child->setDateTime($child->getDateTime(),Sabre_VObject_Property_DateTime::UTC);
120                     }
121             }
122
123             $this->add($newEvent);
124
125         }
126
127         // Removing all VTIMEZONE components
128         unset($this->VTIMEZONE);
129
130     } 
131
132     /**
133      * Validates the node for correctness.
134      * An array is returned with warnings.
135      *
136      * Every item in the array has the following properties:
137      *    * level - (number between 1 and 3 with severity information)
138      *    * message - (human readable message)
139      *    * node - (reference to the offending node)
140      * 
141      * @return array 
142      */
143     public function validate() {
144
145         $warnings = array();
146
147         $version = $this->select('VERSION');
148         if (count($version)!==1) {
149             $warnings[] = array(
150                 'level' => 1,
151                 'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time',
152                 'node' => $this,
153             );
154         } else {
155             if ((string)$this->VERSION !== '2.0') {
156                 $warnings[] = array(
157                     'level' => 1,
158                     'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.',
159                     'node' => $this,
160                 );
161             }
162         } 
163         $version = $this->select('PRODID');
164         if (count($version)!==1) {
165             $warnings[] = array(
166                 'level' => 2,
167                 'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time',
168                 'node' => $this,
169             );
170         }
171         if (count($this->CALSCALE) > 1) {
172             $warnings[] = array(
173                 'level' => 2,
174                 'message' => 'The CALSCALE property must not be specified more than once.',
175                 'node' => $this,
176             );
177         }
178         if (count($this->METHOD) > 1) {
179             $warnings[] = array(
180                 'level' => 2,
181                 'message' => 'The METHOD property must not be specified more than once.',
182                 'node' => $this,
183             );
184         }
185
186         $allowedComponents = array(
187             'VEVENT',
188             'VTODO',
189             'VJOURNAL',
190             'VFREEBUSY',
191             'VTIMEZONE',
192         );
193         $allowedProperties = array(
194             'PRODID',
195             'VERSION',
196             'CALSCALE',
197             'METHOD',
198         );
199         $componentsFound = 0;
200         foreach($this->children as $child) {
201             if($child instanceof Sabre_VObject_Component) {
202                 $componentsFound++;
203                 if (!in_array($child->name, $allowedComponents)) {
204                     $warnings[] = array(
205                         'level' => 1,
206                         'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component",
207                         'node' => $this,
208                     );
209                 }
210             }
211             if ($child instanceof Sabre_VObject_Property) {
212                 if (!in_array($child->name, $allowedProperties)) {
213                     $warnings[] = array(
214                         'level' => 2,
215                         'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component",
216                         'node' => $this,
217                     );
218                 }
219             }
220         }
221
222         if ($componentsFound===0) {
223             $warnings[] = array(
224                 'level' => 1,
225                 'message' => 'An iCalendar object must have at least 1 component.',
226                 'node' => $this,
227             );
228         }
229
230         return array_merge(
231             $warnings,
232             parent::validate()
233         );
234
235     }
236
237 }
238