source: pmb4.2/trunk/fuentes/pmb/admin/connecteurs/out/webdav/vendor/sabre/vobject/lib/Sabre/VObject/Component.php @ 815

Last change on this file since 815 was 815, checked in by jrpelegrina, 4 years ago

Initial release of pmb 4.2

  • Property svn:executable set to *
File size: 11.1 KB
Line 
1<?php
2
3namespace Sabre\VObject;
4
5/**
6 * VObject Component
7 *
8 * This class represents a VCALENDAR/VCARD component. A component is for example
9 * VEVENT, VTODO and also VCALENDAR. It starts with BEGIN:COMPONENTNAME and
10 * ends with END:COMPONENTNAME
11 *
12 * @copyright Copyright (C) 2007-2013 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 */
16class Component extends Node {
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        'VALARM'        => 'Sabre\\VObject\\Component\\VAlarm',
41        'VCALENDAR'     => 'Sabre\\VObject\\Component\\VCalendar',
42        'VCARD'         => 'Sabre\\VObject\\Component\\VCard',
43        'VEVENT'        => 'Sabre\\VObject\\Component\\VEvent',
44        'VJOURNAL'      => 'Sabre\\VObject\\Component\\VJournal',
45        'VTODO'         => 'Sabre\\VObject\\Component\\VTodo',
46        'VFREEBUSY'     => 'Sabre\\VObject\\Component\\VFreeBusy',
47    );
48
49    /**
50     * Creates the new component by name, but in addition will also see if
51     * there's a class mapped to the property name.
52     *
53     * @param string $name
54     * @param string $value
55     * @return Component
56     */
57    static public function create($name, $value = null) {
58
59        $name = strtoupper($name);
60
61        if (isset(self::$classMap[$name])) {
62            return new self::$classMap[$name]($name, $value);
63        } else {
64            return new self($name, $value);
65        }
66
67    }
68
69    /**
70     * Creates a new component.
71     *
72     * By default this object will iterate over its own children, but this can
73     * be overridden with the iterator argument
74     *
75     * @param string $name
76     * @param ElementList $iterator
77     */
78    public function __construct($name, ElementList $iterator = null) {
79
80        $this->name = strtoupper($name);
81        if (!is_null($iterator)) $this->iterator = $iterator;
82
83    }
84
85    /**
86     * Turns the object back into a serialized blob.
87     *
88     * @return string
89     */
90    public function serialize() {
91
92        $str = "BEGIN:" . $this->name . "\r\n";
93
94        /**
95         * Gives a component a 'score' for sorting purposes.
96         *
97         * This is solely used by the childrenSort method.
98         *
99         * A higher score means the item will be lower in the list.
100         * To avoid score collisions, each "score category" has a reasonable
101         * space to accomodate elements. The $key is added to the $score to
102         * preserve the original relative order of elements.
103         *
104         * @param int $key
105         * @param array $array
106         * @return int
107         */
108        $sortScore = function($key, $array) {
109
110            if ($array[$key] instanceof Component) {
111
112                // We want to encode VTIMEZONE first, this is a personal
113                // preference.
114                if ($array[$key]->name === 'VTIMEZONE') {
115                    $score=300000000;
116                    return $score+$key;
117                } else {
118                    $score=400000000;
119                    return $score+$key;
120                }
121            } else {
122                // Properties get encoded first
123                // VCARD version 4.0 wants the VERSION property to appear first
124                if ($array[$key] instanceof Property) {
125                    if ($array[$key]->name === 'VERSION') {
126                        $score=100000000;
127                        return $score+$key;
128                    } else {
129                        // All other properties
130                        $score=200000000;
131                        return $score+$key;
132                    }
133                }
134            }
135
136        };
137
138        $tmp = $this->children;
139        uksort($this->children, function($a, $b) use ($sortScore, $tmp) {
140
141            $sA = $sortScore($a, $tmp);
142            $sB = $sortScore($b, $tmp);
143
144            if ($sA === $sB) return 0;
145
146            return ($sA < $sB) ? -1 : 1;
147
148        });
149
150        foreach($this->children as $child) $str.=$child->serialize();
151        $str.= "END:" . $this->name . "\r\n";
152
153        return $str;
154
155    }
156
157    /**
158     * Adds a new component or element
159     *
160     * You can call this method with the following syntaxes:
161     *
162     * add(Node $node)
163     * add(string $name, $value, array $parameters = array())
164     *
165     * The first version adds an Element
166     * The second adds a property as a string.
167     *
168     * @param mixed $item
169     * @param mixed $itemValue
170     * @return void
171     */
172    public function add($item, $itemValue = null, array $parameters = array()) {
173
174        if ($item instanceof Node) {
175            if (!is_null($itemValue)) {
176                throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject Node');
177            }
178            $item->parent = $this;
179            $this->children[] = $item;
180        } elseif(is_string($item)) {
181
182            $item = Property::create($item,$itemValue, $parameters);
183            $item->parent = $this;
184            $this->children[] = $item;
185
186        } else {
187
188            throw new \InvalidArgumentException('The first argument must either be a \\Sabre\\VObject\\Node or a string');
189
190        }
191
192    }
193
194    /**
195     * Returns an iterable list of children
196     *
197     * @return ElementList
198     */
199    public function children() {
200
201        return new ElementList($this->children);
202
203    }
204
205    /**
206     * Returns an array with elements that match the specified name.
207     *
208     * This function is also aware of MIME-Directory groups (as they appear in
209     * vcards). This means that if a property is grouped as "HOME.EMAIL", it
210     * will also be returned when searching for just "EMAIL". If you want to
211     * search for a property in a specific group, you can select on the entire
212     * string ("HOME.EMAIL"). If you want to search on a specific property that
213     * has not been assigned a group, specify ".EMAIL".
214     *
215     * Keys are retained from the 'children' array, which may be confusing in
216     * certain cases.
217     *
218     * @param string $name
219     * @return array
220     */
221    public function select($name) {
222
223        $group = null;
224        $name = strtoupper($name);
225        if (strpos($name,'.')!==false) {
226            list($group,$name) = explode('.', $name, 2);
227        }
228
229        $result = array();
230        foreach($this->children as $key=>$child) {
231
232            if (
233                strtoupper($child->name) === $name &&
234                (is_null($group) || ( $child instanceof Property && strtoupper($child->group) === $group))
235            ) {
236
237                $result[$key] = $child;
238
239            }
240        }
241
242        reset($result);
243        return $result;
244
245    }
246
247    /**
248     * This method only returns a list of sub-components. Properties are
249     * ignored.
250     *
251     * @return array
252     */
253    public function getComponents() {
254
255        $result = array();
256        foreach($this->children as $child) {
257            if ($child instanceof Component) {
258                $result[] = $child;
259            }
260        }
261
262        return $result;
263
264    }
265
266    /**
267     * Validates the node for correctness.
268     *
269     * The following options are supported:
270     *   - Node::REPAIR - If something is broken, and automatic repair may
271     *                    be attempted.
272     *
273     * An array is returned with warnings.
274     *
275     * Every item in the array has the following properties:
276     *    * level - (number between 1 and 3 with severity information)
277     *    * message - (human readable message)
278     *    * node - (reference to the offending node)
279     *
280     * @param int $options
281     * @return array
282     */
283    public function validate($options = 0) {
284
285        $result = array();
286        foreach($this->children as $child) {
287            $result = array_merge($result, $child->validate($options));
288        }
289        return $result;
290
291    }
292
293    /* Magic property accessors {{{ */
294
295    /**
296     * Using 'get' you will either get a property or component,
297     *
298     * If there were no child-elements found with the specified name,
299     * null is returned.
300     *
301     * @param string $name
302     * @return Property
303     */
304    public function __get($name) {
305
306        $matches = $this->select($name);
307        if (count($matches)===0) {
308            return null;
309        } else {
310            $firstMatch = current($matches);
311            /** @var $firstMatch Property */
312            $firstMatch->setIterator(new ElementList(array_values($matches)));
313            return $firstMatch;
314        }
315
316    }
317
318    /**
319     * This method checks if a sub-element with the specified name exists.
320     *
321     * @param string $name
322     * @return bool
323     */
324    public function __isset($name) {
325
326        $matches = $this->select($name);
327        return count($matches)>0;
328
329    }
330
331    /**
332     * Using the setter method you can add properties or subcomponents
333     *
334     * You can either pass a Component, Property
335     * object, or a string to automatically create a Property.
336     *
337     * If the item already exists, it will be removed. If you want to add
338     * a new item with the same name, always use the add() method.
339     *
340     * @param string $name
341     * @param mixed $value
342     * @return void
343     */
344    public function __set($name, $value) {
345
346        $matches = $this->select($name);
347        $overWrite = count($matches)?key($matches):null;
348
349        if ($value instanceof Component || $value instanceof Property) {
350            $value->parent = $this;
351            if (!is_null($overWrite)) {
352                $this->children[$overWrite] = $value;
353            } else {
354                $this->children[] = $value;
355            }
356        } elseif (is_scalar($value)) {
357            $property = Property::create($name,$value);
358            $property->parent = $this;
359            if (!is_null($overWrite)) {
360                $this->children[$overWrite] = $property;
361            } else {
362                $this->children[] = $property;
363            }
364        } else {
365            throw new \InvalidArgumentException('You must pass a \\Sabre\\VObject\\Component, \\Sabre\\VObject\\Property or scalar type');
366        }
367
368    }
369
370    /**
371     * Removes all properties and components within this component.
372     *
373     * @param string $name
374     * @return void
375     */
376    public function __unset($name) {
377
378        $matches = $this->select($name);
379        foreach($matches as $k=>$child) {
380
381            unset($this->children[$k]);
382            $child->parent = null;
383
384        }
385
386    }
387
388    /* }}} */
389
390    /**
391     * This method is automatically called when the object is cloned.
392     * Specifically, this will ensure all child elements are also cloned.
393     *
394     * @return void
395     */
396    public function __clone() {
397
398        foreach($this->children as $key=>$child) {
399            $this->children[$key] = clone $child;
400            $this->children[$key]->parent = $this;
401        }
402
403    }
404
405}
Note: See TracBrowser for help on using the repository browser.