IronicSerialiser   C
last analyzed

Complexity

Total Complexity 57

Size/Duplication

Total Lines 573
Duplicated Lines 0 %

Importance

Changes 21
Bugs 0 Features 0
Metric Value
wmc 57
eloc 275
c 21
b 0
f 0
dl 0
loc 573
rs 5.04

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 1
A getUpdated() 0 3 1
A writeTopLevelBagObject() 0 12 1
B writeTopLevelElements() 0 39 6
B buildLinksFromRels() 0 31 6
C expandNavigationProperty() 0 63 12
A writeTopLevelComplexObject() 0 15 2
A writeUrlElements() 0 28 6
A writeMediaData() 0 44 5
A buildEntriesFromElements() 0 10 3
A writeTopLevelPrimitive() 0 26 5
B writeTopLevelElement() 0 107 7
A writeUrlElement() 0 17 2

How to fix   Complexity   

Complex Class

Complex classes like IronicSerialiser often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use IronicSerialiser, and based on these observations, apply Extract Interface, too.

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
Bug introduced by
The method getStreamETag2() does not exist on POData\Providers\Stream\StreamProviderWrapper. Did you maybe mean getStreamETag()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

457
            /** @scrutinizer ignore-call */ 
458
            $eTag      = $streamProviderWrapper->getStreamETag2($entryObject, $context, null);

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.

Loading history...
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
Bug introduced by
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 ignore-call  annotation

465
                /** @scrutinizer ignore-call */ 
466
                $readUri = $streamProviderWrapper->getReadStreamUri2(

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.

Loading history...
466
                    $entryObject,
467
                    $context,
468
                    $resourceStreamInfo,
469
                    $relativeUri
470
                );
471
                $mediaContentType = $streamProviderWrapper->getStreamContentType2(
0 ignored issues
show
Bug introduced by
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 ignore-call  annotation

471
                /** @scrutinizer ignore-call */ 
472
                $mediaContentType = $streamProviderWrapper->getStreamContentType2(

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.

Loading history...
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
Bug introduced by
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 ignore-type  annotation

535
            $nuLink->setExpandedResult(new ODataExpandedResult(/** @scrutinizer ignore-type */ $expandedResult));
Loading history...
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
Bug introduced by
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 ignore-type  annotation

623
            $odata->addEntry(/** @scrutinizer ignore-type */ $this->writeTopLevelElement($query));
Loading history...
624
        }
625
        //$odata->setEntries($entries);
626
    }
627
}
628