xref: /plugin/davcal/vendor/sabre/vobject/lib/Document.php (revision a1a3b6794e0e143a4a8b51d3185ce2d339be61ab)
1*a1a3b679SAndreas Boehler<?php
2*a1a3b679SAndreas Boehler
3*a1a3b679SAndreas Boehlernamespace Sabre\VObject;
4*a1a3b679SAndreas Boehler
5*a1a3b679SAndreas Boehler/**
6*a1a3b679SAndreas Boehler * Document
7*a1a3b679SAndreas Boehler *
8*a1a3b679SAndreas Boehler * A document is just like a component, except that it's also the top level
9*a1a3b679SAndreas Boehler * element.
10*a1a3b679SAndreas Boehler *
11*a1a3b679SAndreas Boehler * Both a VCALENDAR and a VCARD are considered documents.
12*a1a3b679SAndreas Boehler *
13*a1a3b679SAndreas Boehler * This class also provides a registry for document types.
14*a1a3b679SAndreas Boehler *
15*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).
16*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/)
17*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License
18*a1a3b679SAndreas Boehler */
19*a1a3b679SAndreas Boehlerabstract class Document extends Component {
20*a1a3b679SAndreas Boehler
21*a1a3b679SAndreas Boehler    /**
22*a1a3b679SAndreas Boehler     * Unknown document type
23*a1a3b679SAndreas Boehler     */
24*a1a3b679SAndreas Boehler    const UNKNOWN = 1;
25*a1a3b679SAndreas Boehler
26*a1a3b679SAndreas Boehler    /**
27*a1a3b679SAndreas Boehler     * vCalendar 1.0
28*a1a3b679SAndreas Boehler     */
29*a1a3b679SAndreas Boehler    const VCALENDAR10 = 2;
30*a1a3b679SAndreas Boehler
31*a1a3b679SAndreas Boehler    /**
32*a1a3b679SAndreas Boehler     * iCalendar 2.0
33*a1a3b679SAndreas Boehler     */
34*a1a3b679SAndreas Boehler    const ICALENDAR20 = 3;
35*a1a3b679SAndreas Boehler
36*a1a3b679SAndreas Boehler    /**
37*a1a3b679SAndreas Boehler     * vCard 2.1
38*a1a3b679SAndreas Boehler     */
39*a1a3b679SAndreas Boehler    const VCARD21 = 4;
40*a1a3b679SAndreas Boehler
41*a1a3b679SAndreas Boehler    /**
42*a1a3b679SAndreas Boehler     * vCard 3.0
43*a1a3b679SAndreas Boehler     */
44*a1a3b679SAndreas Boehler    const VCARD30 = 5;
45*a1a3b679SAndreas Boehler
46*a1a3b679SAndreas Boehler    /**
47*a1a3b679SAndreas Boehler     * vCard 4.0
48*a1a3b679SAndreas Boehler     */
49*a1a3b679SAndreas Boehler    const VCARD40 = 6;
50*a1a3b679SAndreas Boehler
51*a1a3b679SAndreas Boehler    /**
52*a1a3b679SAndreas Boehler     * The default name for this component.
53*a1a3b679SAndreas Boehler     *
54*a1a3b679SAndreas Boehler     * This should be 'VCALENDAR' or 'VCARD'.
55*a1a3b679SAndreas Boehler     *
56*a1a3b679SAndreas Boehler     * @var string
57*a1a3b679SAndreas Boehler     */
58*a1a3b679SAndreas Boehler    static public $defaultName;
59*a1a3b679SAndreas Boehler
60*a1a3b679SAndreas Boehler    /**
61*a1a3b679SAndreas Boehler     * List of properties, and which classes they map to.
62*a1a3b679SAndreas Boehler     *
63*a1a3b679SAndreas Boehler     * @var array
64*a1a3b679SAndreas Boehler     */
65*a1a3b679SAndreas Boehler    static public $propertyMap = array();
66*a1a3b679SAndreas Boehler
67*a1a3b679SAndreas Boehler    /**
68*a1a3b679SAndreas Boehler     * List of components, along with which classes they map to.
69*a1a3b679SAndreas Boehler     *
70*a1a3b679SAndreas Boehler     * @var array
71*a1a3b679SAndreas Boehler     */
72*a1a3b679SAndreas Boehler    static public $componentMap = array();
73*a1a3b679SAndreas Boehler
74*a1a3b679SAndreas Boehler    /**
75*a1a3b679SAndreas Boehler     * List of value-types, and which classes they map to.
76*a1a3b679SAndreas Boehler     *
77*a1a3b679SAndreas Boehler     * @var array
78*a1a3b679SAndreas Boehler     */
79*a1a3b679SAndreas Boehler    static public $valueMap = array();
80*a1a3b679SAndreas Boehler
81*a1a3b679SAndreas Boehler    /**
82*a1a3b679SAndreas Boehler     * Creates a new document.
83*a1a3b679SAndreas Boehler     *
84*a1a3b679SAndreas Boehler     * We're changing the default behavior slightly here. First, we don't want
85*a1a3b679SAndreas Boehler     * to have to specify a name (we already know it), and we want to allow
86*a1a3b679SAndreas Boehler     * children to be specified in the first argument.
87*a1a3b679SAndreas Boehler     *
88*a1a3b679SAndreas Boehler     * But, the default behavior also works.
89*a1a3b679SAndreas Boehler     *
90*a1a3b679SAndreas Boehler     * So the two sigs:
91*a1a3b679SAndreas Boehler     *
92*a1a3b679SAndreas Boehler     * new Document(array $children = array(), $defaults = true);
93*a1a3b679SAndreas Boehler     * new Document(string $name, array $children = array(), $defaults = true)
94*a1a3b679SAndreas Boehler     *
95*a1a3b679SAndreas Boehler     * @return void
96*a1a3b679SAndreas Boehler     */
97*a1a3b679SAndreas Boehler    public function __construct() {
98*a1a3b679SAndreas Boehler
99*a1a3b679SAndreas Boehler        $args = func_get_args();
100*a1a3b679SAndreas Boehler        if (count($args)===0 || is_array($args[0])) {
101*a1a3b679SAndreas Boehler            array_unshift($args, $this, static::$defaultName);
102*a1a3b679SAndreas Boehler            call_user_func_array(array('parent', '__construct'), $args);
103*a1a3b679SAndreas Boehler        } else {
104*a1a3b679SAndreas Boehler            array_unshift($args, $this);
105*a1a3b679SAndreas Boehler            call_user_func_array(array('parent', '__construct'), $args);
106*a1a3b679SAndreas Boehler        }
107*a1a3b679SAndreas Boehler
108*a1a3b679SAndreas Boehler    }
109*a1a3b679SAndreas Boehler
110*a1a3b679SAndreas Boehler    /**
111*a1a3b679SAndreas Boehler     * Returns the current document type.
112*a1a3b679SAndreas Boehler     *
113*a1a3b679SAndreas Boehler     * @return void
114*a1a3b679SAndreas Boehler     */
115*a1a3b679SAndreas Boehler    public function getDocumentType() {
116*a1a3b679SAndreas Boehler
117*a1a3b679SAndreas Boehler        return self::UNKNOWN;
118*a1a3b679SAndreas Boehler
119*a1a3b679SAndreas Boehler    }
120*a1a3b679SAndreas Boehler
121*a1a3b679SAndreas Boehler    /**
122*a1a3b679SAndreas Boehler     * Creates a new component or property.
123*a1a3b679SAndreas Boehler     *
124*a1a3b679SAndreas Boehler     * If it's a known component, we will automatically call createComponent.
125*a1a3b679SAndreas Boehler     * otherwise, we'll assume it's a property and call createProperty instead.
126*a1a3b679SAndreas Boehler     *
127*a1a3b679SAndreas Boehler     * @param string $name
128*a1a3b679SAndreas Boehler     * @param string $arg1,... Unlimited number of args
129*a1a3b679SAndreas Boehler     * @return mixed
130*a1a3b679SAndreas Boehler     */
131*a1a3b679SAndreas Boehler    public function create($name) {
132*a1a3b679SAndreas Boehler
133*a1a3b679SAndreas Boehler        if (isset(static::$componentMap[strtoupper($name)])) {
134*a1a3b679SAndreas Boehler
135*a1a3b679SAndreas Boehler            return call_user_func_array(array($this,'createComponent'), func_get_args());
136*a1a3b679SAndreas Boehler
137*a1a3b679SAndreas Boehler        } else {
138*a1a3b679SAndreas Boehler
139*a1a3b679SAndreas Boehler            return call_user_func_array(array($this,'createProperty'), func_get_args());
140*a1a3b679SAndreas Boehler
141*a1a3b679SAndreas Boehler        }
142*a1a3b679SAndreas Boehler
143*a1a3b679SAndreas Boehler    }
144*a1a3b679SAndreas Boehler
145*a1a3b679SAndreas Boehler    /**
146*a1a3b679SAndreas Boehler     * Creates a new component
147*a1a3b679SAndreas Boehler     *
148*a1a3b679SAndreas Boehler     * This method automatically searches for the correct component class, based
149*a1a3b679SAndreas Boehler     * on its name.
150*a1a3b679SAndreas Boehler     *
151*a1a3b679SAndreas Boehler     * You can specify the children either in key=>value syntax, in which case
152*a1a3b679SAndreas Boehler     * properties will automatically be created, or you can just pass a list of
153*a1a3b679SAndreas Boehler     * Component and Property object.
154*a1a3b679SAndreas Boehler     *
155*a1a3b679SAndreas Boehler     * By default, a set of sensible values will be added to the component. For
156*a1a3b679SAndreas Boehler     * an iCalendar object, this may be something like CALSCALE:GREGORIAN. To
157*a1a3b679SAndreas Boehler     * ensure that this does not happen, set $defaults to false.
158*a1a3b679SAndreas Boehler     *
159*a1a3b679SAndreas Boehler     * @param string $name
160*a1a3b679SAndreas Boehler     * @param array $children
161*a1a3b679SAndreas Boehler     * @param bool $defaults
162*a1a3b679SAndreas Boehler     * @return Component
163*a1a3b679SAndreas Boehler     */
164*a1a3b679SAndreas Boehler    public function createComponent($name, array $children = null, $defaults = true) {
165*a1a3b679SAndreas Boehler
166*a1a3b679SAndreas Boehler        $name = strtoupper($name);
167*a1a3b679SAndreas Boehler        $class = 'Sabre\\VObject\\Component';
168*a1a3b679SAndreas Boehler
169*a1a3b679SAndreas Boehler        if (isset(static::$componentMap[$name])) {
170*a1a3b679SAndreas Boehler            $class=static::$componentMap[$name];
171*a1a3b679SAndreas Boehler        }
172*a1a3b679SAndreas Boehler        if (is_null($children)) $children = array();
173*a1a3b679SAndreas Boehler        return new $class($this, $name, $children, $defaults);
174*a1a3b679SAndreas Boehler
175*a1a3b679SAndreas Boehler    }
176*a1a3b679SAndreas Boehler
177*a1a3b679SAndreas Boehler    /**
178*a1a3b679SAndreas Boehler     * Factory method for creating new properties
179*a1a3b679SAndreas Boehler     *
180*a1a3b679SAndreas Boehler     * This method automatically searches for the correct property class, based
181*a1a3b679SAndreas Boehler     * on its name.
182*a1a3b679SAndreas Boehler     *
183*a1a3b679SAndreas Boehler     * You can specify the parameters either in key=>value syntax, in which case
184*a1a3b679SAndreas Boehler     * parameters will automatically be created, or you can just pass a list of
185*a1a3b679SAndreas Boehler     * Parameter objects.
186*a1a3b679SAndreas Boehler     *
187*a1a3b679SAndreas Boehler     * @param string $name
188*a1a3b679SAndreas Boehler     * @param mixed $value
189*a1a3b679SAndreas Boehler     * @param array $parameters
190*a1a3b679SAndreas Boehler     * @param string $valueType Force a specific valuetype, such as URI or TEXT
191*a1a3b679SAndreas Boehler     * @return Property
192*a1a3b679SAndreas Boehler     */
193*a1a3b679SAndreas Boehler    public function createProperty($name, $value = null, array $parameters = null, $valueType = null) {
194*a1a3b679SAndreas Boehler
195*a1a3b679SAndreas Boehler        // If there's a . in the name, it means it's prefixed by a groupname.
196*a1a3b679SAndreas Boehler        if (($i=strpos($name,'.'))!==false) {
197*a1a3b679SAndreas Boehler            $group = substr($name, 0, $i);
198*a1a3b679SAndreas Boehler            $name = strtoupper(substr($name, $i+1));
199*a1a3b679SAndreas Boehler        } else {
200*a1a3b679SAndreas Boehler            $name = strtoupper($name);
201*a1a3b679SAndreas Boehler            $group = null;
202*a1a3b679SAndreas Boehler        }
203*a1a3b679SAndreas Boehler
204*a1a3b679SAndreas Boehler        $class = null;
205*a1a3b679SAndreas Boehler
206*a1a3b679SAndreas Boehler        if ($valueType) {
207*a1a3b679SAndreas Boehler            // The valueType argument comes first to figure out the correct
208*a1a3b679SAndreas Boehler            // class.
209*a1a3b679SAndreas Boehler            $class = $this->getClassNameForPropertyValue($valueType);
210*a1a3b679SAndreas Boehler        }
211*a1a3b679SAndreas Boehler
212*a1a3b679SAndreas Boehler        if (is_null($class) && isset($parameters['VALUE'])) {
213*a1a3b679SAndreas Boehler            // If a VALUE parameter is supplied, we should use that.
214*a1a3b679SAndreas Boehler            $class = $this->getClassNameForPropertyValue($parameters['VALUE']);
215*a1a3b679SAndreas Boehler        }
216*a1a3b679SAndreas Boehler        if (is_null($class)) {
217*a1a3b679SAndreas Boehler            $class = $this->getClassNameForPropertyName($name);
218*a1a3b679SAndreas Boehler        }
219*a1a3b679SAndreas Boehler        if (is_null($parameters)) $parameters = array();
220*a1a3b679SAndreas Boehler
221*a1a3b679SAndreas Boehler        return new $class($this, $name, $value, $parameters, $group);
222*a1a3b679SAndreas Boehler
223*a1a3b679SAndreas Boehler    }
224*a1a3b679SAndreas Boehler
225*a1a3b679SAndreas Boehler    /**
226*a1a3b679SAndreas Boehler     * This method returns a full class-name for a value parameter.
227*a1a3b679SAndreas Boehler     *
228*a1a3b679SAndreas Boehler     * For instance, DTSTART may have VALUE=DATE. In that case we will look in
229*a1a3b679SAndreas Boehler     * our valueMap table and return the appropriate class name.
230*a1a3b679SAndreas Boehler     *
231*a1a3b679SAndreas Boehler     * This method returns null if we don't have a specialized class.
232*a1a3b679SAndreas Boehler     *
233*a1a3b679SAndreas Boehler     * @param string $valueParam
234*a1a3b679SAndreas Boehler     * @return void
235*a1a3b679SAndreas Boehler     */
236*a1a3b679SAndreas Boehler    public function getClassNameForPropertyValue($valueParam) {
237*a1a3b679SAndreas Boehler
238*a1a3b679SAndreas Boehler        $valueParam = strtoupper($valueParam);
239*a1a3b679SAndreas Boehler        if (isset(static::$valueMap[$valueParam])) {
240*a1a3b679SAndreas Boehler            return static::$valueMap[$valueParam];
241*a1a3b679SAndreas Boehler        }
242*a1a3b679SAndreas Boehler
243*a1a3b679SAndreas Boehler    }
244*a1a3b679SAndreas Boehler
245*a1a3b679SAndreas Boehler    /**
246*a1a3b679SAndreas Boehler     * Returns the default class for a property name.
247*a1a3b679SAndreas Boehler     *
248*a1a3b679SAndreas Boehler     * @param string $propertyName
249*a1a3b679SAndreas Boehler     * @return string
250*a1a3b679SAndreas Boehler     */
251*a1a3b679SAndreas Boehler    public function getClassNameForPropertyName($propertyName) {
252*a1a3b679SAndreas Boehler
253*a1a3b679SAndreas Boehler        if (isset(static::$propertyMap[$propertyName])) {
254*a1a3b679SAndreas Boehler            return static::$propertyMap[$propertyName];
255*a1a3b679SAndreas Boehler        } else {
256*a1a3b679SAndreas Boehler            return 'Sabre\\VObject\\Property\\Unknown';
257*a1a3b679SAndreas Boehler        }
258*a1a3b679SAndreas Boehler
259*a1a3b679SAndreas Boehler    }
260*a1a3b679SAndreas Boehler
261*a1a3b679SAndreas Boehler}
262