]> git.mxchange.org Git - friendica-addons.git/blob - dav/SabreDAV/lib/Sabre/VObject/Component.php
Set notifications of events; the actual notification routine is not yet implemented
[friendica-addons.git] / dav / SabreDAV / lib / Sabre / VObject / Component.php
1 <?php
2
3 /**
4  * VObject Component
5  *
6  * This class represents a VCALENDAR/VCARD component. A component is for example
7  * VEVENT, VTODO and also VCALENDAR. It starts with BEGIN:COMPONENTNAME and
8  * ends with END:COMPONENTNAME
9  *
10  * @package Sabre
11  * @subpackage VObject
12  * @copyright Copyright (C) 2007-2012 Rooftop Solutions. All rights reserved.
13  * @author Evert Pot (http://www.rooftopsolutions.nl/)
14  * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License
15  */
16 class Sabre_VObject_Component extends Sabre_VObject_Element {
17
18     /**
19      * Name, for example VEVENT
20      *
21      * @var string
22      */
23     public $name;
24
25     /**
26      * Children properties and components
27      *
28      * @var array
29      */
30     public $children = array();
31
32     /**
33      * If components are added to this map, they will be automatically mapped
34      * to their respective classes, if parsed by the reader or constructed with
35      * the 'create' method.
36      *
37      * @var array
38      */
39     static public $classMap = array(
40         'VCALENDAR'     => 'Sabre_VObject_Component_VCalendar',
41         'VEVENT'        => 'Sabre_VObject_Component_VEvent',
42         'VTODO'         => 'Sabre_VObject_Component_VTodo',
43         'VJOURNAL'      => 'Sabre_VObject_Component_VJournal',
44         'VALARM'        => 'Sabre_VObject_Component_VAlarm',
45     );
46
47     /**
48      * Creates the new component by name, but in addition will also see if
49      * there's a class mapped to the property name.
50      *
51      * @param string $name
52      * @param string $value
53      * @return Sabre_VObject_Component
54      */
55     static public function create($name, $value = null) {
56
57         $name = strtoupper($name);
58
59         if (isset(self::$classMap[$name])) {
60             return new self::$classMap[$name]($name, $value);
61         } else {
62             return new self($name, $value);
63         }
64
65     }
66
67     /**
68      * Creates a new component.
69      *
70      * By default this object will iterate over its own children, but this can
71      * be overridden with the iterator argument
72      *
73      * @param string $name
74      * @param Sabre_VObject_ElementList $iterator
75      */
76     public function __construct($name, Sabre_VObject_ElementList $iterator = null) {
77
78         $this->name = strtoupper($name);
79         if (!is_null($iterator)) $this->iterator = $iterator;
80
81     }
82
83     /**
84      * Turns the object back into a serialized blob.
85      *
86      * @return string
87      */
88     public function serialize() {
89
90         $str = "BEGIN:" . $this->name . "\r\n";
91
92         /**
93          * Gives a component a 'score' for sorting purposes.
94          *
95          * This is solely used by the childrenSort method.
96          *
97          * A higher score means the item will be lower in the list.
98          * To avoid score collisions, each "score category" has a reasonable
99          * space to accomodate elements. The $key is added to the $score to
100          * preserve the original relative order of elements.
101          *
102          * @param int $key
103          * @param Sabre_VObject $array
104          * @return int
105          */
106         $sortScore = function($key, $array) {
107             
108             if ($array[$key] instanceof Sabre_VObject_Component) {
109                 // We want to encode VTIMEZONE first, this is a personal
110                 // preference.
111                 if ($array[$key]->name === 'VTIMEZONE') {
112                     $score=300000000;
113                     return $score+$key;
114                 } else {
115                     $score=400000000;
116                     return $score+$key;
117                 }
118             } else {
119                 // Properties get encoded first
120                 // VCARD version 4.0 wants the VERSION property to appear first
121                 if ($array[$key] instanceof Sabre_VObject_Property) {
122                     if ($array[$key]->name === 'VERSION') {
123                         $score=100000000;
124                         return $score+$key;
125                     } else {
126                         // All other properties
127                         $score=200000000;
128                         return $score+$key;
129                     }
130                 }
131             }
132             next($children);
133
134         };
135
136         $tmp = $this->children;
137         uksort($this->children, function($a, $b) use ($sortScore, $tmp) {
138
139             $sA = $sortScore($a, $tmp);
140             $sB = $sortScore($b, $tmp);
141
142             if ($sA === $sB) return 0;
143
144             return ($sA < $sB) ? -1 : 1;
145
146         });
147
148         foreach($this->children as $child) $str.=$child->serialize();
149         $str.= "END:" . $this->name . "\r\n";
150
151         return $str;
152
153     }
154
155     /**
156      * Adds a new component or element
157      *
158      * You can call this method with the following syntaxes:
159      *
160      * add(Sabre_VObject_Element $element)
161      * add(string $name, $value)
162      *
163      * The first version adds an Element
164      * The second adds a property as a string.
165      *
166      * @param mixed $item
167      * @param mixed $itemValue
168      * @return void
169      */
170     public function add($item, $itemValue = null) {
171
172         if ($item instanceof Sabre_VObject_Element) {
173             if (!is_null($itemValue)) {
174                 throw new InvalidArgumentException('The second argument must not be specified, when passing a VObject');
175             }
176             $item->parent = $this;
177             $this->children[] = $item;
178         } elseif(is_string($item)) {
179
180             if (!is_scalar($itemValue)) {
181                 throw new InvalidArgumentException('The second argument must be scalar');
182             }
183             $item = Sabre_VObject_Property::create($item,$itemValue);
184             $item->parent = $this;
185             $this->children[] = $item;
186
187         } else {
188
189             throw new InvalidArgumentException('The first argument must either be a Sabre_VObject_Element or a string');
190
191         }
192
193     }
194
195     /**
196      * Returns an iterable list of children
197      *
198      * @return Sabre_VObject_ElementList
199      */
200     public function children() {
201
202         return new Sabre_VObject_ElementList($this->children);
203
204     }
205
206     /**
207      * Returns an array with elements that match the specified name.
208      *
209      * This function is also aware of MIME-Directory groups (as they appear in
210      * vcards). This means that if a property is grouped as "HOME.EMAIL", it
211      * will also be returned when searching for just "EMAIL". If you want to
212      * search for a property in a specific group, you can select on the entire
213      * string ("HOME.EMAIL"). If you want to search on a specific property that
214      * has not been assigned a group, specify ".EMAIL".
215      *
216      * Keys are retained from the 'children' array, which may be confusing in
217      * certain cases.
218      *
219      * @param string $name
220      * @return array
221      */
222     public function select($name) {
223
224         $group = null;
225         $name = strtoupper($name);
226         if (strpos($name,'.')!==false) {
227             list($group,$name) = explode('.', $name, 2);
228         }
229
230         $result = array();
231         foreach($this->children as $key=>$child) {
232
233             if (
234                 strtoupper($child->name) === $name &&
235                 (is_null($group) || ( $child instanceof Sabre_VObject_Property && strtoupper($child->group) === $group))
236             ) {
237
238                 $result[$key] = $child;
239
240             }
241         }
242
243         reset($result);
244         return $result;
245
246     }
247
248     /**
249      * This method only returns a list of sub-components. Properties are
250      * ignored.
251      *
252      * @return array
253      */
254     public function getComponents() {
255
256         $result = array();
257         foreach($this->children as $child) {
258             if ($child instanceof Sabre_VObject_Component) {
259                 $result[] = $child;
260             }
261         }
262
263         return $result;
264
265     }
266
267     /* Magic property accessors {{{ */
268
269     /**
270      * Using 'get' you will either get a property or component,
271      *
272      * If there were no child-elements found with the specified name,
273      * null is returned.
274      *
275      * @param string $name
276      * @return Sabre_VObject_Property
277      */
278     public function __get($name) {
279
280         $matches = $this->select($name);
281         if (count($matches)===0) {
282             return null;
283         } else {
284             $firstMatch = current($matches);
285             /** @var $firstMatch Sabre_VObject_Property */
286             $firstMatch->setIterator(new Sabre_VObject_ElementList(array_values($matches)));
287             return $firstMatch;
288         }
289
290     }
291
292     /**
293      * This method checks if a sub-element with the specified name exists.
294      *
295      * @param string $name
296      * @return bool
297      */
298     public function __isset($name) {
299
300         $matches = $this->select($name);
301         return count($matches)>0;
302
303     }
304
305     /**
306      * Using the setter method you can add properties or subcomponents
307      *
308      * You can either pass a Sabre_VObject_Component, Sabre_VObject_Property
309      * object, or a string to automatically create a Property.
310      *
311      * If the item already exists, it will be removed. If you want to add
312      * a new item with the same name, always use the add() method.
313      *
314      * @param string $name
315      * @param mixed $value
316      * @return void
317      */
318     public function __set($name, $value) {
319
320         $matches = $this->select($name);
321         $overWrite = count($matches)?key($matches):null;
322
323         if ($value instanceof Sabre_VObject_Component || $value instanceof Sabre_VObject_Property) {
324             $value->parent = $this;
325             if (!is_null($overWrite)) {
326                 $this->children[$overWrite] = $value;
327             } else {
328                 $this->children[] = $value;
329             }
330         } elseif (is_scalar($value)) {
331             $property = Sabre_VObject_Property::create($name,$value);
332             $property->parent = $this;
333             if (!is_null($overWrite)) {
334                 $this->children[$overWrite] = $property;
335             } else {
336                 $this->children[] = $property;
337             }
338         } else {
339             throw new InvalidArgumentException('You must pass a Sabre_VObject_Component, Sabre_VObject_Property or scalar type');
340         }
341
342     }
343
344     /**
345      * Removes all properties and components within this component.
346      *
347      * @param string $name
348      * @return void
349      */
350     public function __unset($name) {
351
352         $matches = $this->select($name);
353         foreach($matches as $k=>$child) {
354
355             unset($this->children[$k]);
356             $child->parent = null;
357
358         }
359
360     }
361
362     /* }}} */
363
364     /**
365      * This method is automatically called when the object is cloned.
366      * Specifically, this will ensure all child elements are also cloned.
367      *
368      * @return void
369      */
370     public function __clone() {
371
372         foreach($this->children as $key=>$child) {
373             $this->children[$key] = clone $child;
374             $this->children[$key]->parent = $this;
375         }
376
377     }
378
379 }