1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace POData\Writers\Json; |
4
|
|
|
|
5
|
|
|
use POData\Common\MimeTypes; |
6
|
|
|
use POData\Common\ODataConstants; |
7
|
|
|
use POData\Common\Version; |
8
|
|
|
use POData\ObjectModel\ODataBagContent; |
9
|
|
|
use POData\ObjectModel\ODataEntry; |
10
|
|
|
use POData\ObjectModel\ODataFeed; |
11
|
|
|
use POData\ObjectModel\ODataLink; |
12
|
|
|
use POData\ObjectModel\ODataProperty; |
13
|
|
|
use POData\ObjectModel\ODataPropertyContent; |
14
|
|
|
use POData\ObjectModel\ODataURL; |
15
|
|
|
use POData\ObjectModel\ODataURLCollection; |
16
|
|
|
|
17
|
|
|
/** |
18
|
|
|
* Class JsonLightODataWriter is a writer for the json format in OData V3 also known as JSON Light. |
19
|
|
|
*/ |
20
|
|
|
class JsonLightODataWriter extends JsonODataV2Writer |
21
|
|
|
{ |
22
|
|
|
/** |
23
|
|
|
* @var JsonLightMetadataLevel |
24
|
|
|
*/ |
25
|
|
|
protected $metadataLevel; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* The service base uri. |
29
|
|
|
* |
30
|
|
|
* @var string |
31
|
|
|
*/ |
32
|
|
|
protected $baseUri; |
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* @param string $absoluteServiceUri |
36
|
|
|
*/ |
37
|
|
|
public function __construct(JsonLightMetadataLevel $metadataLevel, $absoluteServiceUri) |
38
|
|
|
{ |
39
|
|
|
if (strlen($absoluteServiceUri) == 0) { |
40
|
|
|
throw new \Exception('absoluteServiceUri must not be empty or null'); |
41
|
|
|
} |
42
|
|
|
$this->baseUri = $absoluteServiceUri; |
43
|
|
|
|
44
|
|
|
$this->_writer = new JsonWriter(''); |
45
|
|
|
$this->urlKey = ODataConstants::JSON_URL_STRING; |
46
|
|
|
$this->dataArrayName = ODataConstants::JSON_LIGHT_VALUE_NAME; |
47
|
|
|
$this->rowCountName = ODataConstants::JSON_LIGHT_ROWCOUNT_STRING; |
48
|
|
|
$this->metadataLevel = $metadataLevel; |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Determines if the given writer is capable of writing the response or not. |
53
|
|
|
* |
54
|
|
|
* @param Version $responseVersion the OData version of the response |
55
|
|
|
* @param string $contentType the Content Type of the response |
56
|
|
|
* |
57
|
|
|
* @return bool true if the writer can handle the response, false otherwise |
58
|
|
|
*/ |
59
|
|
View Code Duplication |
public function canHandle(Version $responseVersion, $contentType) |
|
|
|
|
60
|
|
|
{ |
61
|
|
|
if ($responseVersion != Version::v3()) { |
62
|
|
|
return false; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
$parts = explode(';', $contentType); |
66
|
|
|
|
67
|
|
|
//It must be app/json and have the right odata= piece |
68
|
|
|
return in_array(MimeTypes::MIME_APPLICATION_JSON, $parts) && in_array($this->metadataLevel->getValue(), $parts); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Write the given OData model in a specific response format. |
73
|
|
|
* |
74
|
|
|
* @param ODataURL|ODataURLCollection|ODataPropertyContent|ODataFeed|ODataEntry $model Object of requested content |
75
|
|
|
* |
76
|
|
|
* @return JsonLightODataWriter |
77
|
|
|
*/ |
78
|
|
|
public function write($model) |
79
|
|
|
{ |
80
|
|
|
$this->_writer->startObjectScope(); |
81
|
|
|
|
82
|
|
|
if ($model instanceof ODataURL) { |
83
|
|
|
$this->writeTopLevelMeta('url'); |
84
|
|
|
$this->writeURL($model); |
85
|
|
|
} elseif ($model instanceof ODataURLCollection) { |
86
|
|
|
$this->writeTopLevelMeta('urlCollection'); |
87
|
|
|
$this->writeURLCollection($model); |
88
|
|
|
} elseif ($model instanceof ODataPropertyContent) { |
89
|
|
|
$this->writeTopLevelMeta($model->properties[0]->typeName); |
90
|
|
|
$this->writeTopLevelProperty($model->properties[0]); |
91
|
|
|
} elseif ($model instanceof ODataFeed) { |
92
|
|
|
$this->writeTopLevelMeta($model->title); |
93
|
|
|
$this->writeRowCount($model->rowCount); |
94
|
|
|
$this->_writer |
95
|
|
|
->writeName($this->dataArrayName) |
96
|
|
|
->startArrayScope(); |
97
|
|
|
$this->writeFeed($model); |
98
|
|
|
$this->_writer->endScope(); |
99
|
|
|
} elseif ($model instanceof ODataEntry) { |
100
|
|
|
$this->writeTopLevelMeta($model->resourceSetName . '/@Element'); |
101
|
|
|
$this->writeEntry($model); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
$this->_writer->endScope(); |
105
|
|
|
|
106
|
|
|
return $this; |
107
|
|
|
} |
108
|
|
|
|
109
|
|
|
/** |
110
|
|
|
* @param ODataProperty $property |
111
|
|
|
* |
112
|
|
|
* @return JsonLightODataWriter |
113
|
|
|
*/ |
114
|
|
|
protected function writeTopLevelProperty(ODataProperty $property) |
115
|
|
|
{ |
116
|
|
|
$this->writePropertyMeta($property); |
117
|
|
|
if ($property->value == null) { |
118
|
|
|
$this->_writer->writeName(ODataConstants::JSON_LIGHT_VALUE_NAME); |
119
|
|
|
$this->_writer->writeValue('null'); |
120
|
|
|
} elseif ($property->value instanceof ODataPropertyContent) { |
121
|
|
|
//In the case of complex properties at the top level we don't write the name of the property, |
122
|
|
|
//just the sub properties. |
123
|
|
|
$this->writeComplexPropertyMeta($property) |
124
|
|
|
->writeProperties($property->value); |
125
|
|
|
} elseif ($property->value instanceof ODataBagContent) { |
126
|
|
|
$this->_writer->writeName(ODataConstants::JSON_LIGHT_VALUE_NAME); |
127
|
|
|
$this->writeBagContent($property->value); |
128
|
|
|
} else { |
129
|
|
|
$this->_writer->writeName(ODataConstants::JSON_LIGHT_VALUE_NAME); |
130
|
|
|
$this->_writer->writeValue($property->value, $property->typeName); |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
return $this; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
/** |
137
|
|
|
* @param string $fragment |
138
|
|
|
*/ |
139
|
|
|
protected function writeTopLevelMeta($fragment) |
140
|
|
|
{ |
141
|
|
|
if ($this->metadataLevel == JsonLightMetadataLevel::NONE()) { |
142
|
|
|
return; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
$this->_writer |
146
|
|
|
->writeName(ODataConstants::JSON_LIGHT_METADATA_STRING) |
147
|
|
|
->writeValue($this->baseUri . '/' . ODataConstants::URI_METADATA_SEGMENT . '#' . $fragment); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
protected function writePropertyMeta(ODataProperty $property) |
151
|
|
|
{ |
152
|
|
|
if ($this->metadataLevel != JsonLightMetadataLevel::FULL()) { |
153
|
|
|
//Only full meta level outputs this info |
154
|
|
|
return $this; |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
if (is_null($property->value)) { |
158
|
|
|
//it appears full metadata doesn't output types for nulls... |
159
|
|
|
return $this; |
160
|
|
|
} |
161
|
|
|
|
162
|
|
|
switch ($property->typeName) { |
163
|
|
|
//The type metadata is only included on certain types of properties |
164
|
|
|
//Note this also excludes Complex types |
165
|
|
|
|
166
|
|
|
case 'Edm.Decimal': |
167
|
|
|
case 'Edm.DateTime': |
168
|
|
|
$this->_writer |
169
|
|
|
->writeName($property->name . ODataConstants::JSON_LIGHT_METADATA_PROPERTY_TYPE_SUFFIX_STRING) |
170
|
|
|
->writeValue($property->typeName); |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
return $this; |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* @param ODataEntry $entry Entry to write metadata for |
178
|
|
|
* |
179
|
|
|
* @return JsonLightODataWriter |
180
|
|
|
*/ |
181
|
|
|
protected function writeEntryMetadata(ODataEntry $entry) |
182
|
|
|
{ |
183
|
|
|
if ($this->metadataLevel != JsonLightMetadataLevel::FULL()) { |
184
|
|
|
//Only full meta level outputs this info |
185
|
|
|
return $this; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
$this->_writer |
189
|
|
|
->writeName(ODataConstants::JSON_LIGHT_METADATA_TYPE_STRING) |
190
|
|
|
->writeValue($entry->type) |
191
|
|
|
->writeName(ODataConstants::JSON_LIGHT_METADATA_ID_STRING) |
192
|
|
|
->writeValue($entry->id) |
193
|
|
|
->writeName(ODataConstants::JSON_LIGHT_METADATA_ETAG_STRING) |
194
|
|
|
->writeValue($entry->eTag) |
195
|
|
|
->writeName(ODataConstants::JSON_LIGHT_METADATA_EDIT_LINK_STRING) |
196
|
|
|
->writeValue($entry->editLink); |
197
|
|
|
|
198
|
|
|
return $this; |
199
|
|
|
} |
200
|
|
|
|
201
|
|
|
/** |
202
|
|
|
* @param ODataLink $link Link to write |
203
|
|
|
* |
204
|
|
|
* @return JsonLightODataWriter |
205
|
|
|
*/ |
206
|
|
|
protected function writeLink(ODataLink $link) |
207
|
|
|
{ |
208
|
|
|
if ($this->metadataLevel == JsonLightMetadataLevel::FULL()) { |
209
|
|
|
//Interestingly the fullmetadata outputs this metadata..even if the thing is expanded |
210
|
|
|
$this->_writer |
211
|
|
|
->writeName($link->title . ODataConstants::JSON_LIGHT_METADATA_LINK_NAVIGATION_SUFFIX_STRING) |
212
|
|
|
->writeValue($link->url); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
if ($link->isExpanded) { |
216
|
|
|
$this->_writer->writeName($link->title); |
217
|
|
|
|
218
|
|
|
if (is_null($link->expandedResult)) { |
219
|
|
|
$this->_writer->writeValue('null'); |
220
|
|
|
} else { |
221
|
|
|
$this->writeExpandedLink($link); |
222
|
|
|
} |
223
|
|
|
} |
224
|
|
|
|
225
|
|
|
return $this; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
View Code Duplication |
protected function writeExpandedLink(ODataLink $link) |
|
|
|
|
229
|
|
|
{ |
230
|
|
|
if ($link->isCollection) { |
231
|
|
|
$this->_writer->startArrayScope(); |
232
|
|
|
$this->writeFeed($link->expandedResult); |
|
|
|
|
233
|
|
|
} else { |
234
|
|
|
$this->_writer->startObjectScope(); |
235
|
|
|
$this->writeEntry($link->expandedResult); |
|
|
|
|
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
$this->_writer->endScope(); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* Writes the next page link. |
243
|
|
|
* |
244
|
|
|
* @param ODataLink $nextPageLinkUri Uri for next page link |
245
|
|
|
* |
246
|
|
|
* @return JsonLightODataWriter |
247
|
|
|
*/ |
248
|
|
|
protected function writeNextPageLink(ODataLink $nextPageLinkUri = null) |
249
|
|
|
{ |
250
|
|
|
return; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Begin write complex property. |
255
|
|
|
* |
256
|
|
|
* @param ODataProperty $property property to write |
257
|
|
|
* |
258
|
|
|
* @return JsonLightODataWriter |
259
|
|
|
*/ |
260
|
|
|
protected function writeComplexProperty(ODataProperty $property) |
261
|
|
|
{ |
262
|
|
|
$this->_writer->startObjectScope(); |
263
|
|
|
|
264
|
|
|
$this->writeComplexPropertyMeta($property) |
265
|
|
|
->writeProperties($property->value); |
|
|
|
|
266
|
|
|
|
267
|
|
|
$this->_writer->endScope(); |
268
|
|
|
|
269
|
|
|
return $this; |
270
|
|
|
} |
271
|
|
|
|
272
|
|
|
protected function writeComplexPropertyMeta(ODataProperty $property) |
273
|
|
|
{ |
274
|
|
|
if ($this->metadataLevel == JsonLightMetadataLevel::FULL()) { |
275
|
|
|
$this->_writer |
276
|
|
|
->writeName(ODataConstants::JSON_LIGHT_METADATA_TYPE_STRING) |
277
|
|
|
->writeValue($property->typeName); |
278
|
|
|
} |
279
|
|
|
|
280
|
|
|
return $this; |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
protected function writeBagContent(ODataBagContent $bag) |
284
|
|
|
{ |
285
|
|
|
$this->_writer->startArrayScope(); |
286
|
|
|
|
287
|
|
View Code Duplication |
foreach ($bag->propertyContents as $content) { |
|
|
|
|
288
|
|
|
if ($content instanceof ODataPropertyContent) { |
289
|
|
|
$this->_writer->startObjectScope(); |
290
|
|
|
$this->writeProperties($content); |
291
|
|
|
$this->_writer->endScope(); |
292
|
|
|
} else { |
293
|
|
|
// retrieving the collection datatype in order |
294
|
|
|
//to write in json specific format, with in chords or not |
295
|
|
|
preg_match('#\((.*?)\)#', $bag->type, $type); |
296
|
|
|
$this->_writer->writeValue($content, $type[1]); |
297
|
|
|
} |
298
|
|
|
} |
299
|
|
|
|
300
|
|
|
$this->_writer->endScope(); |
301
|
|
|
return $this; |
302
|
|
|
} |
303
|
|
|
} |
304
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.