]> git.mxchange.org Git - friendica-addons.git/blob - dav/SabreDAV/lib/Sabre/VObject/Component.php
Initial Release of the calendar plugin
[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 coponents 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 higher in the list
98          *
99          * @param Sabre_VObject_Node $n
100          * @return int
101          */
102         $sortScore = function($n) {
103
104             if ($n instanceof Sabre_VObject_Component) {
105                 // We want to encode VTIMEZONE first, this is a personal
106                 // preference.
107                 if ($n->name === 'VTIMEZONE') {
108                     return 1;
109                 } else {
110                     return 0;
111                 }
112             } else {
113                 // VCARD version 4.0 wants the VERSION property to appear first
114                 if ($n->name === 'VERSION') {
115                     return 3;
116                 } else {
117                     return 2;
118                 }
119             }
120
121         };
122
123         usort($this->children, function($a, $b) use ($sortScore) {
124
125             $sA = $sortScore($a);
126             $sB = $sortScore($b);
127
128             if ($sA === $sB) return 0;
129
130             return ($sA > $sB) ? -1 : 1;
131
132         });
133
134         foreach($this->children as $child) $str.=$child->serialize();
135         $str.= "END:" . $this->name . "\r\n";
136
137         return $str;
138
139     }
140
141     /**
142      * Adds a new component or element
143      *
144      * You can call this method with the following syntaxes:
145      *
146      * add(Sabre_VObject_Element $element)
147      * add(string $name, $value)
148      *
149      * The first version adds an Element
150      * The second adds a property as a string.
151      *
152      * @param mixed $item
153      * @param mixed $itemValue
154      * @return void
155      */
156     public function add($item, $itemValue = null) {
157
158         if ($item instanceof Sabre_VObject_Element) {
159             if (!is_null($itemValue)) {
160                 throw new InvalidArgumentException('The second argument must not be specified, when passing a VObject');
161             }
162             $item->parent = $this;
163             $this->children[] = $item;
164         } elseif(is_string($item)) {
165
166             if (!is_scalar($itemValue)) {
167                 throw new InvalidArgumentException('The second argument must be scalar');
168             }
169             $item = Sabre_VObject_Property::create($item,$itemValue);
170             $item->parent = $this;
171             $this->children[] = $item;
172
173         } else {
174
175             throw new InvalidArgumentException('The first argument must either be a Sabre_VObject_Element or a string');
176
177         }
178
179     }
180
181     /**
182      * Returns an iterable list of children
183      *
184      * @return Sabre_VObject_ElementList
185      */
186     public function children() {
187
188         return new Sabre_VObject_ElementList($this->children);
189
190     }
191
192     /**
193      * Returns an array with elements that match the specified name.
194      *
195      * This function is also aware of MIME-Directory groups (as they appear in
196      * vcards). This means that if a property is grouped as "HOME.EMAIL", it
197      * will also be returned when searching for just "EMAIL". If you want to
198      * search for a property in a specific group, you can select on the entire
199      * string ("HOME.EMAIL"). If you want to search on a specific property that
200      * has not been assigned a group, specify ".EMAIL".
201      *
202      * Keys are retained from the 'children' array, which may be confusing in
203      * certain cases.
204      *
205      * @param string $name
206      * @return array
207      */
208     public function select($name) {
209
210         $group = null;
211         $name = strtoupper($name);
212         if (strpos($name,'.')!==false) {
213             list($group,$name) = explode('.', $name, 2);
214         }
215
216         $result = array();
217         foreach($this->children as $key=>$child) {
218
219             if (
220                 strtoupper($child->name) === $name &&
221                 (is_null($group) || ( $child instanceof Sabre_VObject_Property && strtoupper($child->group) === $group))
222             ) {
223
224                 $result[$key] = $child;
225
226             }
227         }
228
229         reset($result);
230         return $result;
231
232     }
233
234     /**
235      * This method only returns a list of sub-components. Properties are
236      * ignored.
237      *
238      * @return array
239      */
240     public function getComponents() {
241
242         $result = array();
243         foreach($this->children as $child) {
244             if ($child instanceof Sabre_VObject_Component) {
245                 $result[] = $child;
246             }
247         }
248
249         return $result;
250
251     }
252
253     /* Magic property accessors {{{ */
254
255     /**
256      * Using 'get' you will either get a property or component,
257      *
258      * If there were no child-elements found with the specified name,
259      * null is returned.
260      *
261      * @param string $name
262      * @return Sabre_VObject_Property
263      */
264     public function __get($name) {
265
266         $matches = $this->select($name);
267         if (count($matches)===0) {
268             return null;
269         } else {
270             $firstMatch = current($matches);
271             /** @var $firstMatch Sabre_VObject_Property */
272             $firstMatch->setIterator(new Sabre_VObject_ElementList(array_values($matches)));
273             return $firstMatch;
274         }
275
276     }
277
278     /**
279      * This method checks if a sub-element with the specified name exists.
280      *
281      * @param string $name
282      * @return bool
283      */
284     public function __isset($name) {
285
286         $matches = $this->select($name);
287         return count($matches)>0;
288
289     }
290
291     /**
292      * Using the setter method you can add properties or subcomponents
293      *
294      * You can either pass a Sabre_VObject_Component, Sabre_VObject_Property
295      * object, or a string to automatically create a Property.
296      *
297      * If the item already exists, it will be removed. If you want to add
298      * a new item with the same name, always use the add() method.
299      *
300      * @param string $name
301      * @param mixed $value
302      * @return void
303      */
304     public function __set($name, $value) {
305
306         $matches = $this->select($name);
307         $overWrite = count($matches)?key($matches):null;
308
309         if ($value instanceof Sabre_VObject_Component || $value instanceof Sabre_VObject_Property) {
310             $value->parent = $this;
311             if (!is_null($overWrite)) {
312                 $this->children[$overWrite] = $value;
313             } else {
314                 $this->children[] = $value;
315             }
316         } elseif (is_scalar($value)) {
317             $property = Sabre_VObject_Property::create($name,$value);
318             $property->parent = $this;
319             if (!is_null($overWrite)) {
320                 $this->children[$overWrite] = $property;
321             } else {
322                 $this->children[] = $property;
323             }
324         } else {
325             throw new InvalidArgumentException('You must pass a Sabre_VObject_Component, Sabre_VObject_Property or scalar type');
326         }
327
328     }
329
330     /**
331      * Removes all properties and components within this component.
332      *
333      * @param string $name
334      * @return void
335      */
336     public function __unset($name) {
337
338         $matches = $this->select($name);
339         foreach($matches as $k=>$child) {
340
341             unset($this->children[$k]);
342             $child->parent = null;
343
344         }
345
346     }
347
348     /* }}} */
349
350     /**
351      * This method is automatically called when the object is cloned.
352      * Specifically, this will ensure all child elements are also cloned.
353      *
354      * @return void
355      */
356     public function __clone() {
357
358         foreach($this->children as $key=>$child) {
359             $this->children[$key] = clone $child;
360             $this->children[$key]->parent = $this;
361         }
362
363     }
364
365 }