Test Setup Failed
Pull Request — master (#63)
by Alex
02:52
created

IronicSerialiser::primitiveToString()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 16
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 16
rs 8.2222
cc 7
eloc 12
nc 6
nop 2
1
<?php
2
3
namespace AlgoWeb\PODataLaravel\Serialisers;
4
5
use POData\Common\Messages;
6
use POData\Common\ODataConstants;
7
use POData\Common\ODataException;
8
use POData\IService;
9
use POData\ObjectModel\IObjectSerialiser;
10
use POData\ObjectModel\ODataEntry;
11
use POData\ObjectModel\ODataFeed;
12
use POData\ObjectModel\ODataLink;
13
use POData\ObjectModel\ODataMediaLink;
14
use POData\ObjectModel\ODataNavigationPropertyInfo;
15
use POData\ObjectModel\ODataProperty;
16
use POData\ObjectModel\ODataPropertyContent;
17
use POData\ObjectModel\ODataURL;
18
use POData\ObjectModel\ODataURLCollection;
19
use POData\Providers\Metadata\ResourceEntityType;
20
use POData\Providers\Metadata\ResourceProperty;
21
use POData\Providers\Metadata\ResourcePropertyKind;
22
use POData\Providers\Metadata\ResourceSet;
23
use POData\Providers\Metadata\ResourceSetWrapper;
24
use POData\Providers\Metadata\ResourceType;
25
use POData\Providers\Metadata\Type\Binary;
26
use POData\Providers\Metadata\Type\Boolean;
27
use POData\Providers\Metadata\Type\DateTime;
28
use POData\Providers\Metadata\Type\IType;
29
use POData\Providers\Metadata\Type\StringType;
30
use POData\Providers\Query\QueryType;
31
use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ExpandedProjectionNode;
32
use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ProjectionNode;
33
use POData\UriProcessor\RequestDescription;
34
use POData\UriProcessor\SegmentStack;
35
36
class IronicSerialiser implements IObjectSerialiser
37
{
38
    /**
39
     * The service implementation.
40
     *
41
     * @var IService
42
     */
43
    protected $service;
44
45
    /**
46
     * Request description instance describes OData request the
47
     * the client has submitted and result of the request.
48
     *
49
     * @var RequestDescription
50
     */
51
    protected $request;
52
53
    /**
54
     * Collection of complex type instances used for cycle detection.
55
     *
56
     * @var array
57
     */
58
    protected $complexTypeInstanceCollection;
59
60
    /**
61
     * Absolute service Uri.
62
     *
63
     * @var string
64
     */
65
    protected $absoluteServiceUri;
66
67
    /**
68
     * Absolute service Uri with slash.
69
     *
70
     * @var string
71
     */
72
    protected $absoluteServiceUriWithSlash;
73
74
    /**
75
     * Holds reference to segment stack being processed.
76
     *
77
     * @var SegmentStack
78
     */
79
    protected $stack;
80
81
    /**
82
     * Lightweight stack tracking for recursive descent fill
83
     */
84
    private $lightStack = [];
85
86
    private $modelSerialiser;
87
88
    /**
89
     * @param IService           $service Reference to the data service instance
90
     * @param RequestDescription $request Type instance describing the client submitted request
91
     */
92
    public function __construct(IService $service, RequestDescription $request = null)
93
    {
94
        $this->service = $service;
95
        $this->request = $request;
96
        $this->absoluteServiceUri = $service->getHost()->getAbsoluteServiceUri()->getUrlAsString();
97
        $this->absoluteServiceUriWithSlash = rtrim($this->absoluteServiceUri, '/') . '/';
98
        $this->stack = new SegmentStack($request);
99
        $this->complexTypeInstanceCollection = [];
100
        $this->modelSerialiser = new ModelSerialiser();
101
    }
102
103
    /**
104
     * Write a top level entry resource.
105
     *
106
     * @param mixed $entryObject Reference to the entry object to be written
107
     *
108
     * @return ODataEntry
109
     */
110
    public function writeTopLevelElement($entryObject)
111
    {
112
        if (!isset($entryObject)) {
113
            array_pop($this->lightStack);
114
            return null;
115
        }
116
117
        $this->loadStackIfEmpty();
118
119
        $stackCount = count($this->lightStack);
120
        $topOfStack = $this->lightStack[$stackCount-1];
121
        $resourceType = $this->getService()->getProvidersWrapper()->resolveResourceType($topOfStack[0]);
122
        $rawProp = $resourceType->getAllProperties();
123
        $relProp = [];
124
        $nonRelProp = [];
125
        foreach ($rawProp as $prop) {
126
            if ($prop->getResourceType() instanceof ResourceEntityType) {
127
                $relProp[] = $prop;
128
            } else {
129
                $nonRelProp[$prop->getName()] = $prop;
130
            }
131
        }
132
133
        $resourceSet = $resourceType->getCustomState();
134
        assert($resourceSet instanceof ResourceSet);
135
        $title = $resourceType->getName();
136
        $type = $resourceType->getFullName();
137
138
        $relativeUri = $this->getEntryInstanceKey(
139
            $entryObject,
140
            $resourceType,
141
            $resourceSet->getName()
142
        );
143
        $absoluteUri = rtrim($this->absoluteServiceUri, '/') . '/' . $relativeUri;
144
145
        list($mediaLink, $mediaLinks) = $this->writeMediaData($entryObject, $type, $relativeUri, $resourceType);
146
147
        $propertyContent = new ODataPropertyContent();
148
        $cereal = $this->modelSerialiser->bulkSerialise($entryObject);
149
        foreach ($cereal as $corn => $flake) {
150
            if (!array_key_exists($corn, $nonRelProp)) {
151
                continue;
152
            }
153
            $rType = $nonRelProp[$corn]->getResourceType()->getInstanceType();
154
            $subProp = new ODataProperty();
155
            $subProp->name = $corn;
0 ignored issues
show
Documentation Bug introduced by
It seems like $corn can also be of type integer. However, the property $name is declared as type string. Maybe add an additional type check?

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 $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. 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.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
156
            $subProp->value = isset($flake) ? $this->primitiveToString($rType, $flake) : null;
157
            $subProp->typeName = $nonRelProp[$corn]->getResourceType()->getFullName();
158
            $propertyContent->properties[] = $subProp;
159
        }
160
161
        $links = [];
162
        foreach ($relProp as $prop) {
163
            $nuLink = new ODataLink();
164
            $propKind = $prop->getKind();
165
166
            assert(
167
                ResourcePropertyKind::RESOURCESET_REFERENCE == $propKind
168
                || ResourcePropertyKind::RESOURCE_REFERENCE == $propKind,
169
                '$propKind != ResourcePropertyKind::RESOURCESET_REFERENCE &&'
170
                .' $propKind != ResourcePropertyKind::RESOURCE_REFERENCE'
171
            );
172
            $propTail = ResourcePropertyKind::RESOURCE_REFERENCE == $propKind ? 'entry' : 'feed';
173
            $propType = 'application/atom+xml;type='.$propTail;
174
            $propName = $prop->getName();
175
            $nuLink->title = $propName;
176
            $nuLink->name = ODataConstants::ODATA_RELATED_NAMESPACE . $propName;
177
            $nuLink->url = $relativeUri . '/' . $propName;
178
            $nuLink->type = $propType;
179
180
            $navProp = new ODataNavigationPropertyInfo($prop, $this->shouldExpandSegment($propName));
181
            if ($navProp->expanded) {
182
                $nextName = $prop->getResourceType()->getName();
183
                $nuLink->isExpanded = true;
184
                $isCollection = ResourcePropertyKind::RESOURCESET_REFERENCE == $propKind;
185
                $nuLink->isCollection = $isCollection;
186
                $value = $entryObject->$propName;
187
                array_push($this->lightStack, [$nextName, $propName]);
188
                if (!$isCollection) {
189
                    $expandedResult = $this->writeTopLevelElement($value);
190
                } else {
191
                    $expandedResult = $this->writeTopLevelElements($value);
192
                }
193
                $nuLink->expandedResult = $expandedResult;
194
                if (!isset($nuLink->expandedResult)) {
195
                    $nuLink->isCollection = null;
196
                    $nuLink->isExpanded = null;
197
                } else {
198
                    if (isset($nuLink->expandedResult->selfLink)) {
199
                        $nuLink->expandedResult->selfLink->title = $propName;
200
                        $nuLink->expandedResult->selfLink->url = $nuLink->url;
201
                        $nuLink->expandedResult->title = $propName;
202
                        $nuLink->expandedResult->id = rtrim($this->absoluteServiceUri, '/') . '/' . $nuLink->url;
203
                    }
204
                }
205
            }
206
207
            $links[] = $nuLink;
208
        }
209
210
        $odata = new ODataEntry();
211
        $odata->resourceSetName = $resourceSet->getName();
212
        $odata->id = $absoluteUri;
213
        $odata->title = $title;
214
        $odata->type = $type;
215
        $odata->propertyContent = $propertyContent;
216
        $odata->isMediaLinkEntry = $resourceType->isMediaLinkEntry();
217
        $odata->editLink = $relativeUri;
218
        $odata->mediaLink = $mediaLink;
219
        $odata->mediaLinks = $mediaLinks;
220
        $odata->links = $links;
221
222
        $newCount = count($this->lightStack);
223
        assert($newCount == $stackCount, "Should have $stackCount elements in stack, have $newCount elements");
224
        array_pop($this->lightStack);
225
        return $odata;
226
    }
227
228
    /**
229
     * Write top level feed element.
230
     *
231
     * @param array &$entryObjects Array of entry resources to be written
232
     *
233
     * @return ODataFeed
234
     */
235
    public function writeTopLevelElements(&$entryObjects)
236
    {
237
        assert(is_array($entryObjects), '!is_array($entryObjects)');
238
239
        $this->loadStackIfEmpty();
240
        $setName = $this->getRequest()->getTargetResourceSetWrapper()->getName();
241
242
        $title = $this->getRequest()->getContainerName();
243
        $relativeUri = $this->getRequest()->getIdentifier();
244
        $absoluteUri = $this->getRequest()->getRequestUrl()->getUrlAsString();
245
246
        $selfLink = new ODataLink();
247
        $selfLink->name = 'self';
248
        $selfLink->title = $relativeUri;
249
        $selfLink->url = $relativeUri;
250
251
        $odata = new ODataFeed();
252
        $odata->title = $title;
253
        $odata->id = $absoluteUri;
254
        $odata->selfLink = $selfLink;
255
256
        if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) {
257
            $odata->rowCount = $this->getRequest()->getCountValue();
258
        }
259
        foreach ($entryObjects as $entry) {
260
            $odata->entries[] = $this->writeTopLevelElement($entry);
261
        }
262
263
264
        if ($this->needNextPageLink(count($entryObjects))) {
265
            $stackSegment = $setName;
266
            $lastObject = end($entryObjects);
267
            $segment = $this->getNextLinkUri($lastObject, $absoluteUri);
268
            $nextLink = new ODataLink();
269
            $nextLink->name = ODataConstants::ATOM_LINK_NEXT_ATTRIBUTE_STRING;
270
            $nextLink->url = rtrim($this->absoluteServiceUri, '/') . '/' . $stackSegment . $segment;
271
            $odata->nextPageLink = $nextLink;
272
        }
273
274
        return $odata;
275
    }
276
277
    /**
278
     * Write top level url element.
279
     *
280
     * @param mixed $entryObject The entry resource whose url to be written
281
     *
282
     * @return ODataURL
283
     */
284
    public function writeUrlElement($entryObject)
285
    {
286
        $url = new ODataURL();
287
        if (!is_null($entryObject)) {
288
            $currentResourceType = $this->getCurrentResourceSetWrapper()->getResourceType();
289
            $relativeUri = $this->getEntryInstanceKey(
290
                $entryObject,
291
                $currentResourceType,
292
                $this->getCurrentResourceSetWrapper()->getName()
293
            );
294
295
            $url->url = rtrim($this->absoluteServiceUri, '/') . '/' . $relativeUri;
296
        }
297
298
        return $url;
299
    }
300
301
    /**
302
     * Write top level url collection.
303
     *
304
     * @param array $entryObjects Array of entry resources
305
     *                            whose url to be written
306
     *
307
     * @return ODataURLCollection
308
     */
309
    public function writeUrlElements($entryObjects)
310
    {
311
        $urls = new ODataURLCollection();
312
        if (!empty($entryObjects)) {
313
            $i = 0;
314
            foreach ($entryObjects as $entryObject) {
315
                $urls->urls[$i] = $this->writeUrlElement($entryObject);
316
                ++$i;
317
            }
318
319
            if ($i > 0 && $this->needNextPageLink(count($entryObjects))) {
320
                $stackSegment = $this->getRequest()->getTargetResourceSetWrapper()->getName();
321
                $lastObject = end($entryObjects);
322
                $segment = $this->getNextLinkUri($lastObject, $this->getRequest()->getRequestUrl()->getUrlAsString());
323
                $nextLink = new ODataLink();
324
                $nextLink->name = ODataConstants::ATOM_LINK_NEXT_ATTRIBUTE_STRING;
325
                $nextLink->url = rtrim($this->absoluteServiceUri, '/') . '/' . $stackSegment . $segment;
326
                $urls->nextPageLink = $nextLink;
327
            }
328
        }
329
330
        if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) {
331
            $urls->count = $this->getRequest()->getCountValue();
332
        }
333
334
        return $urls;
335
    }
336
337
    /**
338
     * Write top level complex resource.
339
     *
340
     * @param mixed &$complexValue The complex object to be
341
     *                                    written
342
     * @param string $propertyName The name of the
343
     *                                    complex property
344
     * @param ResourceType &$resourceType Describes the type of
345
     *                                    complex object
346
     *
347
     * @return ODataPropertyContent
348
     * @codeCoverageIgnore
349
     */
350
    public function writeTopLevelComplexObject(&$complexValue, $propertyName, ResourceType &$resourceType)
351
    {
352
        // TODO: Figure out if we need to bother implementing this
353
    }
354
355
    /**
356
     * Write top level bag resource.
357
     *
358
     * @param mixed &$BagValue The bag object to be
359
     *                                    written
360
     * @param string $propertyName The name of the
361
     *                                    bag property
362
     * @param ResourceType &$resourceType Describes the type of
363
     *                                    bag object
364
     * @codeCoverageIgnore
365
     * @return ODataPropertyContent
366
     */
367
    public function writeTopLevelBagObject(&$BagValue, $propertyName, ResourceType &$resourceType)
368
    {
369
        // TODO: Figure out if we need to bother implementing this
370
    }
371
372
    /**
373
     * Write top level primitive value.
374
     *
375
     * @param mixed &$primitiveValue The primitve value to be
376
     *                                            written
377
     * @param ResourceProperty &$resourceProperty Resource property
378
     *                                            describing the
379
     *                                            primitive property
380
     *                                            to be written
381
     * @codeCoverageIgnore
382
     * @return ODataPropertyContent
383
     */
384
    public function writeTopLevelPrimitive(&$primitiveValue, ResourceProperty &$resourceProperty = null)
385
    {
386
        // TODO: Figure out if we need to bother implementing this
387
    }
388
389
    /**
390
     * Gets reference to the request submitted by client.
391
     *
392
     * @return RequestDescription
393
     */
394
    public function getRequest()
395
    {
396
        assert(null != $this->request, 'Request not yet set');
397
398
        return $this->request;
399
    }
400
401
    /**
402
     * Sets reference to the request submitted by client.
403
     *
404
     * @param RequestDescription $request
405
     */
406
    public function setRequest(RequestDescription $request)
407
    {
408
        $this->request = $request;
409
        $this->stack->setRequest($request);
410
    }
411
412
    /**
413
     * Gets the data service instance.
414
     *
415
     * @return IService
416
     */
417
    public function getService()
418
    {
419
        return $this->service;
420
    }
421
422
    /**
423
     * Gets the segment stack instance.
424
     *
425
     * @return SegmentStack
426
     */
427
    public function getStack()
428
    {
429
        return $this->stack;
430
    }
431
432
    protected function getEntryInstanceKey($entityInstance, ResourceType $resourceType, $containerName)
433
    {
434
        $typeName = $resourceType->getName();
435
        $keyProperties = $resourceType->getKeyProperties();
436
        assert(count($keyProperties) != 0, 'count($keyProperties) == 0');
437
        $keyString = $containerName . '(';
438
        $comma = null;
439
        foreach ($keyProperties as $keyName => $resourceProperty) {
440
            $keyType = $resourceProperty->getInstanceType();
441
            assert($keyType instanceof IType, '$keyType not instanceof IType');
442
            $keyName = $resourceProperty->getName();
443
            $keyValue = $entityInstance->$keyName;
444
            if (!isset($keyValue)) {
445
                throw ODataException::createInternalServerError(
446
                    Messages::badQueryNullKeysAreNotSupported($typeName, $keyName)
447
                );
448
            }
449
450
            $keyValue = $keyType->convertToOData($keyValue);
451
            $keyString .= $comma . $keyName . '=' . $keyValue;
452
            $comma = ',';
453
        }
454
455
        $keyString .= ')';
456
457
        return $keyString;
458
    }
459
460
    /**
461
     * @param $entryObject
462
     * @param $type
463
     * @param $relativeUri
464
     * @param $resourceType
465
     * @return array
466
     */
467
    protected function writeMediaData($entryObject, $type, $relativeUri, ResourceType $resourceType)
468
    {
469
        $context = $this->getService()->getOperationContext();
470
        $streamProviderWrapper = $this->getService()->getStreamProviderWrapper();
471
        assert(null != $streamProviderWrapper, "Retrieved stream provider must not be null");
472
473
        $mediaLink = null;
474
        if ($resourceType->isMediaLinkEntry()) {
475
            $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()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
476
            $mediaLink = new ODataMediaLink($type, '/$value', $relativeUri . '/$value', '*/*', $eTag);
477
        }
478
        $mediaLinks = [];
479
        if ($resourceType->hasNamedStream()) {
480
            $namedStreams = $resourceType->getAllNamedStreams();
481
            foreach ($namedStreams as $streamTitle => $resourceStreamInfo) {
482
                $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 getReadStream()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
483
                    $entryObject,
484
                    $resourceStreamInfo,
485
                    $context,
486
                    $relativeUri
487
                );
488
                $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()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
489
                    $entryObject,
490
                    $resourceStreamInfo,
491
                    $context
492
                );
493
                $eTag = $streamProviderWrapper->getStreamETag2(
0 ignored issues
show
Bug introduced by
The method getStreamETag2() does not exist on POData\Providers\Stream\StreamProviderWrapper. Did you maybe mean getStreamETag()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
494
                    $entryObject,
495
                    $resourceStreamInfo,
496
                    $context
497
                );
498
499
                $nuLink = new ODataMediaLink($streamTitle, $readUri, $readUri, $mediaContentType, $eTag);
500
                $mediaLinks[] = $nuLink;
501
            }
502
        }
503
        return [$mediaLink, $mediaLinks];
504
    }
505
506
    /**
507
     * Gets collection of projection nodes under the current node.
508
     *
509
     * @return ProjectionNode[]|ExpandedProjectionNode[]|null List of nodes
510
     *                                                        describing projections for the current segment, If this method returns
511
     *                                                        null it means no projections are to be applied and the entire resource
512
     *                                                        for the current segment should be serialized, If it returns non-null
513
     *                                                        only the properties described by the returned projection segments should
514
     *                                                        be serialized
515
     */
516
    protected function getProjectionNodes()
517
    {
518
        $expandedProjectionNode = $this->getCurrentExpandedProjectionNode();
519
        if (is_null($expandedProjectionNode) || $expandedProjectionNode->canSelectAllProperties()) {
520
            return null;
521
        }
522
523
        return $expandedProjectionNode->getChildNodes();
524
    }
525
526
    /**
527
     * Find a 'ExpandedProjectionNode' instance in the projection tree
528
     * which describes the current segment.
529
     *
530
     * @return ExpandedProjectionNode|null
531
     */
532
    protected function getCurrentExpandedProjectionNode()
533
    {
534
        $expandedProjectionNode = $this->getRequest()->getRootProjectionNode();
535
        if (is_null($expandedProjectionNode)) {
536
            return null;
537
        } else {
538
            $segmentNames = $this->getStack()->getSegmentNames();
539
            $depth = count($segmentNames);
540
            // $depth == 1 means serialization of root entry
541
            //(the resource identified by resource path) is going on,
542
            //so control won't get into the below for loop.
543
            //we will directly return the root node,
544
            //which is 'ExpandedProjectionNode'
545
            // for resource identified by resource path.
546
            if (0 != $depth) {
547
                for ($i = 1; $i < $depth; ++$i) {
548
                    $expandedProjectionNode = $expandedProjectionNode->findNode($segmentNames[$i]);
549
                    assert(!is_null($expandedProjectionNode), 'is_null($expandedProjectionNode)');
550
                    assert(
551
                        $expandedProjectionNode instanceof ExpandedProjectionNode,
552
                        '$expandedProjectionNode not instanceof ExpandedProjectionNode'
553
                    );
554
                }
555
            }
556
        }
557
558
        return $expandedProjectionNode;
559
    }
560
561
    /**
562
     * Check whether to expand a navigation property or not.
563
     *
564
     * @param string $navigationPropertyName Name of naviagtion property in question
565
     *
566
     * @return bool True if the given navigation should be
567
     *              explanded otherwise false
568
     */
569
    protected function shouldExpandSegment($navigationPropertyName)
570
    {
571
        $expandedProjectionNode = $this->getCurrentExpandedProjectionNode();
572
        if (is_null($expandedProjectionNode)) {
573
            return false;
574
        }
575
576
        $expandedProjectionNode = $expandedProjectionNode->findNode($navigationPropertyName);
577
578
        // null is a valid input to an instanceof call as of PHP 5.6 - will always return false
579
        return $expandedProjectionNode instanceof ExpandedProjectionNode;
580
    }
581
582
    /**
583
     * Wheter next link is needed for the current resource set (feed)
584
     * being serialized.
585
     *
586
     * @param int $resultSetCount Number of entries in the current
587
     *                            resource set
588
     *
589
     * @return bool true if the feed must have a next page link
590
     */
591
    protected function needNextPageLink($resultSetCount)
592
    {
593
        $currentResourceSet = $this->getCurrentResourceSetWrapper();
594
        $recursionLevel = count($this->getStack()->getSegmentNames());
595
        $pageSize = $currentResourceSet->getResourceSetPageSize();
596
597
        if (1 == $recursionLevel) {
598
            //presence of $top option affect next link for root container
599
            $topValueCount = $this->getRequest()->getTopOptionCount();
600
            if (!is_null($topValueCount) && ($topValueCount <= $pageSize)) {
601
                return false;
602
            }
603
        }
604
        return $resultSetCount == $pageSize;
605
    }
606
607
    /**
608
     * Resource set wrapper for the resource being serialized.
609
     *
610
     * @return ResourceSetWrapper
611
     */
612
    protected function getCurrentResourceSetWrapper()
613
    {
614
        $segmentWrappers = $this->getStack()->getSegmentWrappers();
615
        $count = count($segmentWrappers);
616
617
        return 0 == $count ? $this->getRequest()->getTargetResourceSetWrapper() : $segmentWrappers[$count - 1];
618
    }
619
620
    /**
621
     * Get next page link from the given entity instance.
622
     *
623
     * @param mixed  &$lastObject Last object serialized to be
624
     *                            used for generating $skiptoken
625
     * @param string $absoluteUri Absolute response URI
626
     *
627
     * @return string for the link for next page
628
     */
629
    protected function getNextLinkUri(&$lastObject, $absoluteUri)
0 ignored issues
show
Unused Code introduced by
The parameter $absoluteUri is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
630
    {
631
        $currentExpandedProjectionNode = $this->getCurrentExpandedProjectionNode();
632
        $internalOrderByInfo = $currentExpandedProjectionNode->getInternalOrderByInfo();
633
        $skipToken = $internalOrderByInfo->buildSkipTokenValue($lastObject);
634
        assert(!is_null($skipToken), '!is_null($skipToken)');
635
        $skipToken = '?$skip='.$skipToken;
636
        return $skipToken;
637
    }
638
639
    private function loadStackIfEmpty()
640
    {
641
        if (0 == count($this->lightStack)) {
642
            $typeName = $this->getRequest()->getTargetResourceType()->getName();
643
            array_push($this->lightStack, [$typeName, $typeName]);
644
        }
645
    }
646
647
    /**
648
     * Convert the given primitive value to string.
649
     * Note: This method will not handle null primitive value.
650
     *
651
     * @param IType &$primitiveResourceType        Type of the primitive property
652
     *                                             whose value need to be converted
653
     * @param mixed        $primitiveValue         Primitive value to convert
654
     *
655
     * @return string
656
     */
657
    private function primitiveToString(IType &$type, $primitiveValue)
658
    {
659
        if ($type instanceof Boolean) {
660
            $stringValue = (true === $primitiveValue) ? 'true' : 'false';
661
        } elseif ($type instanceof Binary) {
662
            $stringValue = base64_encode($primitiveValue);
663
        } elseif ($type instanceof DateTime && $primitiveValue instanceof \DateTime) {
664
            $stringValue = $primitiveValue->format(\DateTime::ATOM);
665
        } elseif ($type instanceof StringType) {
666
            $stringValue = utf8_encode($primitiveValue);
667
        } else {
668
            $stringValue = strval($primitiveValue);
669
        }
670
671
        return $stringValue;
672
    }
673
}
674