xref: /plugin/davcal/vendor/sabre/vobject/lib/Parameter.php (revision a1a3b6794e0e143a4a8b51d3185ce2d339be61ab)
1*a1a3b679SAndreas Boehler<?php
2*a1a3b679SAndreas Boehler
3*a1a3b679SAndreas Boehlernamespace Sabre\VObject;
4*a1a3b679SAndreas Boehler
5*a1a3b679SAndreas Boehleruse
6*a1a3b679SAndreas Boehler    ArrayObject;
7*a1a3b679SAndreas Boehler
8*a1a3b679SAndreas Boehler/**
9*a1a3b679SAndreas Boehler * VObject Parameter
10*a1a3b679SAndreas Boehler *
11*a1a3b679SAndreas Boehler * This class represents a parameter. A parameter is always tied to a property.
12*a1a3b679SAndreas Boehler * In the case of:
13*a1a3b679SAndreas Boehler *   DTSTART;VALUE=DATE:20101108
14*a1a3b679SAndreas Boehler * VALUE=DATE would be the parameter name and value.
15*a1a3b679SAndreas Boehler *
16*a1a3b679SAndreas Boehler * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).
17*a1a3b679SAndreas Boehler * @author Evert Pot (http://evertpot.com/)
18*a1a3b679SAndreas Boehler * @license http://sabre.io/license/ Modified BSD License
19*a1a3b679SAndreas Boehler */
20*a1a3b679SAndreas Boehlerclass Parameter extends Node {
21*a1a3b679SAndreas Boehler
22*a1a3b679SAndreas Boehler    /**
23*a1a3b679SAndreas Boehler     * Parameter name
24*a1a3b679SAndreas Boehler     *
25*a1a3b679SAndreas Boehler     * @var string
26*a1a3b679SAndreas Boehler     */
27*a1a3b679SAndreas Boehler    public $name;
28*a1a3b679SAndreas Boehler
29*a1a3b679SAndreas Boehler    /**
30*a1a3b679SAndreas Boehler     * vCard 2.1 allows parameters to be encoded without a name.
31*a1a3b679SAndreas Boehler     *
32*a1a3b679SAndreas Boehler     * We can deduce the parameter name based on it's value.
33*a1a3b679SAndreas Boehler     *
34*a1a3b679SAndreas Boehler     * @var bool
35*a1a3b679SAndreas Boehler     */
36*a1a3b679SAndreas Boehler    public $noName = false;
37*a1a3b679SAndreas Boehler
38*a1a3b679SAndreas Boehler    /**
39*a1a3b679SAndreas Boehler     * Parameter value
40*a1a3b679SAndreas Boehler     *
41*a1a3b679SAndreas Boehler     * @var string
42*a1a3b679SAndreas Boehler     */
43*a1a3b679SAndreas Boehler    protected $value;
44*a1a3b679SAndreas Boehler
45*a1a3b679SAndreas Boehler    /**
46*a1a3b679SAndreas Boehler     * Sets up the object.
47*a1a3b679SAndreas Boehler     *
48*a1a3b679SAndreas Boehler     * It's recommended to use the create:: factory method instead.
49*a1a3b679SAndreas Boehler     *
50*a1a3b679SAndreas Boehler     * @param string $name
51*a1a3b679SAndreas Boehler     * @param string $value
52*a1a3b679SAndreas Boehler     */
53*a1a3b679SAndreas Boehler    public function __construct(Document $root, $name, $value = null) {
54*a1a3b679SAndreas Boehler
55*a1a3b679SAndreas Boehler        $this->name = strtoupper($name);
56*a1a3b679SAndreas Boehler        $this->root = $root;
57*a1a3b679SAndreas Boehler        if (is_null($name)) {
58*a1a3b679SAndreas Boehler            $this->noName = true;
59*a1a3b679SAndreas Boehler            $this->name = static::guessParameterNameByValue($value);
60*a1a3b679SAndreas Boehler        }
61*a1a3b679SAndreas Boehler
62*a1a3b679SAndreas Boehler        // If guessParameterNameByValue() returns an empty string
63*a1a3b679SAndreas Boehler        // above, we're actually dealing with a parameter that has no value.
64*a1a3b679SAndreas Boehler        // In that case we have to move the value to the name.
65*a1a3b679SAndreas Boehler        if ($this->name === '') {
66*a1a3b679SAndreas Boehler            $this->noName = false;
67*a1a3b679SAndreas Boehler            $this->name = strtoupper($value);
68*a1a3b679SAndreas Boehler        } else {
69*a1a3b679SAndreas Boehler            $this->setValue($value);
70*a1a3b679SAndreas Boehler        }
71*a1a3b679SAndreas Boehler
72*a1a3b679SAndreas Boehler    }
73*a1a3b679SAndreas Boehler
74*a1a3b679SAndreas Boehler    /**
75*a1a3b679SAndreas Boehler     * Try to guess property name by value, can be used for vCard 2.1 nameless parameters.
76*a1a3b679SAndreas Boehler     *
77*a1a3b679SAndreas Boehler     * Figuring out what the name should have been. Note that a ton of
78*a1a3b679SAndreas Boehler     * these are rather silly in 2014 and would probably rarely be
79*a1a3b679SAndreas Boehler     * used, but we like to be complete.
80*a1a3b679SAndreas Boehler     *
81*a1a3b679SAndreas Boehler     * @param string $value
82*a1a3b679SAndreas Boehler     * @return string
83*a1a3b679SAndreas Boehler     */
84*a1a3b679SAndreas Boehler    public static function guessParameterNameByValue($value) {
85*a1a3b679SAndreas Boehler        switch(strtoupper($value)) {
86*a1a3b679SAndreas Boehler
87*a1a3b679SAndreas Boehler            // Encodings
88*a1a3b679SAndreas Boehler            case '7-BIT' :
89*a1a3b679SAndreas Boehler            case 'QUOTED-PRINTABLE' :
90*a1a3b679SAndreas Boehler            case 'BASE64' :
91*a1a3b679SAndreas Boehler                $name = 'ENCODING';
92*a1a3b679SAndreas Boehler                break;
93*a1a3b679SAndreas Boehler
94*a1a3b679SAndreas Boehler            // Common types
95*a1a3b679SAndreas Boehler            case 'WORK' :
96*a1a3b679SAndreas Boehler            case 'HOME' :
97*a1a3b679SAndreas Boehler            case 'PREF' :
98*a1a3b679SAndreas Boehler
99*a1a3b679SAndreas Boehler                // Delivery Label Type
100*a1a3b679SAndreas Boehler            case 'DOM' :
101*a1a3b679SAndreas Boehler            case 'INTL' :
102*a1a3b679SAndreas Boehler            case 'POSTAL' :
103*a1a3b679SAndreas Boehler            case 'PARCEL' :
104*a1a3b679SAndreas Boehler
105*a1a3b679SAndreas Boehler                // Telephone types
106*a1a3b679SAndreas Boehler            case 'VOICE' :
107*a1a3b679SAndreas Boehler            case 'FAX' :
108*a1a3b679SAndreas Boehler            case 'MSG' :
109*a1a3b679SAndreas Boehler            case 'CELL' :
110*a1a3b679SAndreas Boehler            case 'PAGER' :
111*a1a3b679SAndreas Boehler            case 'BBS' :
112*a1a3b679SAndreas Boehler            case 'MODEM' :
113*a1a3b679SAndreas Boehler            case 'CAR' :
114*a1a3b679SAndreas Boehler            case 'ISDN' :
115*a1a3b679SAndreas Boehler            case 'VIDEO' :
116*a1a3b679SAndreas Boehler
117*a1a3b679SAndreas Boehler                // EMAIL types (lol)
118*a1a3b679SAndreas Boehler            case 'AOL' :
119*a1a3b679SAndreas Boehler            case 'APPLELINK' :
120*a1a3b679SAndreas Boehler            case 'ATTMAIL' :
121*a1a3b679SAndreas Boehler            case 'CIS' :
122*a1a3b679SAndreas Boehler            case 'EWORLD' :
123*a1a3b679SAndreas Boehler            case 'INTERNET' :
124*a1a3b679SAndreas Boehler            case 'IBMMAIL' :
125*a1a3b679SAndreas Boehler            case 'MCIMAIL' :
126*a1a3b679SAndreas Boehler            case 'POWERSHARE' :
127*a1a3b679SAndreas Boehler            case 'PRODIGY' :
128*a1a3b679SAndreas Boehler            case 'TLX' :
129*a1a3b679SAndreas Boehler            case 'X400' :
130*a1a3b679SAndreas Boehler
131*a1a3b679SAndreas Boehler                // Photo / Logo format types
132*a1a3b679SAndreas Boehler            case 'GIF' :
133*a1a3b679SAndreas Boehler            case 'CGM' :
134*a1a3b679SAndreas Boehler            case 'WMF' :
135*a1a3b679SAndreas Boehler            case 'BMP' :
136*a1a3b679SAndreas Boehler            case 'DIB' :
137*a1a3b679SAndreas Boehler            case 'PICT' :
138*a1a3b679SAndreas Boehler            case 'TIFF' :
139*a1a3b679SAndreas Boehler            case 'PDF ':
140*a1a3b679SAndreas Boehler            case 'PS' :
141*a1a3b679SAndreas Boehler            case 'JPEG' :
142*a1a3b679SAndreas Boehler            case 'MPEG' :
143*a1a3b679SAndreas Boehler            case 'MPEG2' :
144*a1a3b679SAndreas Boehler            case 'AVI' :
145*a1a3b679SAndreas Boehler            case 'QTIME' :
146*a1a3b679SAndreas Boehler
147*a1a3b679SAndreas Boehler                // Sound Digital Audio Type
148*a1a3b679SAndreas Boehler            case 'WAVE' :
149*a1a3b679SAndreas Boehler            case 'PCM' :
150*a1a3b679SAndreas Boehler            case 'AIFF' :
151*a1a3b679SAndreas Boehler
152*a1a3b679SAndreas Boehler                // Key types
153*a1a3b679SAndreas Boehler            case 'X509' :
154*a1a3b679SAndreas Boehler            case 'PGP' :
155*a1a3b679SAndreas Boehler                $name = 'TYPE';
156*a1a3b679SAndreas Boehler                break;
157*a1a3b679SAndreas Boehler
158*a1a3b679SAndreas Boehler            // Value types
159*a1a3b679SAndreas Boehler            case 'INLINE' :
160*a1a3b679SAndreas Boehler            case 'URL' :
161*a1a3b679SAndreas Boehler            case 'CONTENT-ID' :
162*a1a3b679SAndreas Boehler            case 'CID' :
163*a1a3b679SAndreas Boehler                $name = 'VALUE';
164*a1a3b679SAndreas Boehler                break;
165*a1a3b679SAndreas Boehler
166*a1a3b679SAndreas Boehler            default:
167*a1a3b679SAndreas Boehler                $name = '';
168*a1a3b679SAndreas Boehler        }
169*a1a3b679SAndreas Boehler
170*a1a3b679SAndreas Boehler        return $name;
171*a1a3b679SAndreas Boehler    }
172*a1a3b679SAndreas Boehler
173*a1a3b679SAndreas Boehler    /**
174*a1a3b679SAndreas Boehler     * Updates the current value.
175*a1a3b679SAndreas Boehler     *
176*a1a3b679SAndreas Boehler     * This may be either a single, or multiple strings in an array.
177*a1a3b679SAndreas Boehler     *
178*a1a3b679SAndreas Boehler     * @param string|array $value
179*a1a3b679SAndreas Boehler     * @return void
180*a1a3b679SAndreas Boehler     */
181*a1a3b679SAndreas Boehler    public function setValue($value) {
182*a1a3b679SAndreas Boehler
183*a1a3b679SAndreas Boehler        $this->value = $value;
184*a1a3b679SAndreas Boehler
185*a1a3b679SAndreas Boehler    }
186*a1a3b679SAndreas Boehler
187*a1a3b679SAndreas Boehler    /**
188*a1a3b679SAndreas Boehler     * Returns the current value
189*a1a3b679SAndreas Boehler     *
190*a1a3b679SAndreas Boehler     * This method will always return a string, or null. If there were multiple
191*a1a3b679SAndreas Boehler     * values, it will automatically concatinate them (separated by comma).
192*a1a3b679SAndreas Boehler     *
193*a1a3b679SAndreas Boehler     * @return string|null
194*a1a3b679SAndreas Boehler     */
195*a1a3b679SAndreas Boehler    public function getValue() {
196*a1a3b679SAndreas Boehler
197*a1a3b679SAndreas Boehler        if (is_array($this->value)) {
198*a1a3b679SAndreas Boehler            return implode(',' , $this->value);
199*a1a3b679SAndreas Boehler        } else {
200*a1a3b679SAndreas Boehler            return $this->value;
201*a1a3b679SAndreas Boehler        }
202*a1a3b679SAndreas Boehler
203*a1a3b679SAndreas Boehler    }
204*a1a3b679SAndreas Boehler
205*a1a3b679SAndreas Boehler    /**
206*a1a3b679SAndreas Boehler     * Sets multiple values for this parameter.
207*a1a3b679SAndreas Boehler     *
208*a1a3b679SAndreas Boehler     * @param array $value
209*a1a3b679SAndreas Boehler     * @return void
210*a1a3b679SAndreas Boehler     */
211*a1a3b679SAndreas Boehler    public function setParts(array $value) {
212*a1a3b679SAndreas Boehler
213*a1a3b679SAndreas Boehler        $this->value = $value;
214*a1a3b679SAndreas Boehler
215*a1a3b679SAndreas Boehler    }
216*a1a3b679SAndreas Boehler
217*a1a3b679SAndreas Boehler    /**
218*a1a3b679SAndreas Boehler     * Returns all values for this parameter.
219*a1a3b679SAndreas Boehler     *
220*a1a3b679SAndreas Boehler     * If there were no values, an empty array will be returned.
221*a1a3b679SAndreas Boehler     *
222*a1a3b679SAndreas Boehler     * @return array
223*a1a3b679SAndreas Boehler     */
224*a1a3b679SAndreas Boehler    public function getParts() {
225*a1a3b679SAndreas Boehler
226*a1a3b679SAndreas Boehler        if (is_array($this->value)) {
227*a1a3b679SAndreas Boehler            return $this->value;
228*a1a3b679SAndreas Boehler        } elseif (is_null($this->value)) {
229*a1a3b679SAndreas Boehler            return array();
230*a1a3b679SAndreas Boehler        } else {
231*a1a3b679SAndreas Boehler            return array($this->value);
232*a1a3b679SAndreas Boehler        }
233*a1a3b679SAndreas Boehler
234*a1a3b679SAndreas Boehler    }
235*a1a3b679SAndreas Boehler
236*a1a3b679SAndreas Boehler    /**
237*a1a3b679SAndreas Boehler     * Adds a value to this parameter
238*a1a3b679SAndreas Boehler     *
239*a1a3b679SAndreas Boehler     * If the argument is specified as an array, all items will be added to the
240*a1a3b679SAndreas Boehler     * parameter value list.
241*a1a3b679SAndreas Boehler     *
242*a1a3b679SAndreas Boehler     * @param string|array $part
243*a1a3b679SAndreas Boehler     * @return void
244*a1a3b679SAndreas Boehler     */
245*a1a3b679SAndreas Boehler    public function addValue($part) {
246*a1a3b679SAndreas Boehler
247*a1a3b679SAndreas Boehler        if (is_null($this->value)) {
248*a1a3b679SAndreas Boehler            $this->value = $part;
249*a1a3b679SAndreas Boehler        } else {
250*a1a3b679SAndreas Boehler            $this->value = array_merge((array)$this->value, (array)$part);
251*a1a3b679SAndreas Boehler        }
252*a1a3b679SAndreas Boehler
253*a1a3b679SAndreas Boehler    }
254*a1a3b679SAndreas Boehler
255*a1a3b679SAndreas Boehler    /**
256*a1a3b679SAndreas Boehler     * Checks if this parameter contains the specified value.
257*a1a3b679SAndreas Boehler     *
258*a1a3b679SAndreas Boehler     * This is a case-insensitive match. It makes sense to call this for for
259*a1a3b679SAndreas Boehler     * instance the TYPE parameter, to see if it contains a keyword such as
260*a1a3b679SAndreas Boehler     * 'WORK' or 'FAX'.
261*a1a3b679SAndreas Boehler     *
262*a1a3b679SAndreas Boehler     * @param string $value
263*a1a3b679SAndreas Boehler     * @return bool
264*a1a3b679SAndreas Boehler     */
265*a1a3b679SAndreas Boehler    public function has($value) {
266*a1a3b679SAndreas Boehler
267*a1a3b679SAndreas Boehler        return in_array(
268*a1a3b679SAndreas Boehler            strtolower($value),
269*a1a3b679SAndreas Boehler            array_map('strtolower', (array)$this->value)
270*a1a3b679SAndreas Boehler        );
271*a1a3b679SAndreas Boehler
272*a1a3b679SAndreas Boehler    }
273*a1a3b679SAndreas Boehler
274*a1a3b679SAndreas Boehler    /**
275*a1a3b679SAndreas Boehler     * Turns the object back into a serialized blob.
276*a1a3b679SAndreas Boehler     *
277*a1a3b679SAndreas Boehler     * @return string
278*a1a3b679SAndreas Boehler     */
279*a1a3b679SAndreas Boehler    public function serialize() {
280*a1a3b679SAndreas Boehler
281*a1a3b679SAndreas Boehler        $value = $this->getParts();
282*a1a3b679SAndreas Boehler
283*a1a3b679SAndreas Boehler        if (count($value)===0) {
284*a1a3b679SAndreas Boehler            return $this->name . '=';
285*a1a3b679SAndreas Boehler        }
286*a1a3b679SAndreas Boehler
287*a1a3b679SAndreas Boehler        if ($this->root->getDocumentType() === Document::VCARD21 && $this->noName) {
288*a1a3b679SAndreas Boehler
289*a1a3b679SAndreas Boehler            return implode(';', $value);
290*a1a3b679SAndreas Boehler
291*a1a3b679SAndreas Boehler        }
292*a1a3b679SAndreas Boehler
293*a1a3b679SAndreas Boehler        return $this->name . '=' . array_reduce(
294*a1a3b679SAndreas Boehler            $value,
295*a1a3b679SAndreas Boehler            function($out, $item) {
296*a1a3b679SAndreas Boehler
297*a1a3b679SAndreas Boehler                if (!is_null($out)) $out.=',';
298*a1a3b679SAndreas Boehler
299*a1a3b679SAndreas Boehler                // If there's no special characters in the string, we'll use the simple
300*a1a3b679SAndreas Boehler                // format.
301*a1a3b679SAndreas Boehler                //
302*a1a3b679SAndreas Boehler                // The list of special characters is defined as:
303*a1a3b679SAndreas Boehler                //
304*a1a3b679SAndreas Boehler                // Any character except CONTROL, DQUOTE, ";", ":", ","
305*a1a3b679SAndreas Boehler                //
306*a1a3b679SAndreas Boehler                // by the iCalendar spec:
307*a1a3b679SAndreas Boehler                // https://tools.ietf.org/html/rfc5545#section-3.1
308*a1a3b679SAndreas Boehler                //
309*a1a3b679SAndreas Boehler                // And we add ^ to that because of:
310*a1a3b679SAndreas Boehler                // https://tools.ietf.org/html/rfc6868
311*a1a3b679SAndreas Boehler                //
312*a1a3b679SAndreas Boehler                // But we've found that iCal (7.0, shipped with OSX 10.9)
313*a1a3b679SAndreas Boehler                // severaly trips on + characters not being quoted, so we
314*a1a3b679SAndreas Boehler                // added + as well.
315*a1a3b679SAndreas Boehler                if (!preg_match('#(?: [\n":;\^,\+] )#x', $item)) {
316*a1a3b679SAndreas Boehler                    return $out.$item;
317*a1a3b679SAndreas Boehler                } else {
318*a1a3b679SAndreas Boehler                    // Enclosing in double-quotes, and using RFC6868 for encoding any
319*a1a3b679SAndreas Boehler                    // special characters
320*a1a3b679SAndreas Boehler                    $out.='"' . strtr(
321*a1a3b679SAndreas Boehler                        $item,
322*a1a3b679SAndreas Boehler                        array(
323*a1a3b679SAndreas Boehler                            '^'  => '^^',
324*a1a3b679SAndreas Boehler                            "\n" => '^n',
325*a1a3b679SAndreas Boehler                            '"'  => '^\'',
326*a1a3b679SAndreas Boehler                        )
327*a1a3b679SAndreas Boehler                    ) . '"';
328*a1a3b679SAndreas Boehler                    return $out;
329*a1a3b679SAndreas Boehler                }
330*a1a3b679SAndreas Boehler
331*a1a3b679SAndreas Boehler            }
332*a1a3b679SAndreas Boehler        );
333*a1a3b679SAndreas Boehler
334*a1a3b679SAndreas Boehler    }
335*a1a3b679SAndreas Boehler
336*a1a3b679SAndreas Boehler    /**
337*a1a3b679SAndreas Boehler     * This method returns an array, with the representation as it should be
338*a1a3b679SAndreas Boehler     * encoded in json. This is used to create jCard or jCal documents.
339*a1a3b679SAndreas Boehler     *
340*a1a3b679SAndreas Boehler     * @return array
341*a1a3b679SAndreas Boehler     */
342*a1a3b679SAndreas Boehler    public function jsonSerialize() {
343*a1a3b679SAndreas Boehler
344*a1a3b679SAndreas Boehler        return $this->value;
345*a1a3b679SAndreas Boehler
346*a1a3b679SAndreas Boehler    }
347*a1a3b679SAndreas Boehler
348*a1a3b679SAndreas Boehler    /**
349*a1a3b679SAndreas Boehler     * Called when this object is being cast to a string
350*a1a3b679SAndreas Boehler     *
351*a1a3b679SAndreas Boehler     * @return string
352*a1a3b679SAndreas Boehler     */
353*a1a3b679SAndreas Boehler    public function __toString() {
354*a1a3b679SAndreas Boehler
355*a1a3b679SAndreas Boehler        return (string)$this->getValue();
356*a1a3b679SAndreas Boehler
357*a1a3b679SAndreas Boehler    }
358*a1a3b679SAndreas Boehler
359*a1a3b679SAndreas Boehler    /**
360*a1a3b679SAndreas Boehler     * Returns the iterator for this object
361*a1a3b679SAndreas Boehler     *
362*a1a3b679SAndreas Boehler     * @return ElementList
363*a1a3b679SAndreas Boehler     */
364*a1a3b679SAndreas Boehler    public function getIterator() {
365*a1a3b679SAndreas Boehler
366*a1a3b679SAndreas Boehler        if (!is_null($this->iterator))
367*a1a3b679SAndreas Boehler            return $this->iterator;
368*a1a3b679SAndreas Boehler
369*a1a3b679SAndreas Boehler        return $this->iterator = new ArrayObject((array)$this->value);
370*a1a3b679SAndreas Boehler
371*a1a3b679SAndreas Boehler    }
372*a1a3b679SAndreas Boehler
373*a1a3b679SAndreas Boehler}
374