1 | <?php |
||||||
2 | |||||||
3 | declare(strict_types=1); |
||||||
4 | |||||||
5 | namespace AlgoWeb\PODataLaravel\Serialisers; |
||||||
6 | |||||||
7 | use Carbon\Carbon; |
||||||
8 | use Illuminate\Database\Eloquent\Model; |
||||||
9 | use Illuminate\Support\Collection; |
||||||
10 | use Illuminate\Support\Facades\App; |
||||||
11 | use POData\Common\InvalidOperationException; |
||||||
12 | use POData\Common\Messages; |
||||||
13 | use POData\Common\ODataConstants; |
||||||
14 | use POData\Common\ODataException; |
||||||
15 | use POData\IService; |
||||||
16 | use POData\ObjectModel\IObjectSerialiser; |
||||||
17 | use POData\ObjectModel\ODataBagContent; |
||||||
18 | use POData\ObjectModel\ODataCategory; |
||||||
19 | use POData\ObjectModel\ODataEntry; |
||||||
20 | use POData\ObjectModel\ODataExpandedResult; |
||||||
21 | use POData\ObjectModel\ODataFeed; |
||||||
22 | use POData\ObjectModel\ODataLink; |
||||||
23 | use POData\ObjectModel\ODataMediaLink; |
||||||
24 | use POData\ObjectModel\ODataProperty; |
||||||
25 | use POData\ObjectModel\ODataPropertyContent; |
||||||
26 | use POData\ObjectModel\ODataTitle; |
||||||
27 | use POData\ObjectModel\ODataURL; |
||||||
28 | use POData\ObjectModel\ODataURLCollection; |
||||||
29 | use POData\Providers\Metadata\IMetadataProvider; |
||||||
30 | use POData\Providers\Metadata\ResourceEntityType; |
||||||
31 | use POData\Providers\Metadata\ResourceProperty; |
||||||
32 | use POData\Providers\Metadata\ResourcePropertyKind; |
||||||
33 | use POData\Providers\Metadata\ResourceSet; |
||||||
34 | use POData\Providers\Metadata\ResourceSetWrapper; |
||||||
35 | use POData\Providers\Metadata\ResourceType; |
||||||
36 | use POData\Providers\Metadata\ResourceTypeKind; |
||||||
37 | use POData\Providers\Metadata\Type\Binary; |
||||||
38 | use POData\Providers\Metadata\Type\Boolean; |
||||||
39 | use POData\Providers\Metadata\Type\DateTime; |
||||||
40 | use POData\Providers\Metadata\Type\IType; |
||||||
41 | use POData\Providers\Metadata\Type\StringType; |
||||||
42 | use POData\Providers\Query\QueryResult; |
||||||
43 | use POData\Providers\Query\QueryType; |
||||||
44 | use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ExpandedProjectionNode; |
||||||
45 | use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ProjectionNode; |
||||||
46 | use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\RootProjectionNode; |
||||||
47 | use POData\UriProcessor\QueryProcessor\OrderByParser\InternalOrderByInfo; |
||||||
48 | use POData\UriProcessor\RequestDescription; |
||||||
49 | use POData\UriProcessor\SegmentStack; |
||||||
50 | |||||||
51 | class IronicSerialiser implements IObjectSerialiser |
||||||
52 | { |
||||||
53 | use SerialiseDepWrapperTrait; |
||||||
54 | use SerialisePropertyCacheTrait; |
||||||
55 | use SerialiseNavigationTrait; |
||||||
56 | use SerialiseNextPageLinksTrait; |
||||||
57 | |||||||
58 | /** |
||||||
59 | * Update time to insert into ODataEntry/ODataFeed fields. |
||||||
60 | * @var Carbon |
||||||
61 | */ |
||||||
62 | private $updated; |
||||||
63 | |||||||
64 | /** |
||||||
65 | * Has base URI already been written out during serialisation? |
||||||
66 | * @var bool |
||||||
67 | */ |
||||||
68 | private $isBaseWritten = false; |
||||||
69 | |||||||
70 | /** |
||||||
71 | * @param IService $service Reference to the data service instance |
||||||
72 | * @param RequestDescription|null $request Type instance describing the client submitted request |
||||||
73 | * @throws \Exception |
||||||
74 | */ |
||||||
75 | public function __construct(IService $service, RequestDescription $request = null) |
||||||
76 | { |
||||||
77 | $this->service = $service; |
||||||
78 | $this->request = $request; |
||||||
79 | $this->absoluteServiceUri = $service->getHost()->getAbsoluteServiceUri()->getUrlAsString(); |
||||||
80 | $this->absoluteServiceUriWithSlash = rtrim($this->absoluteServiceUri, '/') . '/'; |
||||||
81 | $this->stack = new SegmentStack($request); |
||||||
82 | $this->modelSerialiser = new ModelSerialiser(); |
||||||
83 | $this->updated = Carbon::now(); |
||||||
84 | } |
||||||
85 | |||||||
86 | /** |
||||||
87 | * Write a top level entry resource. |
||||||
88 | * |
||||||
89 | * @param QueryResult $entryObject Reference to the entry object to be written |
||||||
90 | * |
||||||
91 | * @throws InvalidOperationException |
||||||
92 | * @throws \ReflectionException |
||||||
93 | * @throws ODataException |
||||||
94 | * @return ODataEntry|null |
||||||
95 | */ |
||||||
96 | public function writeTopLevelElement(QueryResult $entryObject) |
||||||
97 | { |
||||||
98 | if (!isset($entryObject->results)) { |
||||||
99 | array_pop($this->lightStack); |
||||||
100 | return null; |
||||||
101 | } |
||||||
102 | |||||||
103 | SerialiserUtilities::checkSingleElementInput($entryObject); |
||||||
104 | |||||||
105 | $this->loadStackIfEmpty(); |
||||||
106 | $baseURI = $this->isBaseWritten ? null : $this->absoluteServiceUriWithSlash; |
||||||
107 | $this->isBaseWritten = true; |
||||||
108 | |||||||
109 | $stackCount = count($this->lightStack); |
||||||
110 | $topOfStack = $this->lightStack[$stackCount-1]; |
||||||
111 | /** @var object $res */ |
||||||
112 | $res = $entryObject->results; |
||||||
113 | $payloadClass = get_class($res); |
||||||
114 | /** @var ResourceEntityType $resourceType */ |
||||||
115 | $resourceType = $this->getService()->getProvidersWrapper()->resolveResourceType($topOfStack['type']); |
||||||
116 | |||||||
117 | // need gubbinz to unpack an abstract resource type |
||||||
118 | $resourceType = SerialiserUtilities::getConcreteTypeFromAbstractType( |
||||||
119 | $resourceType, |
||||||
120 | $this->getMetadata(), |
||||||
121 | $payloadClass |
||||||
122 | ); |
||||||
123 | |||||||
124 | // make sure we're barking up right tree |
||||||
125 | if (!$resourceType instanceof ResourceEntityType) { |
||||||
126 | throw new InvalidOperationException(get_class($resourceType)); |
||||||
127 | } |
||||||
128 | |||||||
129 | /** @var Model $res */ |
||||||
130 | $res = $entryObject->results; |
||||||
131 | $targClass = $resourceType->getInstanceType()->getName(); |
||||||
132 | if (!($res instanceof $targClass)) { |
||||||
133 | $msg = 'Object being serialised not instance of expected class, ' |
||||||
134 | . $targClass . ', is actually ' . $payloadClass; |
||||||
135 | throw new InvalidOperationException($msg); |
||||||
136 | } |
||||||
137 | |||||||
138 | $this->checkRelationPropertiesCached($targClass, $resourceType); |
||||||
139 | /** @var ResourceProperty[] $relProp */ |
||||||
140 | $relProp = $this->propertiesCache[$targClass]['rel']; |
||||||
141 | /** @var ResourceProperty[] $nonRelProp */ |
||||||
142 | $nonRelProp = $this->propertiesCache[$targClass]['nonRel']; |
||||||
143 | |||||||
144 | $resourceSet = $resourceType->getCustomState(); |
||||||
145 | if (!$resourceSet instanceof ResourceSet) { |
||||||
146 | throw new InvalidOperationException('Bad custom state on ResourceType'); |
||||||
147 | } |
||||||
148 | $title = $resourceType->getName(); |
||||||
149 | $type = $resourceType->getFullName(); |
||||||
150 | |||||||
151 | $relativeUri = SerialiserUtilities::getEntryInstanceKey( |
||||||
152 | $res, |
||||||
153 | $resourceType, |
||||||
154 | $resourceSet->getName() |
||||||
155 | ); |
||||||
156 | $absoluteUri = rtrim($this->absoluteServiceUri ?? '', '/') . '/' . $relativeUri; |
||||||
157 | |||||||
158 | /** var $mediaLink ODataMediaLink|null */ |
||||||
159 | $mediaLink = null; |
||||||
160 | /** var $mediaLinks ODataMediaLink[] */ |
||||||
161 | $mediaLinks = []; |
||||||
162 | $this->writeMediaData( |
||||||
163 | $res, |
||||||
164 | $type, |
||||||
165 | $relativeUri, |
||||||
166 | $resourceType, |
||||||
167 | $mediaLink, |
||||||
168 | $mediaLinks |
||||||
169 | ); |
||||||
170 | |||||||
171 | $propertyContent = SerialiserLowLevelWriters::writePrimitiveProperties( |
||||||
172 | $res, |
||||||
173 | $this->getModelSerialiser(), |
||||||
174 | $nonRelProp |
||||||
175 | ); |
||||||
176 | |||||||
177 | $links = $this->buildLinksFromRels($entryObject, $relProp, $relativeUri); |
||||||
178 | |||||||
179 | $odata = new ODataEntry(); |
||||||
180 | $odata->resourceSetName = $resourceSet->getName(); |
||||||
181 | $odata->setId($absoluteUri); |
||||||
182 | $odata->setTitle(new ODataTitle($title)); |
||||||
183 | $odata->type = new ODataCategory($type); |
||||||
184 | $odata->propertyContent = $propertyContent; |
||||||
185 | $odata->isMediaLinkEntry = $resourceType->isMediaLinkEntry(); |
||||||
186 | $odata->editLink = new ODataLink(); |
||||||
187 | $odata->editLink->setUrl($relativeUri); |
||||||
188 | $odata->editLink->setName('edit'); |
||||||
189 | $odata->editLink->setTitle($title); |
||||||
190 | $odata->mediaLink = $mediaLink; |
||||||
191 | $odata->mediaLinks = $mediaLinks; |
||||||
192 | $odata->links = $links; |
||||||
193 | $odata->setUpdated($this->getUpdated()->format(DATE_ATOM)); |
||||||
194 | $odata->setBaseURI($baseURI); |
||||||
195 | |||||||
196 | $newCount = count($this->lightStack); |
||||||
197 | if ($newCount != $stackCount) { |
||||||
198 | $msg = 'Should have ' . $stackCount . ' elements in stack, have ' . $newCount . ' elements'; |
||||||
199 | throw new InvalidOperationException($msg); |
||||||
200 | } |
||||||
201 | $this->updateLightStack($newCount); |
||||||
202 | return $odata; |
||||||
203 | } |
||||||
204 | |||||||
205 | /** |
||||||
206 | * Write top level feed element. |
||||||
207 | * |
||||||
208 | * @param QueryResult $entryObjects Array of entry resources to be written |
||||||
209 | * |
||||||
210 | * @throws InvalidOperationException |
||||||
211 | * @throws ODataException |
||||||
212 | * @throws \ReflectionException |
||||||
213 | * @return ODataFeed |
||||||
214 | */ |
||||||
215 | public function writeTopLevelElements(QueryResult &$entryObjects) |
||||||
216 | { |
||||||
217 | SerialiserUtilities::checkElementsInput($entryObjects); |
||||||
218 | |||||||
219 | $this->loadStackIfEmpty(); |
||||||
220 | |||||||
221 | /** @var string $title */ |
||||||
222 | $title = $this->getRequest()->getContainerName(); |
||||||
223 | $relativeUri = $this->getRequest()->getIdentifier(); |
||||||
224 | $absoluteUri = $this->getRequest()->getRequestUrl()->getUrlAsString(); |
||||||
225 | |||||||
226 | $selfLink = new ODataLink(); |
||||||
227 | $selfLink->setName('self'); |
||||||
228 | $selfLink->setTitle($relativeUri); |
||||||
229 | $selfLink->setUrl($relativeUri); |
||||||
230 | |||||||
231 | $odata = new ODataFeed(); |
||||||
232 | $odata->setTitle(new ODataTitle($title)); |
||||||
233 | $odata->id = $absoluteUri; |
||||||
234 | $odata->setSelfLink($selfLink); |
||||||
235 | $odata->setUpdated($this->getUpdated()->format(DATE_ATOM)); |
||||||
236 | $odata->setBaseURI($this->isBaseWritten ? null : $this->absoluteServiceUriWithSlash); |
||||||
237 | $this->isBaseWritten = true; |
||||||
238 | |||||||
239 | if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) { |
||||||
240 | $odata->setRowCount($this->getRequest()->getCountValue()); |
||||||
241 | } |
||||||
242 | $this->buildEntriesFromElements($entryObjects->results, $odata); |
||||||
243 | |||||||
244 | $resourceSet = $this->getRequest()->getTargetResourceSetWrapper()->getResourceSet(); |
||||||
245 | $requestTop = $this->getRequest()->getTopOptionCount(); |
||||||
246 | $pageSize = $this->getService()->getConfiguration()->getEntitySetPageSize($resourceSet); |
||||||
247 | $requestTop = (null === $requestTop) ? $pageSize+1 : $requestTop; |
||||||
248 | |||||||
249 | if (true == $entryObjects->hasMore && $requestTop > $pageSize) { |
||||||
250 | $this->buildNextPageLink($entryObjects, $odata); |
||||||
251 | } |
||||||
252 | |||||||
253 | return $odata; |
||||||
254 | } |
||||||
255 | |||||||
256 | /** |
||||||
257 | * Write top level url element. |
||||||
258 | * |
||||||
259 | * @param QueryResult $entryObject The entry resource whose url to be written |
||||||
260 | * |
||||||
261 | * @throws InvalidOperationException |
||||||
262 | * @throws ODataException |
||||||
263 | * @throws \ReflectionException |
||||||
264 | * @return ODataURL |
||||||
265 | */ |
||||||
266 | public function writeUrlElement(QueryResult $entryObject) |
||||||
267 | { |
||||||
268 | $url = new ODataURL(''); |
||||||
269 | /** @var Model|null $res */ |
||||||
270 | $res = $entryObject->results; |
||||||
271 | if (null !== $res) { |
||||||
272 | $currentResourceType = $this->getCurrentResourceSetWrapper()->getResourceType(); |
||||||
273 | $relativeUri = SerialiserUtilities::getEntryInstanceKey( |
||||||
274 | $res, |
||||||
275 | $currentResourceType, |
||||||
276 | $this->getCurrentResourceSetWrapper()->getName() |
||||||
277 | ); |
||||||
278 | |||||||
279 | $url->setUrl(rtrim($this->absoluteServiceUri, '/') . '/' . $relativeUri); |
||||||
280 | } |
||||||
281 | |||||||
282 | return $url; |
||||||
283 | } |
||||||
284 | |||||||
285 | /** |
||||||
286 | * Write top level url collection. |
||||||
287 | * |
||||||
288 | * @param QueryResult $entryObjects Array of entry resources whose url to be written |
||||||
289 | * |
||||||
290 | * @throws InvalidOperationException |
||||||
291 | * @throws ODataException |
||||||
292 | * @throws \ReflectionException |
||||||
293 | * @return ODataURLCollection |
||||||
294 | */ |
||||||
295 | public function writeUrlElements(QueryResult $entryObjects) |
||||||
296 | { |
||||||
297 | $urls = new ODataURLCollection(); |
||||||
298 | if (!empty($entryObjects->results)) { |
||||||
299 | $i = 0; |
||||||
300 | $lines = []; |
||||||
301 | foreach ($entryObjects->results as $entryObject) { |
||||||
302 | if (!$entryObject instanceof QueryResult) { |
||||||
303 | $query = new QueryResult(); |
||||||
304 | $query->results = $entryObject; |
||||||
305 | } else { |
||||||
306 | $query = $entryObject; |
||||||
307 | } |
||||||
308 | $lines[$i] = $this->writeUrlElement($query); |
||||||
309 | ++$i; |
||||||
310 | } |
||||||
311 | $urls->setUrls($lines); |
||||||
312 | |||||||
313 | if (true === $entryObjects->hasMore) { |
||||||
314 | $this->buildNextPageLink($entryObjects, $urls); |
||||||
315 | } |
||||||
316 | } |
||||||
317 | |||||||
318 | if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) { |
||||||
319 | $urls->setCount(intval($this->getRequest()->getCountValue())); |
||||||
320 | } |
||||||
321 | |||||||
322 | return $urls; |
||||||
323 | } |
||||||
324 | |||||||
325 | /** |
||||||
326 | * Write top level complex resource. |
||||||
327 | * |
||||||
328 | * @param QueryResult $complexValue The complex object to be written |
||||||
329 | * @param string $propertyName The name of the complex property |
||||||
330 | * @param ResourceType $resourceType Describes the type of complex object |
||||||
331 | * |
||||||
332 | * @throws InvalidOperationException |
||||||
333 | * @throws \ReflectionException |
||||||
334 | * @return ODataPropertyContent |
||||||
335 | */ |
||||||
336 | public function writeTopLevelComplexObject(QueryResult &$complexValue, $propertyName, ResourceType &$resourceType) |
||||||
337 | { |
||||||
338 | /** @var object $result */ |
||||||
339 | $result = $complexValue->results; |
||||||
340 | |||||||
341 | $propertyContent = new ODataPropertyContent([]); |
||||||
342 | $odataProperty = new ODataProperty($propertyName, $resourceType->getFullName(), null); |
||||||
343 | if (null != $result) { |
||||||
344 | $internalContent = SerialiserLowLevelWriters::writeComplexValue($resourceType, $result); |
||||||
345 | $odataProperty->setValue($internalContent); |
||||||
346 | } |
||||||
347 | |||||||
348 | $propertyContent[$propertyName] = $odataProperty; |
||||||
349 | |||||||
350 | return $propertyContent; |
||||||
351 | } |
||||||
352 | |||||||
353 | /** |
||||||
354 | * Write top level bag resource. |
||||||
355 | * |
||||||
356 | * @param QueryResult $BagValue The bag object to be |
||||||
357 | * written |
||||||
358 | * @param string $propertyName The name of the |
||||||
359 | * bag property |
||||||
360 | * @param ResourceType $resourceType Describes the type of |
||||||
361 | * bag object |
||||||
362 | * |
||||||
363 | * @throws InvalidOperationException |
||||||
364 | * @throws \ReflectionException |
||||||
365 | * @return ODataPropertyContent |
||||||
366 | */ |
||||||
367 | public function writeTopLevelBagObject(QueryResult &$BagValue, $propertyName, ResourceType &$resourceType) |
||||||
368 | { |
||||||
369 | /** @var mixed[]|null $result */ |
||||||
370 | $result = $BagValue->results; |
||||||
371 | |||||||
372 | $propertyContent = new ODataPropertyContent([]); |
||||||
373 | $odataProperty = new ODataProperty($propertyName, null, null); |
||||||
374 | $odataProperty->setTypeName('Collection(' . $resourceType->getFullName() . ')'); |
||||||
375 | $odataProperty->setValue(SerialiserLowLevelWriters::writeBagValue($resourceType, $result)); |
||||||
376 | |||||||
377 | $propertyContent[$propertyName] = $odataProperty; |
||||||
378 | return $propertyContent; |
||||||
379 | } |
||||||
380 | |||||||
381 | /** |
||||||
382 | * Write top level primitive value. |
||||||
383 | * |
||||||
384 | * @param QueryResult $primitiveValue The primitive value to be |
||||||
385 | * written |
||||||
386 | * @param ResourceProperty $resourceProperty Resource property describing the |
||||||
387 | * primitive property to be written |
||||||
388 | * @throws InvalidOperationException |
||||||
389 | * @throws \ReflectionException |
||||||
390 | * @return ODataPropertyContent |
||||||
391 | */ |
||||||
392 | public function writeTopLevelPrimitive(QueryResult &$primitiveValue, ResourceProperty &$resourceProperty = null) |
||||||
393 | { |
||||||
394 | if (null === $resourceProperty) { |
||||||
395 | throw new InvalidOperationException('Resource property must not be null'); |
||||||
396 | } |
||||||
397 | $propertyContent = new ODataPropertyContent([]); |
||||||
398 | |||||||
399 | $odataProperty = new ODataProperty($resourceProperty->getName(), null, null); |
||||||
400 | $iType = $resourceProperty->getInstanceType(); |
||||||
401 | if (!$iType instanceof IType) { |
||||||
402 | throw new InvalidOperationException(get_class($iType)); |
||||||
403 | } |
||||||
404 | $odataProperty->setTypeName($iType->getFullTypeName()); |
||||||
405 | $value = null; |
||||||
406 | if (null != $primitiveValue->results) { |
||||||
407 | $rType = $resourceProperty->getResourceType()->getInstanceType(); |
||||||
408 | if (!$rType instanceof IType) { |
||||||
409 | throw new InvalidOperationException(get_class($rType)); |
||||||
410 | } |
||||||
411 | $value = SerialiserLowLevelWriters::primitiveToString($rType, $primitiveValue->results); |
||||||
412 | } |
||||||
413 | $odataProperty->setValue($value); |
||||||
414 | |||||||
415 | $propertyContent[$odataProperty->getName()] = $odataProperty; |
||||||
416 | |||||||
417 | return $propertyContent; |
||||||
418 | } |
||||||
419 | |||||||
420 | /** |
||||||
421 | * Get update timestamp. |
||||||
422 | * |
||||||
423 | * @return Carbon |
||||||
424 | */ |
||||||
425 | public function getUpdated() |
||||||
426 | { |
||||||
427 | return $this->updated; |
||||||
428 | } |
||||||
429 | |||||||
430 | /** |
||||||
431 | * @param mixed $entryObject |
||||||
432 | * @param string $type |
||||||
433 | * @param string $relativeUri |
||||||
434 | * @param ResourceType $resourceType |
||||||
435 | * @param ODataMediaLink|null $mediaLink |
||||||
436 | * @param ODataMediaLink[] $mediaLinks |
||||||
437 | * @throws InvalidOperationException |
||||||
438 | * @return void |
||||||
439 | */ |
||||||
440 | protected function writeMediaData( |
||||||
441 | $entryObject, |
||||||
442 | $type, |
||||||
443 | $relativeUri, |
||||||
444 | ResourceType $resourceType, |
||||||
445 | ODataMediaLink &$mediaLink = null, |
||||||
446 | array &$mediaLinks = [] |
||||||
447 | ) { |
||||||
448 | $context = $this->getService()->getOperationContext(); |
||||||
449 | $streamProviderWrapper = $this->getService()->getStreamProviderWrapper(); |
||||||
450 | if (null == $streamProviderWrapper) { |
||||||
451 | throw new InvalidOperationException('Retrieved stream provider must not be null'); |
||||||
452 | } |
||||||
453 | |||||||
454 | /** @var ODataMediaLink|null $mediaLink */ |
||||||
455 | $mediaLink = null; |
||||||
456 | if ($resourceType->isMediaLinkEntry()) { |
||||||
457 | $eTag = $streamProviderWrapper->getStreamETag2($entryObject, $context, null); |
||||||
0 ignored issues
–
show
|
|||||||
458 | $mediaLink = new ODataMediaLink($type, '/$value', $relativeUri . '/$value', '*/*', $eTag, 'edit-media'); |
||||||
459 | } |
||||||
460 | /** @var ODataMediaLink[] $mediaLinks */ |
||||||
461 | $mediaLinks = []; |
||||||
462 | if ($resourceType->hasNamedStream()) { |
||||||
463 | $namedStreams = $resourceType->getAllNamedStreams(); |
||||||
464 | foreach ($namedStreams as $streamTitle => $resourceStreamInfo) { |
||||||
465 | $readUri = $streamProviderWrapper->getReadStreamUri2( |
||||||
0 ignored issues
–
show
The method
getReadStreamUri2() does not exist on POData\Providers\Stream\StreamProviderWrapper . Did you maybe mean getReadStreamUri() ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
466 | $entryObject, |
||||||
467 | $context, |
||||||
468 | $resourceStreamInfo, |
||||||
469 | $relativeUri |
||||||
470 | ); |
||||||
471 | $mediaContentType = $streamProviderWrapper->getStreamContentType2( |
||||||
0 ignored issues
–
show
The method
getStreamContentType2() does not exist on POData\Providers\Stream\StreamProviderWrapper . Did you maybe mean getStreamContentType() ?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
472 | $entryObject, |
||||||
473 | $context, |
||||||
474 | $resourceStreamInfo |
||||||
475 | ); |
||||||
476 | $eTag = $streamProviderWrapper->getStreamETag2( |
||||||
477 | $entryObject, |
||||||
478 | $context, |
||||||
479 | $resourceStreamInfo |
||||||
480 | ); |
||||||
481 | |||||||
482 | $nuLink = new ODataMediaLink($streamTitle, $readUri, $readUri, $mediaContentType, $eTag); |
||||||
483 | $mediaLinks[] = $nuLink; |
||||||
484 | } |
||||||
485 | } |
||||||
486 | } |
||||||
487 | |||||||
488 | /** |
||||||
489 | * @param QueryResult $entryObject |
||||||
490 | * @param ResourceProperty $prop |
||||||
491 | * @param ODataLink $nuLink |
||||||
492 | * @param ResourcePropertyKind $propKind |
||||||
493 | * @param string $propName |
||||||
494 | * @throws InvalidOperationException |
||||||
495 | * @throws ODataException |
||||||
496 | * @throws \ReflectionException |
||||||
497 | */ |
||||||
498 | private function expandNavigationProperty( |
||||||
499 | QueryResult $entryObject, |
||||||
500 | ResourceProperty $prop, |
||||||
501 | ODataLink $nuLink, |
||||||
502 | ResourcePropertyKind $propKind, |
||||||
503 | string $propName |
||||||
504 | ): void { |
||||||
505 | $nextName = $prop->getResourceType()->getName(); |
||||||
506 | $value = $entryObject->results->{$propName}; |
||||||
507 | $isCollection = ResourcePropertyKind::RESOURCESET_REFERENCE() == $propKind; |
||||||
508 | $nuLink->setIsCollection($isCollection); |
||||||
509 | |||||||
510 | if (is_array($value)) { |
||||||
511 | if (1 == count($value) && !$isCollection) { |
||||||
512 | $value = $value[0]; |
||||||
513 | } else { |
||||||
514 | $value = collect($value); |
||||||
515 | } |
||||||
516 | } |
||||||
517 | |||||||
518 | $result = new QueryResult(); |
||||||
519 | $result->results = $value; |
||||||
520 | $nullResult = null === $value; |
||||||
521 | $isSingleton = $value instanceof Model; |
||||||
522 | $resultCount = $nullResult ? 0 : ($isSingleton ? 1 : $value->count()); |
||||||
523 | |||||||
524 | if (0 < $resultCount) { |
||||||
525 | $newStackLine = ['type' => $nextName, 'prop' => $propName, 'count' => $resultCount]; |
||||||
526 | array_push($this->lightStack, $newStackLine); |
||||||
527 | if (!$isCollection) { |
||||||
528 | $type = 'application/atom+xml;type=entry'; |
||||||
529 | $expandedResult = $this->writeTopLevelElement($result); |
||||||
530 | } else { |
||||||
531 | $type = 'application/atom+xml;type=feed'; |
||||||
532 | $expandedResult = $this->writeTopLevelElements($result); |
||||||
533 | } |
||||||
534 | $nuLink->setType($type); |
||||||
535 | $nuLink->setExpandedResult(new ODataExpandedResult($expandedResult)); |
||||||
0 ignored issues
–
show
It seems like
$expandedResult can also be of type null ; however, parameter $data of POData\ObjectModel\OData...edResult::__construct() does only seem to accept POData\ObjectModel\ODataContainerBase , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
536 | } else { |
||||||
537 | /** @var ResourceType $type */ |
||||||
538 | $type = $this->getService()->getProvidersWrapper()->resolveResourceType($nextName); |
||||||
539 | if (!$isCollection) { |
||||||
540 | $result = new ODataEntry(); |
||||||
541 | $result->resourceSetName = $type->getName(); |
||||||
542 | } else { |
||||||
543 | $result = new ODataFeed(); |
||||||
544 | $result->setSelfLink(new ODataLink(ODataConstants::ATOM_SELF_RELATION_ATTRIBUTE_VALUE)); |
||||||
545 | } |
||||||
546 | $nuLink->setExpandedResult(new ODataExpandedResult($result)); |
||||||
547 | } |
||||||
548 | if (null !== $nuLink->getExpandedResult() && null !== $nuLink->getExpandedResult()->getData()->getSelfLink()) { |
||||||
549 | $url = $nuLink->getUrl(); |
||||||
550 | $raw = $nuLink->getExpandedResult()->getData(); |
||||||
551 | |||||||
552 | $raw->getSelfLink()->setTitle($propName); |
||||||
553 | $raw->getSelfLink()->setUrl($url); |
||||||
554 | $raw->setTitle(new ODataTitle($propName)); |
||||||
555 | $raw->setId(rtrim($this->absoluteServiceUri ?? '', '/') . '/' . $url); |
||||||
556 | |||||||
557 | if ($raw instanceof ODataEntry) { |
||||||
558 | $nuLink->getExpandedResult()->setEntry($raw); |
||||||
559 | } else { |
||||||
560 | $nuLink->getExpandedResult()->setFeed($raw); |
||||||
561 | } |
||||||
562 | } |
||||||
563 | } |
||||||
564 | |||||||
565 | /** |
||||||
566 | * @param QueryResult $entryObject |
||||||
567 | * @param ResourceProperty[] $relProp |
||||||
568 | * @param string $relativeUri |
||||||
569 | * @throws InvalidOperationException |
||||||
570 | * @throws ODataException |
||||||
571 | * @throws \ReflectionException |
||||||
572 | * @return ODataLink[] |
||||||
573 | */ |
||||||
574 | protected function buildLinksFromRels(QueryResult $entryObject, array $relProp, string $relativeUri): array |
||||||
575 | { |
||||||
576 | $links = []; |
||||||
577 | foreach ($relProp as $prop) { |
||||||
578 | $nuLink = new ODataLink(); |
||||||
579 | /** @var ResourcePropertyKind|int $propKind */ |
||||||
580 | $propKind = $prop->getKind(); |
||||||
581 | |||||||
582 | if (!(ResourcePropertyKind::RESOURCESET_REFERENCE() == $propKind |
||||||
583 | || ResourcePropertyKind::RESOURCE_REFERENCE() == $propKind)) { |
||||||
584 | $msg = '$propKind != ResourcePropertyKind::RESOURCESET_REFERENCE &&' |
||||||
585 | . ' $propKind != ResourcePropertyKind::RESOURCE_REFERENCE'; |
||||||
586 | throw new InvalidOperationException($msg); |
||||||
587 | } |
||||||
588 | $propTail = ResourcePropertyKind::RESOURCE_REFERENCE() == $propKind ? 'entry' : 'feed'; |
||||||
589 | $propType = 'application/atom+xml;type=' . $propTail; |
||||||
590 | $propName = $prop->getName(); |
||||||
591 | $nuLink->setTitle($propName); |
||||||
592 | $nuLink->setName(ODataConstants::ODATA_RELATED_NAMESPACE . $propName); |
||||||
593 | $nuLink->setUrl($relativeUri . '/' . $propName); |
||||||
594 | $nuLink->setType($propType); |
||||||
595 | $nuLink->setIsCollection('feed' === $propTail); |
||||||
596 | |||||||
597 | $shouldExpand = $this->shouldExpandSegment($propName); |
||||||
598 | |||||||
599 | if ($shouldExpand) { |
||||||
600 | $this->expandNavigationProperty($entryObject, $prop, $nuLink, $propKind, $propName); |
||||||
601 | } |
||||||
602 | $links[] = $nuLink; |
||||||
603 | } |
||||||
604 | return $links; |
||||||
605 | } |
||||||
606 | |||||||
607 | /** |
||||||
608 | * @param object[]|Collection $res |
||||||
609 | * @param ODataFeed $odata |
||||||
610 | * @throws InvalidOperationException |
||||||
611 | * @throws ODataException |
||||||
612 | * @throws \ReflectionException |
||||||
613 | */ |
||||||
614 | protected function buildEntriesFromElements($res, ODataFeed $odata): void |
||||||
615 | { |
||||||
616 | foreach ($res as $entry) { |
||||||
617 | if (!$entry instanceof QueryResult) { |
||||||
618 | $query = new QueryResult(); |
||||||
619 | $query->results = $entry; |
||||||
620 | } else { |
||||||
621 | $query = $entry; |
||||||
622 | } |
||||||
623 | $odata->addEntry($this->writeTopLevelElement($query)); |
||||||
0 ignored issues
–
show
It seems like
$this->writeTopLevelElement($query) can also be of type null ; however, parameter $entry of POData\ObjectModel\ODataFeed::addEntry() does only seem to accept POData\ObjectModel\ODataEntry , maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
624 | } |
||||||
625 | //$odata->setEntries($entries); |
||||||
626 | } |
||||||
627 | } |
||||||
628 |
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.
This is most likely a typographical error or the method has been renamed.