7
|
1 <?php
|
|
2
|
|
3 namespace Sabre\VObject\Parser;
|
|
4
|
|
5 use
|
|
6 Sabre\VObject\Component\VCalendar,
|
|
7 Sabre\VObject\Component\VCard,
|
|
8 Sabre\VObject\ParseException,
|
|
9 Sabre\VObject\EofException;
|
|
10
|
|
11 /**
|
|
12 * Json Parser.
|
|
13 *
|
|
14 * This parser parses both the jCal and jCard formats.
|
|
15 *
|
|
16 * @copyright Copyright (C) 2011-2015 fruux GmbH (https://fruux.com/).
|
|
17 * @author Evert Pot (http://evertpot.com/)
|
|
18 * @license http://sabre.io/license/ Modified BSD License
|
|
19 */
|
|
20 class Json extends Parser {
|
|
21
|
|
22 /**
|
|
23 * The input data
|
|
24 *
|
|
25 * @var array
|
|
26 */
|
|
27 protected $input;
|
|
28
|
|
29 /**
|
|
30 * Root component
|
|
31 *
|
|
32 * @var Document
|
|
33 */
|
|
34 protected $root;
|
|
35
|
|
36 /**
|
|
37 * This method starts the parsing process.
|
|
38 *
|
|
39 * If the input was not supplied during construction, it's possible to pass
|
|
40 * it here instead.
|
|
41 *
|
|
42 * If either input or options are not supplied, the defaults will be used.
|
|
43 *
|
|
44 * @param resource|string|array|null $input
|
|
45 * @param int|null $options
|
|
46 * @return array
|
|
47 */
|
|
48 public function parse($input = null, $options = null) {
|
|
49
|
|
50 if (!is_null($input)) {
|
|
51 $this->setInput($input);
|
|
52 }
|
|
53 if (is_null($this->input)) {
|
|
54 throw new EofException('End of input stream, or no input supplied');
|
|
55 }
|
|
56
|
|
57 if (!is_null($options)) {
|
|
58 $this->options = $options;
|
|
59 }
|
|
60
|
|
61 switch($this->input[0]) {
|
|
62 case 'vcalendar' :
|
|
63 $this->root = new VCalendar(array(), false);
|
|
64 break;
|
|
65 case 'vcard' :
|
|
66 $this->root = new VCard(array(), false);
|
|
67 break;
|
|
68 default :
|
|
69 throw new ParseException('The root component must either be a vcalendar, or a vcard');
|
|
70
|
|
71 }
|
|
72 foreach($this->input[1] as $prop) {
|
|
73 $this->root->add($this->parseProperty($prop));
|
|
74 }
|
|
75 if (isset($this->input[2])) foreach($this->input[2] as $comp) {
|
|
76 $this->root->add($this->parseComponent($comp));
|
|
77 }
|
|
78
|
|
79 // Resetting the input so we can throw an feof exception the next time.
|
|
80 $this->input = null;
|
|
81
|
|
82 return $this->root;
|
|
83
|
|
84 }
|
|
85
|
|
86 /**
|
|
87 * Parses a component
|
|
88 *
|
|
89 * @param array $jComp
|
|
90 * @return \Sabre\VObject\Component
|
|
91 */
|
|
92 public function parseComponent(array $jComp) {
|
|
93
|
|
94 // We can remove $self from PHP 5.4 onward.
|
|
95 $self = $this;
|
|
96
|
|
97 $properties = array_map(
|
|
98 function($jProp) use ($self) {
|
|
99 return $self->parseProperty($jProp);
|
|
100 },
|
|
101 $jComp[1]
|
|
102 );
|
|
103
|
|
104 if (isset($jComp[2])) {
|
|
105
|
|
106 $components = array_map(
|
|
107 function($jComp) use ($self) {
|
|
108 return $self->parseComponent($jComp);
|
|
109 },
|
|
110 $jComp[2]
|
|
111 );
|
|
112
|
|
113 } else $components = array();
|
|
114
|
|
115 return $this->root->createComponent(
|
|
116 $jComp[0],
|
|
117 array_merge($properties, $components),
|
|
118 $defaults = false
|
|
119 );
|
|
120
|
|
121 }
|
|
122
|
|
123 /**
|
|
124 * Parses properties.
|
|
125 *
|
|
126 * @param array $jProp
|
|
127 * @return \Sabre\VObject\Property
|
|
128 */
|
|
129 public function parseProperty(array $jProp) {
|
|
130
|
|
131 list(
|
|
132 $propertyName,
|
|
133 $parameters,
|
|
134 $valueType
|
|
135 ) = $jProp;
|
|
136
|
|
137 $propertyName = strtoupper($propertyName);
|
|
138
|
|
139 // This is the default class we would be using if we didn't know the
|
|
140 // value type. We're using this value later in this function.
|
|
141 $defaultPropertyClass = $this->root->getClassNameForPropertyName($propertyName);
|
|
142
|
|
143 $parameters = (array)$parameters;
|
|
144
|
|
145 $value = array_slice($jProp, 3);
|
|
146
|
|
147 $valueType = strtoupper($valueType);
|
|
148
|
|
149 if (isset($parameters['group'])) {
|
|
150 $propertyName = $parameters['group'] . '.' . $propertyName;
|
|
151 unset($parameters['group']);
|
|
152 }
|
|
153
|
|
154 $prop = $this->root->createProperty($propertyName, null, $parameters, $valueType);
|
|
155 $prop->setJsonValue($value);
|
|
156
|
|
157 // We have to do something awkward here. FlatText as well as Text
|
|
158 // represents TEXT values. We have to normalize these here. In the
|
|
159 // future we can get rid of FlatText once we're allowed to break BC
|
|
160 // again.
|
|
161 if ($defaultPropertyClass === 'Sabre\VObject\Property\FlatText') {
|
|
162 $defaultPropertyClass = 'Sabre\VObject\Property\Text';
|
|
163 }
|
|
164
|
|
165 // If the value type we received (e.g.: TEXT) was not the default value
|
|
166 // type for the given property (e.g.: BDAY), we need to add a VALUE=
|
|
167 // parameter.
|
|
168 if ($defaultPropertyClass !== get_class($prop)) {
|
|
169 $prop["VALUE"] = $valueType;
|
|
170 }
|
|
171
|
|
172 return $prop;
|
|
173
|
|
174 }
|
|
175
|
|
176 /**
|
|
177 * Sets the input data
|
|
178 *
|
|
179 * @param resource|string|array $input
|
|
180 * @return void
|
|
181 */
|
|
182 public function setInput($input) {
|
|
183
|
|
184 if (is_resource($input)) {
|
|
185 $input = stream_get_contents($input);
|
|
186 }
|
|
187 if (is_string($input)) {
|
|
188 $input = json_decode($input);
|
|
189 }
|
|
190 $this->input = $input;
|
|
191
|
|
192 }
|
|
193
|
|
194 }
|