Completed
Push — master ( 2e5c05...c5380b )
by Christopher
28s queued 11s
created

IronicSerialiser::writeTopLevelBagObject()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 8
dl 0
loc 12
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 3
1
<?php declare(strict_types=1);
2
3
namespace AlgoWeb\PODataLaravel\Serialisers;
4
5
use Carbon\Carbon;
6
use Illuminate\Database\Eloquent\Model;
7
use Illuminate\Support\Collection;
8
use Illuminate\Support\Facades\App;
9
use POData\Common\InvalidOperationException;
10
use POData\Common\Messages;
11
use POData\Common\ODataConstants;
12
use POData\Common\ODataException;
13
use POData\IService;
14
use POData\ObjectModel\IObjectSerialiser;
15
use POData\ObjectModel\ODataBagContent;
16
use POData\ObjectModel\ODataCategory;
17
use POData\ObjectModel\ODataEntry;
18
use POData\ObjectModel\ODataFeed;
19
use POData\ObjectModel\ODataLink;
20
use POData\ObjectModel\ODataMediaLink;
21
use POData\ObjectModel\ODataNavigationPropertyInfo;
22
use POData\ObjectModel\ODataProperty;
23
use POData\ObjectModel\ODataPropertyContent;
24
use POData\ObjectModel\ODataTitle;
25
use POData\ObjectModel\ODataURL;
26
use POData\ObjectModel\ODataURLCollection;
27
use POData\Providers\Metadata\IMetadataProvider;
28
use POData\Providers\Metadata\ResourceEntityType;
29
use POData\Providers\Metadata\ResourceProperty;
30
use POData\Providers\Metadata\ResourcePropertyKind;
31
use POData\Providers\Metadata\ResourceSet;
32
use POData\Providers\Metadata\ResourceSetWrapper;
33
use POData\Providers\Metadata\ResourceType;
34
use POData\Providers\Metadata\ResourceTypeKind;
35
use POData\Providers\Metadata\Type\Binary;
36
use POData\Providers\Metadata\Type\Boolean;
37
use POData\Providers\Metadata\Type\DateTime;
38
use POData\Providers\Metadata\Type\IType;
39
use POData\Providers\Metadata\Type\StringType;
40
use POData\Providers\Query\QueryResult;
41
use POData\Providers\Query\QueryType;
42
use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ExpandedProjectionNode;
43
use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ProjectionNode;
44
use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\RootProjectionNode;
45
use POData\UriProcessor\QueryProcessor\OrderByParser\InternalOrderByInfo;
46
use POData\UriProcessor\RequestDescription;
47
use POData\UriProcessor\SegmentStack;
48
49
class IronicSerialiser implements IObjectSerialiser
50
{
51
    use SerialiseDepWrapperTrait;
52
    use SerialisePropertyCacheTrait;
53
    use SerialiseNavigationTrait;
54
    use SerialiseNextPageLinksTrait;
55
56
    /**
57
     * Update time to insert into ODataEntry/ODataFeed fields.
58
     * @var Carbon
59
     */
60
    private $updated;
61
62
    /**
63
     * Has base URI already been written out during serialisation?
64
     * @var bool
65
     */
66
    private $isBaseWritten = false;
67
68
    /**
69
     * @param  IService                $service Reference to the data service instance
70
     * @param  RequestDescription|null $request Type instance describing the client submitted request
71
     * @throws \Exception
72
     */
73
    public function __construct(IService $service, RequestDescription $request = null)
74
    {
75
        $this->service                     = $service;
76
        $this->request                     = $request;
77
        $this->absoluteServiceUri          = $service->getHost()->getAbsoluteServiceUri()->getUrlAsString();
78
        $this->absoluteServiceUriWithSlash = rtrim($this->absoluteServiceUri, '/') . '/';
79
        $this->stack                       = new SegmentStack($request);
80
        $this->modelSerialiser             = new ModelSerialiser();
81
        $this->updated                     = Carbon::now();
82
    }
83
84
    /**
85
     * Write a top level entry resource.
86
     *
87
     * @param QueryResult $entryObject Reference to the entry object to be written
88
     *
89
     * @throws InvalidOperationException
90
     * @throws \ReflectionException
91
     * @throws ODataException
92
     * @return ODataEntry|null
93
     */
94
    public function writeTopLevelElement(QueryResult $entryObject)
95
    {
96
        if (!isset($entryObject->results)) {
97
            array_pop($this->lightStack);
98
            return null;
99
        }
100
        SerialiserUtilities::checkSingleElementInput($entryObject);
101
102
        $this->loadStackIfEmpty();
103
        $baseURI             = $this->isBaseWritten ? null : $this->absoluteServiceUriWithSlash;
104
        $this->isBaseWritten = true;
105
106
        $stackCount = count($this->lightStack);
107
        $topOfStack = $this->lightStack[$stackCount-1];
108
        /** @var object $res */
109
        $res          = $entryObject->results;
110
        $payloadClass = get_class($res);
111
        /** @var ResourceEntityType $resourceType */
112
        $resourceType = $this->getService()->getProvidersWrapper()->resolveResourceType($topOfStack['type']);
113
114
        // need gubbinz to unpack an abstract resource type
115
        $resourceType = SerialiserUtilities::getConcreteTypeFromAbstractType(
116
            $resourceType,
117
            $this->getMetadata(),
118
            $payloadClass
119
        );
120
121
        // make sure we're barking up right tree
122
        if (!$resourceType instanceof ResourceEntityType) {
123
            throw new InvalidOperationException(get_class($resourceType));
124
        }
125
126
        /** @var Model $res */
127
        $res       = $entryObject->results;
128
        $targClass = $resourceType->getInstanceType()->getName();
129
        if (!($res instanceof $targClass)) {
130
            $msg = 'Object being serialised not instance of expected class, '
131
                   . $targClass . ', is actually ' . $payloadClass;
132
            throw new InvalidOperationException($msg);
133
        }
134
135
        $this->checkRelationPropertiesCached($targClass, $resourceType);
136
        /** @var ResourceProperty[] $relProp */
137
        $relProp = $this->propertiesCache[$targClass]['rel'];
138
        /** @var ResourceProperty[] $nonRelProp */
139
        $nonRelProp = $this->propertiesCache[$targClass]['nonRel'];
140
141
        $resourceSet = $resourceType->getCustomState();
142
        if (!$resourceSet instanceof ResourceSet) {
143
            throw new InvalidOperationException('');
144
        }
145
        $title = $resourceType->getName();
146
        $type  = $resourceType->getFullName();
147
148
        $relativeUri = SerialiserUtilities::getEntryInstanceKey(
149
            $res,
150
            $resourceType,
151
            $resourceSet->getName()
152
        );
153
        $absoluteUri = rtrim($this->absoluteServiceUri ?? '', '/') . '/' . $relativeUri;
154
155
        /** var $mediaLink ODataMediaLink|null */
156
        $mediaLink = null;
157
        /** var $mediaLinks ODataMediaLink[] */
158
        $mediaLinks = [];
159
        $this->writeMediaData(
160
            $res,
161
            $type,
162
            $relativeUri,
163
            $resourceType,
164
            $mediaLink,
165
            $mediaLinks
166
        );
167
168
        $propertyContent = SerialiserLowLevelWriters::writePrimitiveProperties(
169
            $res,
170
            $this->getModelSerialiser(),
171
            $nonRelProp
172
        );
173
174
        $links = $this->buildLinksFromRels($entryObject, $relProp, $relativeUri);
175
176
        $odata                   = new ODataEntry();
177
        $odata->resourceSetName  = $resourceSet->getName();
178
        $odata->id               = $absoluteUri;
179
        $odata->title            = new ODataTitle($title);
180
        $odata->type             = new ODataCategory($type);
181
        $odata->propertyContent  = $propertyContent;
182
        $odata->isMediaLinkEntry = $resourceType->isMediaLinkEntry();
183
        $odata->editLink         = new ODataLink();
184
        $odata->editLink->url    = $relativeUri;
185
        $odata->editLink->name   = 'edit';
186
        $odata->editLink->title  = $title;
187
        $odata->mediaLink        = $mediaLink;
188
        $odata->mediaLinks       = $mediaLinks;
189
        $odata->links            = $links;
190
        $odata->updated          = $this->getUpdated()->format(DATE_ATOM);
191
        $odata->baseURI          = $baseURI;
192
193
        $newCount = count($this->lightStack);
194
        if ($newCount != $stackCount) {
195
            $msg = 'Should have ' . $stackCount . ' elements in stack, have ' . $newCount . ' elements';
196
            throw new InvalidOperationException($msg);
197
        }
198
        $this->updateLightStack($newCount);
199
        return $odata;
200
    }
201
202
    /**
203
     * Write top level feed element.
204
     *
205
     * @param QueryResult &$entryObjects Array of entry resources to be written
206
     *
207
     * @throws InvalidOperationException
208
     * @throws ODataException
209
     * @throws \ReflectionException
210
     * @return ODataFeed
211
     */
212
    public function writeTopLevelElements(QueryResult &$entryObjects)
213
    {
214
        SerialiserUtilities::checkElementsInput($entryObjects);
215
216
        $this->loadStackIfEmpty();
217
218
        $title       = $this->getRequest()->getContainerName();
219
        $relativeUri = $this->getRequest()->getIdentifier();
220
        $absoluteUri = $this->getRequest()->getRequestUrl()->getUrlAsString();
221
222
        $selfLink        = new ODataLink();
223
        $selfLink->name  = 'self';
224
        $selfLink->title = $relativeUri;
225
        $selfLink->url   = $relativeUri;
226
227
        $odata               = new ODataFeed();
228
        $odata->title        = new ODataTitle($title);
229
        $odata->id           = $absoluteUri;
230
        $odata->selfLink     = $selfLink;
231
        $odata->updated      = $this->getUpdated()->format(DATE_ATOM);
232
        $odata->baseURI      = $this->isBaseWritten ? null : $this->absoluteServiceUriWithSlash;
233
        $this->isBaseWritten = true;
234
235
        if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) {
236
            $odata->rowCount = $this->getRequest()->getCountValue();
237
        }
238
        $this->buildEntriesFromElements($entryObjects->results, $odata);
239
240
        $resourceSet = $this->getRequest()->getTargetResourceSetWrapper()->getResourceSet();
241
        $requestTop  = $this->getRequest()->getTopOptionCount();
242
        $pageSize    = $this->getService()->getConfiguration()->getEntitySetPageSize($resourceSet);
243
        $requestTop  = (null === $requestTop) ? $pageSize+1 : $requestTop;
244
245
        if (true === $entryObjects->hasMore && $requestTop > $pageSize) {
246
            $this->buildNextPageLink($entryObjects, $odata);
247
        }
248
249
        return $odata;
250
    }
251
252
    /**
253
     * Write top level url element.
254
     *
255
     * @param QueryResult $entryObject The entry resource whose url to be written
256
     *
257
     * @throws InvalidOperationException
258
     * @throws ODataException
259
     * @throws \ReflectionException
260
     * @return ODataURL
261
     */
262
    public function writeUrlElement(QueryResult $entryObject)
263
    {
264
        $url = new ODataURL();
265
        /** @var Model|null $res */
266
        $res = $entryObject->results;
267
        if (null !== $res) {
268
            $currentResourceType = $this->getCurrentResourceSetWrapper()->getResourceType();
269
            $relativeUri         = SerialiserUtilities::getEntryInstanceKey(
270
                $res,
271
                $currentResourceType,
272
                $this->getCurrentResourceSetWrapper()->getName()
273
            );
274
275
            $url->url = rtrim($this->absoluteServiceUri, '/') . '/' . $relativeUri;
276
        }
277
278
        return $url;
279
    }
280
281
    /**
282
     * Write top level url collection.
283
     *
284
     * @param QueryResult $entryObjects Array of entry resources whose url to be written
285
     *
286
     * @throws InvalidOperationException
287
     * @throws ODataException
288
     * @throws \ReflectionException
289
     * @return ODataURLCollection
290
     */
291
    public function writeUrlElements(QueryResult $entryObjects)
292
    {
293
        $urls = new ODataURLCollection();
294
        if (!empty($entryObjects->results)) {
295
            $i = 0;
296
            foreach ($entryObjects->results as $entryObject) {
297
                if (!$entryObject instanceof QueryResult) {
298
                    $query          = new QueryResult();
299
                    $query->results = $entryObject;
300
                } else {
301
                    $query = $entryObject;
302
                }
303
                $urls->urls[$i] = $this->writeUrlElement($query);
304
                ++$i;
305
            }
306
307
            if ($i > 0 && true === $entryObjects->hasMore) {
308
                $this->buildNextPageLink($entryObjects, $urls);
309
            }
310
        }
311
312
        if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) {
313
            $urls->count = $this->getRequest()->getCountValue();
314
        }
315
316
        return $urls;
317
    }
318
319
    /**
320
     * Write top level complex resource.
321
     *
322
     * @param QueryResult  &$complexValue The complex object to be written
323
     * @param string       $propertyName  The name of the complex property
324
     * @param ResourceType &$resourceType Describes the type of complex object
325
     *
326
     * @throws InvalidOperationException
327
     * @throws \ReflectionException
328
     * @return ODataPropertyContent
329
     */
330
    public function writeTopLevelComplexObject(QueryResult &$complexValue, $propertyName, ResourceType &$resourceType)
331
    {
332
        /** @var object $result */
333
        $result = $complexValue->results;
334
335
        $propertyContent         = new ODataPropertyContent();
336
        $odataProperty           = new ODataProperty();
337
        $odataProperty->name     = $propertyName;
338
        $odataProperty->typeName = $resourceType->getFullName();
339
        if (null != $result) {
340
            $internalContent      = SerialiserLowLevelWriters::writeComplexValue($resourceType, $result);
341
            $odataProperty->value = $internalContent;
342
        }
343
344
        $propertyContent->properties[$propertyName] = $odataProperty;
345
346
        return $propertyContent;
347
    }
348
349
    /**
350
     * Write top level bag resource.
351
     *
352
     * @param QueryResult  &$BagValue     The bag object to be
353
     *                                    written
354
     * @param string       $propertyName  The name of the
355
     *                                    bag property
356
     * @param ResourceType &$resourceType Describes the type of
357
     *                                    bag object
358
     *
359
     * @throws InvalidOperationException
360
     * @throws \ReflectionException
361
     * @return ODataPropertyContent
362
     */
363
    public function writeTopLevelBagObject(QueryResult &$BagValue, $propertyName, ResourceType &$resourceType)
364
    {
365
        $result = $BagValue->results;
366
367
        $propertyContent         = new ODataPropertyContent();
368
        $odataProperty           = new ODataProperty();
369
        $odataProperty->name     = $propertyName;
370
        $odataProperty->typeName = 'Collection(' . $resourceType->getFullName() . ')';
371
        $odataProperty->value    = SerialiserLowLevelWriters::writeBagValue($resourceType, $result);
372
373
        $propertyContent->properties[$propertyName] = $odataProperty;
374
        return $propertyContent;
375
    }
376
377
    /**
378
     * Write top level primitive value.
379
     *
380
     * @param  QueryResult               &$primitiveValue   The primitive value to be
381
     *                                                      written
382
     * @param  ResourceProperty          &$resourceProperty Resource property describing the
383
     *                                                      primitive property to be written
384
     * @throws InvalidOperationException
385
     * @throws \ReflectionException
386
     * @return ODataPropertyContent
387
     */
388
    public function writeTopLevelPrimitive(QueryResult &$primitiveValue, ResourceProperty &$resourceProperty = null)
389
    {
390
        if (null === $resourceProperty) {
391
            throw new InvalidOperationException('Resource property must not be null');
392
        }
393
        $propertyContent = new ODataPropertyContent();
394
395
        $odataProperty       = new ODataProperty();
396
        $odataProperty->name = $resourceProperty->getName();
397
        $iType               = $resourceProperty->getInstanceType();
398
        if (!$iType instanceof IType) {
399
            throw new InvalidOperationException(get_class($iType));
400
        }
401
        $odataProperty->typeName = $iType->getFullTypeName();
402
        if (null == $primitiveValue->results) {
403
            $odataProperty->value = null;
404
        } else {
405
            $rType = $resourceProperty->getResourceType()->getInstanceType();
406
            if (!$rType instanceof IType) {
407
                throw new InvalidOperationException(get_class($rType));
408
            }
409
            $odataProperty->value = SerialiserLowLevelWriters::primitiveToString($rType, $primitiveValue->results);
410
        }
411
412
        $propertyContent->properties[$odataProperty->name] = $odataProperty;
413
414
        return $propertyContent;
415
    }
416
417
    /**
418
     * Get update timestamp.
419
     *
420
     * @return Carbon
421
     */
422
    public function getUpdated()
423
    {
424
        return $this->updated;
425
    }
426
427
    /**
428
     * @param $entryObject
429
     * @param $type
430
     * @param $relativeUri
431
     * @param  ResourceType              $resourceType
432
     * @param  ODataMediaLink|null       $mediaLink
433
     * @param  ODataMediaLink[]          $mediaLinks
434
     * @throws InvalidOperationException
435
     * @return void
436
     */
437
    protected function writeMediaData(
438
        $entryObject,
439
        $type,
440
        $relativeUri,
441
        ResourceType $resourceType,
442
        ODataMediaLink &$mediaLink = null,
443
        array &$mediaLinks = []
444
    ) {
445
        $context               = $this->getService()->getOperationContext();
446
        $streamProviderWrapper = $this->getService()->getStreamProviderWrapper();
447
        if (null == $streamProviderWrapper) {
448
            throw new InvalidOperationException('Retrieved stream provider must not be null');
449
        }
450
451
        /** @var ODataMediaLink|null $mediaLink */
452
        $mediaLink = null;
453
        if ($resourceType->isMediaLinkEntry()) {
454
            $eTag      = $streamProviderWrapper->getStreamETag2($entryObject, null, $context);
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

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

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...
455
            $mediaLink = new ODataMediaLink($type, '/$value', $relativeUri . '/$value', '*/*', $eTag, 'edit-media');
456
        }
457
        /** @var ODataMediaLink[] $mediaLinks */
458
        $mediaLinks = [];
459
        if ($resourceType->hasNamedStream()) {
460
            $namedStreams = $resourceType->getAllNamedStreams();
461
            foreach ($namedStreams as $streamTitle => $resourceStreamInfo) {
462
                $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

462
                /** @scrutinizer ignore-call */ 
463
                $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...
463
                    $entryObject,
464
                    $resourceStreamInfo,
465
                    $context,
466
                    $relativeUri
467
                );
468
                $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

468
                /** @scrutinizer ignore-call */ 
469
                $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...
469
                    $entryObject,
470
                    $resourceStreamInfo,
471
                    $context
472
                );
473
                $eTag = $streamProviderWrapper->getStreamETag2(
474
                    $entryObject,
475
                    $resourceStreamInfo,
476
                    $context
477
                );
478
479
                $nuLink       = new ODataMediaLink($streamTitle, $readUri, $readUri, $mediaContentType, $eTag);
480
                $mediaLinks[] = $nuLink;
481
            }
482
        }
483
    }
484
485
    /**
486
     * @param  QueryResult               $entryObject
487
     * @param  ResourceProperty          $prop
488
     * @param  OdataLink                 $nuLink
489
     * @param  int                       $propKind
490
     * @param  string                    $propName
491
     * @throws InvalidOperationException
492
     * @throws ODataException
493
     * @throws \ReflectionException
494
     */
495
    private function expandNavigationProperty(
496
        QueryResult $entryObject,
497
        ResourceProperty $prop,
498
        ODataLink $nuLink,
499
        int $propKind,
500
        string $propName
501
    ) {
502
        $nextName             = $prop->getResourceType()->getName();
503
        $value                = $entryObject->results->{$propName};
504
        $isCollection         = ResourcePropertyKind::RESOURCESET_REFERENCE == $propKind;
505
        $nuLink->isCollection = $isCollection;
506
507
        if (is_array($value)) {
508
            if (1 == count($value) && !$isCollection) {
509
                $value = $value[0];
510
            } else {
511
                $value = collect($value);
512
            }
513
        }
514
515
        $result          = new QueryResult();
516
        $result->results = $value;
517
        $nullResult      = null === $value;
518
        $isSingleton     = $value instanceof Model;
519
        $resultCount     = $nullResult ? 0 : ($isSingleton ? 1 : $value->count());
520
521
        if (0 < $resultCount) {
522
            $newStackLine = ['type' => $nextName, 'prop' => $propName, 'count' => $resultCount];
523
            array_push($this->lightStack, $newStackLine);
524
            if (!$isCollection) {
525
                $nuLink->type   = 'application/atom+xml;type=entry';
526
                $expandedResult = $this->writeTopLevelElement($result);
527
            } else {
528
                $nuLink->type   = 'application/atom+xml;type=feed';
529
                $expandedResult = $this->writeTopLevelElements($result);
530
            }
531
            $nuLink->expandedResult = $expandedResult;
532
        } else {
533
            $type = $this->getService()->getProvidersWrapper()->resolveResourceType($nextName);
534
            if (!$isCollection) {
535
                $result                  = new ODataEntry();
536
                $result->resourceSetName = $type->getName();
537
            } else {
538
                $result                 = new ODataFeed();
539
                $result->selfLink       = new ODataLink();
540
                $result->selfLink->name = ODataConstants::ATOM_SELF_RELATION_ATTRIBUTE_VALUE;
541
            }
542
            $nuLink->expandedResult = $result;
543
        }
544
        if (isset($nuLink->expandedResult->selfLink)) {
545
            $nuLink->expandedResult->selfLink->title = $propName;
546
            $nuLink->expandedResult->selfLink->url   = $nuLink->url;
547
            $nuLink->expandedResult->title           = new ODataTitle($propName);
548
            $nuLink->expandedResult->id              = rtrim($this->absoluteServiceUri ?? '', '/') . '/' . $nuLink->url;
549
        }
550
    }
551
552
    /**
553
     * @param  QueryResult               $entryObject
554
     * @param  ResourceProperty[]        $relProp
555
     * @param  string                    $relativeUri
556
     * @throws InvalidOperationException
557
     * @throws ODataException
558
     * @throws \ReflectionException
559
     * @return array
560
     */
561
    protected function buildLinksFromRels(QueryResult $entryObject, array $relProp, string $relativeUri) : array
562
    {
563
        $links = [];
564
        foreach ($relProp as $prop) {
565
            $nuLink   = new ODataLink();
566
            /** @var ResourcePropertyKind|int $propKind */
567
            $propKind = $prop->getKind();
568
569
            if (!(ResourcePropertyKind::RESOURCESET_REFERENCE == $propKind
570
                  || ResourcePropertyKind::RESOURCE_REFERENCE == $propKind)) {
571
                $msg = '$propKind != ResourcePropertyKind::RESOURCESET_REFERENCE &&'
572
                       . ' $propKind != ResourcePropertyKind::RESOURCE_REFERENCE';
573
                throw new InvalidOperationException($msg);
574
            }
575
            $propTail             = ResourcePropertyKind::RESOURCE_REFERENCE == $propKind ? 'entry' : 'feed';
576
            $propType             = 'application/atom+xml;type=' . $propTail;
577
            $propName             = $prop->getName();
578
            $nuLink->title        = $propName;
579
            $nuLink->name         = ODataConstants::ODATA_RELATED_NAMESPACE . $propName;
580
            $nuLink->url          = $relativeUri . '/' . $propName;
581
            $nuLink->type         = $propType;
582
            $nuLink->isCollection = 'feed' === $propTail;
583
584
            $shouldExpand = $this->shouldExpandSegment($propName);
585
586
            $navProp = new ODataNavigationPropertyInfo($prop, $shouldExpand);
587
            if ($navProp->expanded) {
588
                $this->expandNavigationProperty($entryObject, $prop, $nuLink, $propKind, $propName);
0 ignored issues
show
Bug introduced by
$propKind of type void is incompatible with the type integer expected by parameter $propKind of AlgoWeb\PODataLaravel\Se...andNavigationProperty(). ( Ignorable by Annotation )

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

588
                $this->expandNavigationProperty($entryObject, $prop, $nuLink, /** @scrutinizer ignore-type */ $propKind, $propName);
Loading history...
589
            }
590
            $nuLink->isExpanded = isset($nuLink->expandedResult);
591
            $links[] = $nuLink;
592
        }
593
        return $links;
594
    }
595
596
    /**
597
     * @param  array|object              $res
598
     * @param  ODataFeed                 $odata
599
     * @throws InvalidOperationException
600
     * @throws ODataException
601
     * @throws \ReflectionException
602
     */
603
    protected function buildEntriesFromElements($res, ODataFeed $odata)
604
    {
605
        foreach ($res as $entry) {
606
            if (!$entry instanceof QueryResult) {
607
                $query          = new QueryResult();
608
                $query->results = $entry;
609
            } else {
610
                $query = $entry;
611
            }
612
            $odata->entries[] = $this->writeTopLevelElement($query);
613
        }
614
    }
615
}
616