|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
declare(strict_types=1); |
|
4
|
|
|
|
|
5
|
|
|
namespace POData\ObjectModel; |
|
6
|
|
|
|
|
7
|
|
|
use AlgoWeb\ODataMetadata\MetadataManager; |
|
8
|
|
|
use POData\Common\MimeTypes; |
|
9
|
|
|
use POData\Common\ODataConstants; |
|
10
|
|
|
use POData\ObjectModel\AtomObjectModel\AtomAuthor; |
|
11
|
|
|
use POData\ObjectModel\AtomObjectModel\AtomContent; |
|
12
|
|
|
|
|
13
|
|
|
/** |
|
14
|
|
|
* Class ODataEntry. |
|
15
|
|
|
* TODO: the methods should be rearranged to match theorder of the properties. |
|
16
|
|
|
* TODO: the properties are still public needs a lot of unpicking to work out as type hints maybe wrong. |
|
17
|
|
|
*/ |
|
18
|
|
|
class ODataEntry extends ODataContainerBase |
|
19
|
|
|
{ |
|
20
|
|
|
/** |
|
21
|
|
|
* Entry Edit Link. |
|
22
|
|
|
* |
|
23
|
|
|
* @var ODataLink|null |
|
24
|
|
|
*/ |
|
25
|
|
|
public $editLink; |
|
26
|
|
|
/** |
|
27
|
|
|
* Entry Type. This become the value of term attribute of Category element. |
|
28
|
|
|
* |
|
29
|
|
|
* @var ODataCategory|null |
|
30
|
|
|
*/ |
|
31
|
|
|
public $type; |
|
32
|
|
|
/** |
|
33
|
|
|
* Instance to hold entity properties. |
|
34
|
|
|
* Properties corresponding to "m:properties" under content element |
|
35
|
|
|
* in the case of Non-MLE. For MLE "m:properties" is direct child of entry. |
|
36
|
|
|
* |
|
37
|
|
|
* @var ODataPropertyContent|null |
|
38
|
|
|
*/ |
|
39
|
|
|
public $propertyContent; |
|
40
|
|
|
/** |
|
41
|
|
|
* Collection of entry media links (Named Stream Links). |
|
42
|
|
|
* |
|
43
|
|
|
* @var array<ODataMediaLink> |
|
44
|
|
|
*/ |
|
45
|
|
|
public $mediaLinks = []; |
|
46
|
|
|
/** |
|
47
|
|
|
* media link entry (MLE Link). |
|
48
|
|
|
* |
|
49
|
|
|
* @var ODataMediaLink|null |
|
50
|
|
|
*/ |
|
51
|
|
|
public $mediaLink; |
|
52
|
|
|
/** |
|
53
|
|
|
* Collection of navigation links (can be expanded). |
|
54
|
|
|
* |
|
55
|
|
|
* @var array<ODataLink> |
|
56
|
|
|
*/ |
|
57
|
|
|
public $links = []; |
|
58
|
|
|
/** |
|
59
|
|
|
* Entry ETag. |
|
60
|
|
|
* |
|
61
|
|
|
* @var string|null |
|
62
|
|
|
*/ |
|
63
|
|
|
public $eTag; |
|
64
|
|
|
|
|
65
|
|
|
/** |
|
66
|
|
|
* True if this is a media link entry. |
|
67
|
|
|
* |
|
68
|
|
|
* @var bool|null |
|
69
|
|
|
*/ |
|
70
|
|
|
public $isMediaLinkEntry; |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* The name of the resource set this entry belongs to, use in metadata output. |
|
74
|
|
|
* |
|
75
|
|
|
* @var string|null |
|
76
|
|
|
*/ |
|
77
|
|
|
public $resourceSetName; |
|
78
|
|
|
|
|
79
|
|
|
|
|
80
|
|
|
|
|
81
|
|
|
/** |
|
82
|
|
|
* ODataEntry constructor. |
|
83
|
|
|
* @param string|null $id |
|
84
|
|
|
* @param string|null $selfLink |
|
85
|
|
|
* @param ODataTitle|null $title |
|
86
|
|
|
* @param ODataLink|null $editLink |
|
87
|
|
|
* @param ODataCategory|null $type |
|
88
|
|
|
* @param ODataPropertyContent|null $propertyContent |
|
89
|
|
|
* @param array $mediaLinks |
|
90
|
|
|
* @param ODataMediaLink|null $mediaLink |
|
91
|
|
|
* @param array $links |
|
92
|
|
|
* @param string|null $eTag |
|
93
|
|
|
* @param bool|null $isMediaLinkEntry |
|
94
|
|
|
* @param string|null $resourceSetName |
|
95
|
|
|
* @param string|null $updated |
|
96
|
|
|
* @param string|null $baseURI |
|
97
|
|
|
*/ |
|
98
|
|
|
public function __construct( |
|
99
|
|
|
?string $id = null, |
|
100
|
|
|
?string $selfLink = null, |
|
101
|
|
|
?ODataTitle $title = null, |
|
102
|
|
|
?ODataLink $editLink = null, |
|
103
|
|
|
?ODataCategory $type = null, |
|
104
|
|
|
?ODataPropertyContent $propertyContent = null, |
|
105
|
|
|
array $mediaLinks = [], |
|
106
|
|
|
?ODataMediaLink $mediaLink = null, |
|
107
|
|
|
array $links = [], |
|
108
|
|
|
?string $eTag = null, |
|
109
|
|
|
?bool $isMediaLinkEntry = null, |
|
110
|
|
|
?string $resourceSetName = null, |
|
111
|
|
|
?string $updated = null, |
|
112
|
|
|
?string $baseURI = null |
|
113
|
|
|
) { |
|
114
|
|
|
$this->id = $id; |
|
115
|
|
|
$this->selfLink = $selfLink; |
|
|
|
|
|
|
116
|
|
|
$this->title = $title; |
|
117
|
|
|
$this->editLink = $editLink; |
|
118
|
|
|
$this->type = $type; |
|
119
|
|
|
$this->propertyContent = $propertyContent; |
|
120
|
|
|
$this->mediaLinks = $mediaLinks; |
|
121
|
|
|
$this->mediaLink = $mediaLink; |
|
122
|
|
|
$this->links = $links; |
|
123
|
|
|
$this->eTag = $eTag; |
|
124
|
|
|
$this->isMediaLinkEntry = $isMediaLinkEntry; |
|
125
|
|
|
$this->resourceSetName = $resourceSetName; |
|
126
|
|
|
$this->updated = $updated; |
|
127
|
|
|
$this->baseURI = $baseURI; |
|
128
|
|
|
} |
|
129
|
|
|
|
|
130
|
|
|
|
|
131
|
|
|
/** |
|
132
|
|
|
* @return string|null |
|
133
|
|
|
*/ |
|
134
|
|
|
public function getETag(): ?string |
|
135
|
|
|
{ |
|
136
|
|
|
return $this->eTag; |
|
137
|
|
|
} |
|
138
|
|
|
|
|
139
|
|
|
/** |
|
140
|
|
|
* @param string|null $eTag |
|
141
|
|
|
* @return ODataEntry |
|
142
|
|
|
*/ |
|
143
|
|
|
public function setETag(?string $eTag): ODataEntry |
|
144
|
|
|
{ |
|
145
|
|
|
$this->eTag = $eTag; |
|
146
|
|
|
return $this; |
|
147
|
|
|
} |
|
148
|
|
|
|
|
149
|
|
|
/** |
|
150
|
|
|
* @return bool|null |
|
151
|
|
|
*/ |
|
152
|
|
|
public function getIsMediaLinkEntry(): ?bool |
|
153
|
|
|
{ |
|
154
|
|
|
return $this->isMediaLinkEntry; |
|
155
|
|
|
} |
|
156
|
|
|
|
|
157
|
|
|
/** |
|
158
|
|
|
* @param bool|null $isMediaLinkEntry |
|
159
|
|
|
* @return ODataEntry |
|
160
|
|
|
*/ |
|
161
|
|
|
public function setIsMediaLinkEntry(?bool $isMediaLinkEntry): ODataEntry |
|
162
|
|
|
{ |
|
163
|
|
|
$this->isMediaLinkEntry = $isMediaLinkEntry; |
|
164
|
|
|
return $this; |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
/** |
|
168
|
|
|
* @return string|null |
|
169
|
|
|
*/ |
|
170
|
|
|
public function getResourceSetName(): ?string |
|
171
|
|
|
{ |
|
172
|
|
|
return $this->resourceSetName; |
|
173
|
|
|
} |
|
174
|
|
|
|
|
175
|
|
|
/** |
|
176
|
|
|
* @param string|null $resourceSetName |
|
177
|
|
|
* @return ODataEntry |
|
178
|
|
|
*/ |
|
179
|
|
|
public function setResourceSetName(?string $resourceSetName): ODataEntry |
|
180
|
|
|
{ |
|
181
|
|
|
$this->resourceSetName = $resourceSetName; |
|
182
|
|
|
return $this; |
|
183
|
|
|
} |
|
184
|
|
|
|
|
185
|
|
|
/** |
|
186
|
|
|
* @return AtomContent |
|
187
|
|
|
*/ |
|
188
|
|
|
public function getAtomContent() |
|
189
|
|
|
{ |
|
190
|
|
|
if (!$this->isMediaLinkEntry) { |
|
|
|
|
|
|
191
|
|
|
return new AtomObjectModel\AtomContent( |
|
192
|
|
|
MimeTypes::MIME_APPLICATION_XML, |
|
193
|
|
|
null, |
|
194
|
|
|
$this->propertyContent |
|
195
|
|
|
); |
|
196
|
|
|
} |
|
197
|
|
|
return new AtomObjectModel\AtomContent($this->mediaLink->contentType, $this->mediaLink->srcLink); |
|
198
|
|
|
} |
|
199
|
|
|
|
|
200
|
|
|
/** |
|
201
|
|
|
* @param AtomContent $atomContent |
|
202
|
|
|
* @return ODataEntry |
|
203
|
|
|
*/ |
|
204
|
|
|
public function setAtomContent(AtomObjectModel\AtomContent $atomContent): self |
|
205
|
|
|
{ |
|
206
|
|
|
$this->setPropertyContent($atomContent->properties); |
|
207
|
|
|
return $this; |
|
208
|
|
|
} |
|
209
|
|
|
|
|
210
|
|
|
/** |
|
211
|
|
|
* @return AtomAuthor |
|
212
|
|
|
*/ |
|
213
|
|
|
public function getAtomAuthor(): AtomAuthor |
|
214
|
|
|
{ |
|
215
|
|
|
return new AtomObjectModel\AtomAuthor(); |
|
216
|
|
|
} |
|
217
|
|
|
|
|
218
|
|
|
/** |
|
219
|
|
|
* @return null|ODataPropertyContent |
|
220
|
|
|
*/ |
|
221
|
|
|
public function getPropertyContent(): ?ODataPropertyContent |
|
222
|
|
|
{ |
|
223
|
|
|
if (!$this->isMediaLinkEntry) { |
|
|
|
|
|
|
224
|
|
|
return null; |
|
225
|
|
|
} |
|
226
|
|
|
return $this->propertyContent; |
|
227
|
|
|
} |
|
228
|
|
|
|
|
229
|
|
|
/** |
|
230
|
|
|
* @param ODataPropertyContent|null $oDataPropertyContent |
|
231
|
|
|
* @return ODataEntry |
|
232
|
|
|
*/ |
|
233
|
|
|
public function setPropertyContent(ODataPropertyContent $oDataPropertyContent = null): self |
|
234
|
|
|
{ |
|
235
|
|
|
$this->propertyContent = $oDataPropertyContent; |
|
236
|
|
|
return $this; |
|
237
|
|
|
} |
|
238
|
|
|
|
|
239
|
|
|
/** |
|
240
|
|
|
* @return ODataLink |
|
241
|
|
|
*/ |
|
242
|
|
|
public function getEditLink(): ODataLink |
|
243
|
|
|
{ |
|
244
|
|
|
return $this->editLink; |
|
|
|
|
|
|
245
|
|
|
} |
|
246
|
|
|
|
|
247
|
|
|
/** |
|
248
|
|
|
* @return ODataCategory |
|
249
|
|
|
*/ |
|
250
|
|
|
public function getType(): ?ODataCategory |
|
251
|
|
|
{ |
|
252
|
|
|
return $this->type; |
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
/** |
|
256
|
|
|
* @param ODataCategory|null $type |
|
257
|
|
|
* @return ODataEntry |
|
258
|
|
|
*/ |
|
259
|
|
|
public function setType(ODataCategory $type = null): self |
|
260
|
|
|
{ |
|
261
|
|
|
$this->type = $type; |
|
262
|
|
|
if (null !== $type) { |
|
263
|
|
|
$rawTerm = $type->getTerm(); |
|
264
|
|
|
$termArray = explode('.', $rawTerm); |
|
265
|
|
|
$final = $termArray[count($termArray) - 1]; |
|
266
|
|
|
$this->resourceSetName = MetadataManager::getResourceSetNameFromResourceType($final); |
|
267
|
|
|
} |
|
268
|
|
|
return $this; |
|
269
|
|
|
} |
|
270
|
|
|
|
|
271
|
|
|
/** |
|
272
|
|
|
* @return ODataLink[] |
|
273
|
|
|
*/ |
|
274
|
|
|
public function getLinks(): array |
|
275
|
|
|
{ |
|
276
|
|
|
return $this->links; |
|
277
|
|
|
} |
|
278
|
|
|
|
|
279
|
|
|
/** |
|
280
|
|
|
* @param $links ODataLink[] |
|
281
|
|
|
* @return ODataEntry |
|
282
|
|
|
*/ |
|
283
|
|
|
public function setLinks(array $links): self |
|
284
|
|
|
{ |
|
285
|
|
|
$this->links = []; |
|
286
|
|
|
foreach ($links as $link) { |
|
287
|
|
|
if ('edit' == $link->getName()) { |
|
288
|
|
|
$this->editLink = $link; |
|
289
|
|
|
$this->resourceSetName = explode('(', $link->getUrl())[0]; |
|
290
|
|
|
continue; |
|
291
|
|
|
} |
|
292
|
|
|
if ('http://schemas.microsoft.com/ado/2007/08/dataservices/related' == substr($link->getName(), 0, 61) |
|
293
|
|
|
) { |
|
294
|
|
|
$this->links[] = $link; |
|
295
|
|
|
continue; |
|
296
|
|
|
} |
|
297
|
|
|
} |
|
298
|
|
|
return $this; |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
/** |
|
302
|
|
|
* @return ODataMediaLink[] |
|
303
|
|
|
*/ |
|
304
|
|
|
public function getMediaLinks(): array |
|
305
|
|
|
{ |
|
306
|
|
|
return $this->mediaLinks; |
|
307
|
|
|
} |
|
308
|
|
|
|
|
309
|
|
|
/** |
|
310
|
|
|
* @param ODataMediaLink[] $mediaLinks |
|
311
|
|
|
* @return ODataEntry |
|
312
|
|
|
*/ |
|
313
|
|
|
public function setMediaLinks(array $mediaLinks): self |
|
314
|
|
|
{ |
|
315
|
|
|
$this->mediaLinks = []; |
|
316
|
|
|
$editLink = null; |
|
317
|
|
|
foreach ($mediaLinks as $mediaLink) { |
|
318
|
|
|
$this->handleMediaLinkEntry($mediaLink, $editLink); |
|
319
|
|
|
} |
|
320
|
|
|
$this->correctMediaLinkSrc($editLink); |
|
321
|
|
|
if (null === $this->mediaLink) { |
|
322
|
|
|
$this->isMediaLinkEntry = false; |
|
323
|
|
|
} |
|
324
|
|
|
return $this; |
|
325
|
|
|
} |
|
326
|
|
|
|
|
327
|
|
|
/** |
|
328
|
|
|
* @param ODataMediaLink $mediaLink |
|
329
|
|
|
* @param ODataMediaLink|null $editLink |
|
330
|
|
|
*/ |
|
331
|
|
|
private function handleMediaLinkEntry(ODataMediaLink $mediaLink, ODataMediaLink &$editLink = null): void |
|
332
|
|
|
{ |
|
333
|
|
|
if ('edit-media' == $mediaLink->rel) { |
|
334
|
|
|
$this->isMediaLinkEntry = true; |
|
335
|
|
|
$this->mediaLink = $mediaLink; |
|
336
|
|
|
} |
|
337
|
|
|
if (ODataConstants::ATOM_MEDIA_RESOURCE_RELATION_ATTRIBUTE_VALUE == substr($mediaLink->rel, 0, 68)) { |
|
338
|
|
|
$this->mediaLinks[] = $mediaLink; |
|
339
|
|
|
} |
|
340
|
|
|
if ('edit' == $mediaLink->rel) { |
|
341
|
|
|
$editLink = $mediaLink; |
|
342
|
|
|
} |
|
343
|
|
|
} |
|
344
|
|
|
|
|
345
|
|
|
/** |
|
346
|
|
|
* @param ODataMediaLink|null $editLink |
|
347
|
|
|
*/ |
|
348
|
|
|
private function correctMediaLinkSrc(ODataMediaLink $editLink = null): void |
|
349
|
|
|
{ |
|
350
|
|
|
if (null !== $this->mediaLink && null !== $editLink) { |
|
351
|
|
|
$this->mediaLink->srcLink = $editLink->editLink . $this->mediaLink->editLink; |
|
352
|
|
|
foreach ($this->mediaLinks as $mediaLink) { |
|
353
|
|
|
$mediaLink->srcLink = $editLink->editLink . '/' . $mediaLink->name; |
|
354
|
|
|
} |
|
355
|
|
|
} |
|
356
|
|
|
} |
|
357
|
|
|
|
|
358
|
|
|
/** |
|
359
|
|
|
* @return ODataMediaLink |
|
360
|
|
|
*/ |
|
361
|
|
|
public function getMediaLink(): ODataMediaLink |
|
362
|
|
|
{ |
|
363
|
|
|
return $this->mediaLink; |
|
|
|
|
|
|
364
|
|
|
} |
|
365
|
|
|
|
|
366
|
|
|
/** |
|
367
|
|
|
* @param string|null $msg |
|
368
|
|
|
* @return bool |
|
369
|
|
|
*/ |
|
370
|
|
|
public function isOk(&$msg = null): bool |
|
371
|
|
|
{ |
|
372
|
|
|
if (!$this->propertyContent instanceof ODataPropertyContent) { |
|
373
|
|
|
$msg = 'Property content must be instanceof ODataPropertyContent.'; |
|
374
|
|
|
return false; |
|
375
|
|
|
} |
|
376
|
|
|
if (0 === count($this->propertyContent->properties)) { |
|
377
|
|
|
$msg = 'Must have at least one property present.'; |
|
378
|
|
|
return false; |
|
379
|
|
|
} |
|
380
|
|
|
|
|
381
|
|
|
return true; |
|
382
|
|
|
} |
|
383
|
|
|
} |
|
384
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountIdthat can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theidproperty of an instance of theAccountclass. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.