Passed
Push — master ( 0669ef...efaea1 )
by Alex
04:43 queued 01:07
created

UriProcessorNew::executePut()   B

Complexity

Conditions 4
Paths 8

Size

Total Lines 22
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 15
nc 8
nop 0
dl 0
loc 22
rs 8.9197
c 0
b 0
f 0
1
<?php
2
3
namespace POData\UriProcessor;
4
5
use POData\Common\HttpStatus;
6
use POData\Common\Messages;
7
use POData\Common\ODataConstants;
8
use POData\Common\ODataException;
9
use POData\IService;
10
use POData\ObjectModel\CynicDeserialiser;
11
use POData\ObjectModel\ModelDeserialiser;
12
use POData\ObjectModel\ODataEntry;
13
use POData\ObjectModel\ODataURL;
14
use POData\OperationContext\HTTPRequestMethod;
15
use POData\Providers\Metadata\ResourcePropertyKind;
16
use POData\Providers\Metadata\ResourceSet;
17
use POData\Providers\Metadata\ResourceSetWrapper;
18
use POData\Providers\ProvidersWrapper;
19
use POData\Providers\Query\QueryResult;
20
use POData\Providers\Query\QueryType;
21
use POData\UriProcessor\Interfaces\IUriProcessor;
22
use POData\UriProcessor\QueryProcessor\QueryProcessor;
23
use POData\UriProcessor\ResourcePathProcessor\ResourcePathProcessor;
24
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\KeyDescriptor;
25
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\SegmentDescriptor;
26
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\SegmentParser;
27
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\TargetKind;
28
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\TargetSource;
29
30
/**
31
 * Class UriProcessorNew.
32
 *
33
 * A type to process client's requested URI
34
 * The syntax of request URI is:
35
 *  Scheme Host Port ServiceRoot ResourcePath ? QueryOption
36
 * For more details refer:
37
 * http://www.odata.org/developers/protocols/uri-conventions#UriComponents
38
 */
39
class UriProcessorNew implements IUriProcessor
40
{
41
    /**
42
     * Description of the OData request that a client has submitted.
43
     *
44
     * @var RequestDescription
45
     */
46
    private $request;
47
48
    /**
49
     * Holds reference to the data service instance.
50
     *
51
     * @var IService
52
     */
53
    private $service;
54
55
    /**
56
     * Holds reference to the wrapper over IDSMP and IDSQP implementation.
57
     *
58
     * @var ProvidersWrapper
59
     */
60
    private $providers;
61
62
    /**
63
     * Holds reference to request expander.
64
     *
65
     * @var RequestExpander
66
     */
67
    private $expander;
68
69
    /**
70
     * @var ModelDeserialiser
71
     */
72
    private $cereal;
73
74
    /**
75
     * @var CynicDeserialiser
76
     */
77
    private $cynicDeserialiser;
78
79
    /**
80
     * Constructs a new instance of UriProcessor.
81
     *
82
     * @param IService $service Reference to the data service instance
83
     */
84
    private function __construct(IService $service)
85
    {
86
        $this->service = $service;
87
        $this->providers = $service->getProvidersWrapper();
88
        $this->request = ResourcePathProcessor::process($service);
89
        $this->expander = new RequestExpander(
90
            $this->getRequest(),
91
            $this->getService(),
92
            $this->getProviders()
93
        );
94
        $this->getRequest()->setUriProcessor($this);
95
        $this->cereal = new ModelDeserialiser();
96
        $this->cynicDeserialiser = new CynicDeserialiser(
97
            $service->getMetadataProvider(),
98
            $service->getProvidersWrapper()
99
        );
100
    }
101
102
    /**
103
     * Process the resource path and query options of client's request uri.
104
     *
105
     * @param IService $service Reference to the data service instance
106
     *
107
     * @throws ODataException
108
     *
109
     * @return IUriProcessor
110
     */
111
    public static function process(IService $service)
112
    {
113
        $absRequestUri = $service->getHost()->getAbsoluteRequestUri();
114
        $absServiceUri = $service->getHost()->getAbsoluteServiceUri();
115
116
        if (!$absServiceUri->isBaseOf($absRequestUri)) {
117
            throw ODataException::createInternalServerError(
118
                Messages::uriProcessorRequestUriDoesNotHaveTheRightBaseUri(
119
                    $absRequestUri->getUrlAsString(),
120
                    $absServiceUri->getUrlAsString()
121
                )
122
            );
123
        }
124
125
        $processor = new self($service);
126
        //Parse the query string options of the request Uri.
127
        QueryProcessor::process($processor->request, $service);
128
        return $processor;
129
    }
130
131
    /**
132
     * Gets reference to the request submitted by client.
133
     *
134
     * @return RequestDescription
135
     */
136
    public function getRequest()
137
    {
138
        return $this->request;
139
    }
140
141
    /**
142
     * Gets reference to the request submitted by client.
143
     *
144
     * @return ProvidersWrapper
145
     */
146
    public function getProviders()
147
    {
148
        return $this->providers;
149
    }
150
151
    /**
152
     * Gets the data service instance.
153
     *
154
     * @return IService
155
     */
156
    public function getService()
157
    {
158
        return $this->service;
159
    }
160
161
    /**
162
     * Gets the request expander instance.
163
     *
164
     * @return RequestExpander
165
     */
166
    public function getExpander()
167
    {
168
        return $this->expander;
169
    }
170
171
    /**
172
     * @return ModelDeserialiser
173
     */
174
    public function getModelDeserialiser()
175
    {
176
        return $this->cereal;
177
    }
178
179
    public function getCynicDeserialiser()
180
    {
181
        return $this->cynicDeserialiser;
182
    }
183
184
    /**
185
     * Execute the client submitted request against the data source.
186
     */
187
    public function execute()
188
    {
189
        $service = $this->getService();
190
        assert($service instanceof IService, '!($service instanceof IService)');
191
        $context = $service->getOperationContext();
192
        $method = $context->incomingRequest()->getMethod();
193
194
        switch ($method) {
195
            case HTTPRequestMethod::GET():
196
                $this->executeGet();
197
                break;
198
            case HTTPRequestMethod::DELETE():
199
                $this->executeGet();
200
                $this->executeDelete();
201
                break;
202
            case HTTPRequestMethod::PUT():
203
                $this->executeGet();
204
                $this->executePut();
205
                break;
206
            case HTTPRequestMethod::POST():
207
                $this->executePost();
208
                break;
209
            default:
210
                throw ODataException::createNotImplementedError(Messages::onlyReadSupport($method));
211
        }
212
213
        // Apply $select and $expand options to result set, this function will be always applied
214
        // irrespective of return value of IDSQP2::canApplyQueryOptions which means library will
215
        // not delegate $expand/$select operation to IDSQP2 implementation
216
        $this->getExpander()->handleExpansion();
217
    }
218
219
    /**
220
     * Execute the client submitted request against the data source (GET).
221
     */
222
    protected function executeGet()
223
    {
224
        $segments = $this->getRequest()->getSegments();
225
        $root = $this->getRequest()->getRootProjectionNode();
226
        $eagerLoad = (null === $root) ? [] : $root->getEagerLoadList();
227
228
        foreach ($segments as $segment) {
229
            $requestTargetKind = $segment->getTargetKind();
230
231
            switch ($requestTargetKind) {
232
                case TargetKind::SINGLETON():
233
                    $this->executeGetSingleton($segment);
234
                    break;
235
                case TargetKind::RESOURCE():
236
                    if (TargetSource::ENTITY_SET == $segment->getTargetSource()) {
237
                        $this->handleSegmentTargetsToResourceSet($segment, $eagerLoad);
238
                    } else {
239
                        $this->executeGetResource($segment, $eagerLoad);
240
                    }
241
                    break;
242
                case TargetKind::MEDIA_RESOURCE():
243
                    $this->checkResourceExistsByIdentifier($segment);
244
                    $segment->setResult($segment->getPrevious()->getResult());
245
                    // a media resource means we're done - bail out of segment processing
246
                    break 2;
247
                case TargetKind::LINK():
248
                    $this->executeGetLink($segment);
249
                    break;
250
                case TargetKind::PRIMITIVE_VALUE():
251
                    $previous = $segment->getPrevious();
252
                    if (null !== $previous && TargetKind::RESOURCE() == $previous->getTargetKind()) {
253
                        $result = $previous->getResult();
254
                        if ($result instanceof QueryResult) {
255
                            $raw = null !== $result->count ? $result->count : count($result->results);
256
                            $segment->setResult($raw);
257
                        }
258
                    }
259
                    break;
260
                case TargetKind::PRIMITIVE():
261
                case TargetKind::COMPLEX_OBJECT():
262
                case TargetKind::BAG():
263
                    break;
264
                default:
265
                    assert(false, 'Not implemented yet');
266
            }
267
268
            if (null === $segment->getNext()
269
                || ODataConstants::URI_COUNT_SEGMENT == $segment->getNext()->getIdentifier()
270
            ) {
271
                $this->applyQueryOptions($segment);
272
            }
273
        }
274
    }
275
276
    /**
277
     * Execute the client submitted request against the data source (DELETE).
278
     */
279
    protected function executeDelete()
280
    {
281
        $segment = $this->getFinalEffectiveSegment();
282
        $requestMethod = $this->getService()->getOperationContext()->incomingRequest()->getMethod();
283
        $resourceSet = $segment->getTargetResourceSetWrapper();
284
        $keyDescriptor = $segment->getKeyDescriptor();
285
286
        $this->checkUriValidForSuppliedVerb($resourceSet, $keyDescriptor, $requestMethod);
287
        assert($resourceSet instanceof ResourceSet);
0 ignored issues
show
Bug introduced by
The call to assert() has too few arguments starting with description. ( Ignorable by Annotation )

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

287
        /** @scrutinizer ignore-call */ 
288
        assert($resourceSet instanceof ResourceSet);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
288
        $this->getProviders()->deleteResource($resourceSet, $segment->getResult());
289
        $this->getService()->getHost()->setResponseStatusCode(HttpStatus::CODE_NOCONTENT);
290
    }
291
292
    /**
293
     * Execute the client submitted request against the data source (PUT).
294
     */
295
    protected function executePut()
296
    {
297
        $segment = $this->getFinalEffectiveSegment();
298
        $requestMethod = $this->getService()->getOperationContext()->incomingRequest()->getMethod();
299
        $resourceSet = null !== $segment ? $segment->getTargetResourceSetWrapper() : null;
300
        $keyDescriptor = null !== $segment ? $segment->getKeyDescriptor() : null;
301
302
        $this->checkUriValidForSuppliedVerb($resourceSet, $keyDescriptor, $requestMethod);
303
        assert($resourceSet instanceof ResourceSet);
0 ignored issues
show
Bug introduced by
The call to assert() has too few arguments starting with description. ( Ignorable by Annotation )

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

303
        /** @scrutinizer ignore-call */ 
304
        assert($resourceSet instanceof ResourceSet);

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
304
        assert($keyDescriptor instanceof KeyDescriptor);
305
306
        $payload = $this->getRequest()->getData();
307
        assert($payload instanceof ODataEntry, get_class($payload));
0 ignored issues
show
Bug introduced by
It seems like $payload can also be of type array; however, parameter $object of get_class() does only seem to accept object, 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

307
        assert($payload instanceof ODataEntry, get_class(/** @scrutinizer ignore-type */ $payload));
Loading history...
308
        assert(!empty($payload->id), 'Payload ID must not be empty for PUT request');
309
        $data = $this->getModelDeserialiser()->bulkDeserialise($resourceSet->getResourceType(), $payload);
310
311
        if (empty($data)) {
312
            throw ODataException::createBadRequestError(Messages::noDataForThisVerb($requestMethod));
313
        }
314
315
        $queryResult = $this->getCynicDeserialiser()->processPayload($payload);
316
        $segment->setResult($queryResult);
317
    }
318
319
    /**
320
     * Execute the client submitted request against the data source (POST).
321
     */
322
    protected function executePost()
323
    {
324
        $segments = $this->getRequest()->getSegments();
325
        $requestMethod = $this->getService()->getOperationContext()->incomingRequest()->getMethod();
326
327
        foreach ($segments as $segment) {
328
            $requestTargetKind = $segment->getTargetKind();
329
            if ($requestTargetKind == TargetKind::RESOURCE()) {
330
                $resourceSet = $segment->getTargetResourceSetWrapper();
331
                if (!$resourceSet) {
332
                    $url = $this->getService()->getHost()->getAbsoluteRequestUri()->getUrlAsString();
333
                    $msg = Messages::badRequestInvalidUriForThisVerb($url, $requestMethod);
334
                    throw ODataException::createBadRequestError($msg);
335
                }
336
337
                $payload = $this->getRequest()->getData();
338
                if ($payload instanceof ODataURL) {
339
                    $this->executeGet();
340
                    $masterModel = $this->getRequest()->getSegments()[0]->getResult();
341
                    $masterResourceSet = $this->getRequest()->getSegments()[0]->getTargetResourceSetWrapper();
342
                    $masterNavProperty = $this->getRequest()->getLastSegment()->getIdentifier();
343
                    $slaveModelUri = new \POData\Common\Url($payload->url);
344
                    $host = $this->service->getHost();
345
                    $absoluteServiceUri = $host->getAbsoluteServiceUri();
346
                    $requestUriSegments = array_slice(
347
                        $slaveModelUri->getSegments(),
348
                        $absoluteServiceUri->getSegmentCount()
349
                    );
350
                    $newSegments = SegmentParser::parseRequestUriSegments(
351
                        $requestUriSegments,
352
                        $this->service->getProvidersWrapper(),
353
                        true
354
                    );
355
                    $this->executeGetResource($newSegments[0]);
356
                    $slaveModel = $newSegments[0]->getResult();
357
                    $slaveResourceSet = $newSegments[0]->getTargetResourceSetWrapper();
358
                    $linkAdded = $this->getProviders()
359
                        ->hookSingleModel(
360
                            $masterResourceSet,
361
                            $masterModel,
362
                            $slaveResourceSet,
363
                            $slaveModel,
364
                            $masterNavProperty
365
                        );
366
                    if ($linkAdded) {
367
                        $this->getService()->getHost()->setResponseStatusCode(HttpStatus::CODE_NOCONTENT);
368
                    } else {
369
                        throw ODataException::createInternalServerError('AdapterIndicatedLinkNotAttached');
370
                    }
371
                    foreach ($segments as $segment) {
372
                        $segment->setResult(null);
373
                    }
374
                    return;
375
                }
376
                assert($payload instanceof ODataEntry, get_class($payload));
377
                assert(empty($payload->id), 'Payload ID must be empty for POST request');
378
                $data = $this->getModelDeserialiser()->bulkDeserialise($resourceSet->getResourceType(), $payload);
379
380
                if (empty($data)) {
381
                    throw ODataException::createBadRequestError(Messages::noDataForThisVerb($requestMethod));
382
                }
383
                $this->getService()->getHost()->setResponseStatusCode(HttpStatus::CODE_CREATED);
384
                $queryResult = $this->getCynicDeserialiser()->processPayload($payload);
385
                $keyID = $payload->id;
386
                assert($keyID instanceof KeyDescriptor, get_class($keyID));
387
                $locationUrl = $keyID->generateRelativeUri($resourceSet->getResourceSet());
388
                $absoluteServiceUri = $this->getService()->getHost()->getAbsoluteServiceUri()->getUrlAsString();
389
                $location = rtrim($absoluteServiceUri, '/') . '/' . $locationUrl;
390
                $this->getService()->getHost()->setResponseLocation($location);
391
                $segment->setResult($queryResult);
392
            }
393
        }
394
    }
395
396
    /**
397
     * @return null|SegmentDescriptor
398
     */
399
    protected function getFinalEffectiveSegment()
400
    {
401
        $segment = $this->getRequest()->getLastSegment();
402
        // if last segment is $count, back up one
403
        if (null !== $segment && ODataConstants::URI_COUNT_SEGMENT == $segment->getIdentifier()) {
404
            $segment = $segment->getPrevious();
405
            return $segment;
406
        }
407
        return $segment;
408
    }
409
410
    /**
411
     * @param $resourceSet
412
     * @param $keyDescriptor
413
     * @param $requestMethod
414
     * @throws ODataException
415
     */
416
    protected function checkUriValidForSuppliedVerb($resourceSet, $keyDescriptor, $requestMethod)
417
    {
418
        if (!$resourceSet || !$keyDescriptor) {
419
            $url = $this->getService()->getHost()->getAbsoluteRequestUri()->getUrlAsString();
420
            throw ODataException::createBadRequestError(
421
                Messages::badRequestInvalidUriForThisVerb($url, $requestMethod)
422
            );
423
        }
424
    }
425
426
    /**
427
     * @param $segment
428
     */
429
    private function executeGetSingleton($segment)
430
    {
431
        $segmentId = $segment->getIdentifier();
432
        $singleton = $this->getService()->getProvidersWrapper()->resolveSingleton($segmentId);
433
        $segment->setResult($singleton->get());
434
    }
435
436
    /**
437
     * @param $segment
438
     */
439
    private function executeGetResource($segment, array $eagerList = [])
440
    {
441
        foreach ($eagerList as $eager) {
442
            assert(is_string($eager) && 0 < strlen($eager), 'Eager-load list elements must be non-empty strings');
443
        }
444
        $queryResult = $this->executeGetResourceRelated($segment);
445
        $segment->setResult($queryResult);
446
    }
447
448
    /**
449
     * @param $segment
450
     */
451
    private function executeGetLink($segment)
452
    {
453
        $previous = $segment->getPrevious();
454
        assert(isset($previous));
0 ignored issues
show
Bug introduced by
The call to assert() has too few arguments starting with description. ( 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
        assert(isset($previous));

This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
455
        $segment->setResult($previous->getResult());
456
    }
457
458
    /**
459
     * @param $segment
460
     * @return null|object|QueryResult
461
     */
462
    private function executeGetResourceRelated($segment)
463
    {
464
        $projectedProperty = $segment->getProjectedProperty();
465
        $projectedPropertyKind = null !== $projectedProperty ? $projectedProperty->getKind() : 0;
466
        $queryResult = null;
467
        switch ($projectedPropertyKind) {
468
            case ResourcePropertyKind::RESOURCE_REFERENCE:
469
                $queryResult = $this->getProviders()->getRelatedResourceReference(
470
                    $segment->getPrevious()->getTargetResourceSetWrapper(),
471
                    $segment->getPrevious()->getResult(),
472
                    $segment->getTargetResourceSetWrapper(),
473
                    $projectedProperty
474
                );
475
                break;
476
            case ResourcePropertyKind::RESOURCESET_REFERENCE:
477
                if ($segment->isSingleResult()) {
478
                    $queryResult = $this->getProviders()->getResourceFromRelatedResourceSet(
479
                        $segment->getPrevious()->getTargetResourceSetWrapper(),
480
                        $segment->getPrevious()->getResult(),
481
                        $segment->getTargetResourceSetWrapper(),
482
                        $projectedProperty,
483
                        $segment->getKeyDescriptor()
484
                    );
485
                } else {
486
                    $skipToken = $this->getRequest()->getInternalSkipTokenInfo();
487
                    $skipToken = (null !== $skipToken) ? $skipToken->getSkipTokenInfo() : null;
488
                    $queryResult = $this->getProviders()->getRelatedResourceSet(
489
                        $this->getRequest()->queryType,
490
                        $segment->getPrevious()->getTargetResourceSetWrapper(),
491
                        $segment->getPrevious()->getResult(),
492
                        $segment->getTargetResourceSetWrapper(),
493
                        $projectedProperty,
494
                        $this->getRequest()->getFilterInfo(),
495
                        null, // $orderby
496
                        null, // $top
497
                        null, // $skip
498
                        $skipToken
499
                    );
500
                }
501
                break;
502
            default:
503
                $this->checkResourceExistsByIdentifier($segment);
504
                assert(false, 'Invalid property kind type for resource retrieval');
505
        }
506
        return $queryResult;
507
    }
508
509
    /**
510
     * Query for a resource set pointed by the given segment descriptor and update the descriptor with the result.
511
     *
512
     * @param SegmentDescriptor $segment Describes the resource set to query
513
     */
514
    private function handleSegmentTargetsToResourceSet(SegmentDescriptor $segment, array $eagerList)
515
    {
516
        if ($segment->isSingleResult()) {
517
            $entityInstance = $this->getProviders()->getResourceFromResourceSet(
518
                $segment->getTargetResourceSetWrapper(),
519
                $segment->getKeyDescriptor(),
520
                $eagerList
521
            );
522
            $segment->setResult($entityInstance);
523
        } else {
524
            $skip = (null == $this->getRequest()) ? 0 : $this->getRequest()->getSkipCount();
525
            $skip = (null === $skip) ? 0 : $skip;
526
            $skipToken = $this->getRequest()->getInternalSkipTokenInfo();
527
            $skipToken = (null != $skipToken) ? $skipToken->getSkipTokenInfo() : null;
528
            $queryResult = $this->getProviders()->getResourceSet(
529
                $this->getRequest()->queryType,
530
                $segment->getTargetResourceSetWrapper(),
531
                $this->getRequest()->getFilterInfo(),
532
                $this->getRequest()->getInternalOrderByInfo(),
533
                $this->getRequest()->getTopCount(),
534
                $skip,
535
                $skipToken,
536
                $eagerList
537
            );
538
            $segment->setResult($queryResult);
539
        }
540
    }
541
542
    /**
543
     * @param $segment
544
     * @throws ODataException
545
     */
546
    private function checkResourceExistsByIdentifier($segment)
547
    {
548
        if (null === $segment->getPrevious()->getResult()) {
549
            throw ODataException::createResourceNotFoundError(
550
                $segment->getPrevious()->getIdentifier()
551
            );
552
        }
553
    }
554
555
    /**
556
     * Applies the query options to the resource(s) retrieved from the data source.
557
     *
558
     * @param SegmentDescriptor $segment The descriptor which holds resource(s) on which query options to be applied
559
     */
560
    private function applyQueryOptions(SegmentDescriptor $segment)
561
    {
562
        $result = $segment->getResult();
563
        if (!$result instanceof QueryResult) {
564
            //If the segment isn't a query result, then there's no paging or counting to be done
565
            return;
566
        }
567
        // Note $inlinecount=allpages means include the total count regardless of paging..so we set the counts first
568
        // regardless if POData does the paging or not.
569
        if ($this->getRequest()->queryType == QueryType::ENTITIES_WITH_COUNT()) {
570
            if ($this->getProviders()->handlesOrderedPaging()) {
571
                $this->getRequest()->setCountValue($result->count);
572
            } else {
573
                $this->getRequest()->setCountValue(count($result->results));
574
            }
575
        }
576
        //Have POData perform paging if necessary
577
        if (!$this->getProviders()->handlesOrderedPaging() && !empty($result->results)) {
578
            $result->results = $this->performPaging($result->results);
0 ignored issues
show
Bug introduced by
It seems like $result->results can also be of type object; however, parameter $result of POData\UriProcessor\UriP...sorNew::performPaging() does only seem to accept array, 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

578
            $result->results = $this->performPaging(/** @scrutinizer ignore-type */ $result->results);
Loading history...
579
        }
580
        //a bit surprising, but $skip and $top affects $count so update it here, not above
581
        //IE  data.svc/Collection/$count?$top=10 returns 10 even if Collection has 11+ entries
582
        if ($this->getRequest()->queryType == QueryType::COUNT()) {
583
            if ($this->getProviders()->handlesOrderedPaging()) {
584
                $this->getRequest()->setCountValue($result->count);
585
            } else {
586
                $this->getRequest()->setCountValue(count($result->results));
587
            }
588
        }
589
        $segment->setResult($result);
590
    }
591
592
    /**
593
     * If the provider does not perform the paging (ordering, top, skip) then this method does it.
594
     *
595
     * @param array $result
596
     *
597
     * @return array
598
     */
599
    private function performPaging(array $result)
600
    {
601
        //Apply (implicit and explicit) $orderby option
602
        $internalOrderByInfo = $this->getRequest()->getInternalOrderByInfo();
603
        if (null !== $internalOrderByInfo) {
604
            $orderByFunction = $internalOrderByInfo->getSorterFunction();
605
            usort($result, $orderByFunction);
606
        }
607
        //Apply $skiptoken option
608
        $internalSkipTokenInfo = $this->getRequest()->getInternalSkipTokenInfo();
609
        if (null !== $internalSkipTokenInfo) {
610
            $matchingIndex = $internalSkipTokenInfo->getIndexOfFirstEntryInTheNextPage($result);
611
            $result = array_slice($result, $matchingIndex);
612
        }
613
        //Apply $top and $skip option
614
        if (!empty($result)) {
615
            $top = $this->getRequest()->getTopCount();
616
            $skip = $this->getRequest()->getSkipCount();
617
            if (null === $skip) {
618
                $skip = 0;
619
            }
620
            $result = array_slice($result, $skip, $top);
621
        }
622
        return $result;
623
    }
624
}
625