1<?php
2
3namespace Sabre\VObject\Property;
4
5use Sabre\VObject;
6
7/**
8 * Compound property.
9 *
10 * This class adds (de)serialization of compound properties to/from arrays.
11 *
12 * Currently the following properties from RFC 6350 are mapped to use this
13 * class:
14 *
15 *  N:          Section 6.2.2
16 *  ADR:        Section 6.3.1
17 *  ORG:        Section 6.6.4
18 *  CATEGORIES: Section 6.7.1
19 *
20 * In order to use this correctly, you must call setParts and getParts to
21 * retrieve and modify dates respectively.
22 *
23 * @author Thomas Tanghus (http://tanghus.net/)
24 * @author Lars Kneschke
25 * @author Evert Pot (http://evertpot.com/)
26 * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).
27 * @license http://sabre.io/license/ Modified BSD License
28 */
29class Compound extends VObject\Property {
30
31    /**
32     * If property names are added to this map, they will be (de)serialised as arrays
33     * using the getParts() and setParts() methods.
34     * The keys are the property names, values are delimiter chars.
35     *
36     * @var array
37     */
38    public static $delimiterMap = array(
39        'N'           =>    ';',
40        'ADR'         =>    ';',
41        'ORG'         =>    ';',
42        'CATEGORIES'  =>    ',',
43    );
44
45    /**
46     * The currently used delimiter.
47     *
48     * @var string
49     */
50    protected $delimiter = null;
51
52    /**
53     * Get a compound value as an array.
54     *
55     * @param $name string
56     * @return array
57     */
58    public function getParts() {
59
60        if (is_null($this->value)) {
61            return array();
62        }
63
64        $delimiter = $this->getDelimiter();
65
66        // split by any $delimiter which is NOT prefixed by a slash.
67        // Note that this is not a a perfect solution. If a value is prefixed
68        // by two slashes, it should actually be split anyway.
69        //
70        // Hopefully we can fix this better in a future version, where we can
71        // break compatibility a bit.
72        $compoundValues = preg_split("/(?<!\\\)$delimiter/", $this->value);
73
74        // remove slashes from any semicolon and comma left escaped in the single values
75        $compoundValues = array_map(
76            function($val) {
77                return strtr($val, array('\,' => ',', '\;' => ';'));
78        }, $compoundValues);
79
80        return $compoundValues;
81
82    }
83
84    /**
85     * Returns the delimiter for this property.
86     *
87     * @return string
88     */
89    public function getDelimiter() {
90
91        if (!$this->delimiter) {
92            if (isset(self::$delimiterMap[$this->name])) {
93                $this->delimiter = self::$delimiterMap[$this->name];
94            } else {
95                // To be a bit future proof, we are going to default the
96                // delimiter to ;
97                $this->delimiter = ';';
98            }
99        }
100        return $this->delimiter;
101
102    }
103
104    /**
105     * Set a compound value as an array.
106     *
107     *
108     * @param $name string
109     * @return array
110     */
111    public function setParts(array $values) {
112
113        // add slashes to all semicolons and commas in the single values
114        $values = array_map(
115            function($val) {
116                return strtr($val, array(',' => '\,', ';' => '\;'));
117            }, $values);
118
119        $this->setValue(
120            implode($this->getDelimiter(), $values)
121        );
122
123    }
124
125}
126