RequestDescription::__construct()   B
last analyzed

Complexity

Conditions 7
Paths 48

Size

Total Lines 64
Code Lines 31

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 31
nc 48
nop 8
dl 0
loc 64
rs 8.4906
c 0
b 0
f 0

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace POData\UriProcessor;
6
7
use POData\Common\Messages;
8
use POData\Common\MimeTypes;
9
use POData\Common\ODataConstants;
10
use POData\Common\ODataException;
11
use POData\Common\Url;
12
use POData\Common\Version;
13
use POData\ObjectModel\ODataEntry;
14
use POData\ObjectModel\ODataFeed;
15
use POData\OperationContext\IHTTPRequest;
16
use POData\Providers\Metadata\ResourceProperty;
17
use POData\Providers\Metadata\ResourceSetWrapper;
18
use POData\Providers\Metadata\ResourceStreamInfo;
19
use POData\Providers\Metadata\ResourceType;
20
use POData\Providers\Query\QueryType;
21
use POData\Readers\ODataReaderRegistry;
22
use POData\UriProcessor\Interfaces\IUriProcessor;
23
use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\RootProjectionNode;
24
use POData\UriProcessor\QueryProcessor\ExpressionParser\FilterInfo;
25
use POData\UriProcessor\QueryProcessor\OrderByParser\InternalOrderByInfo;
26
use POData\UriProcessor\QueryProcessor\SkipTokenParser\InternalSkipTokenInfo;
27
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\SegmentDescriptor;
28
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\TargetKind;
29
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\TargetSource;
30
31
/**
32
 * Class RequestDescription.
33
 */
34
class RequestDescription
35
{
36
    /**
37
     * Collection of known data service versions.
38
     *
39
     * @var Version[]
40
     */
41
    private static $knownDataServiceVersions = null;
42
    /**
43
     * The count option specified in the request.
44
     *
45
     * @var QueryType
46
     */
47
    public $queryType;
48
    /**
49
     * Holds the value of HTTP 'DataServiceVersion' header in the request,
50
     * DataServiceVersion header value states the version of the
51
     * Open Data Protocol used by the client to generate the request.
52
     * Refer http://www.odata.org/developers/protocols/overview#ProtocolVersioning.
53
     *
54
     * @var Version
55
     */
56
    private $requestVersion = null;
57
    /**
58
     * Holds the value of HTTP 'MaxDataServiceVersion' header in the request,
59
     * MaxDataServiceVersion header value specifies the maximum version number
60
     * the client can accept in a response.
61
     * Refer http://www.odata.org/developers/protocols/overview#ProtocolVersioning.
62
     *
63
     * @var Version
64
     */
65
    private $requestMaxVersion = null;
66
    /**
67
     * This is the value of 'DataServiceVersion' header to be output in the response. this header
68
     * value states the OData version the server used to generate the response.
69
     * While processing the query and result set this value will be keeps on
70
     * updating, after every update this is compared against the
71
     * 'MaxDataServiceVersion' header in the client request to see whether the
72
     * client can interpret the response or not. The client should use this
73
     * value to determine whether it can correctly interpret the response or not.
74
     * Refer http://www.odata.org/developers/protocols/overview#ProtocolVersioning.
75
     *
76
     * @var Version
77
     */
78
    private $requiredMinResponseVersion;
79
    /**
80
     * The minimum client version requirement, This value keeps getting updated
81
     * during processing of query, this is compared against the
82
     * DataServiceVersion header in the client request and if the client request
83
     * is less than this value then we fail the request (e.g. $count request
84
     * was sent but client said it was Version 1.0).
85
     *
86
     * @var Version
87
     */
88
    private $requiredMinRequestVersion;
89
    /** @var Version */
90
    private $maxServiceVersion;
91
    /**
92
     * @var Url
93
     */
94
    private $requestUrl;
95
    /**
96
     * Collection of SegmentDescriptor containing information about
97
     * each segment in the resource path part of the request uri.
98
     *
99
     * @var SegmentDescriptor[]
100
     */
101
    private $segments;
102
    /**
103
     * Holds reference to the last segment descriptor.
104
     *
105
     * @var SegmentDescriptor
106
     */
107
    private $lastSegment;
108
    /**
109
     * The name of the container for results.
110
     *
111
     * @var string|null
112
     */
113
    private $containerName;
114
    /**
115
     * Number of segments.
116
     *
117
     * @var int
118
     */
119
    private $segmentCount;
120
121
    /**
122
     * Holds the value of $skip query option, if no $skip option
123
     * found then this parameter will be NULL.
124
     *
125
     * @var int|null
126
     */
127
    private $skipCount;
128
129
    /**
130
     * Holds the value of take count, this value is depends on
131
     * presence of $top option and configured page size.
132
     *
133
     * @var int|null
134
     */
135
    private $topCount;
136
137
    /**
138
     * Holds the value of $top query option, if no $top option
139
     * found then this parameter will be NULL.
140
     *
141
     * @var int|null
142
     */
143
    private $topOptionCount;
144
145
    /**
146
     * Holds the parsed details for sorting, this will
147
     * be set in 3 cases
148
     * (1) if $orderby option is specified in the request uri
149
     * (2) if $skip or $top option is specified in the request uri
150
     * (3) if server side paging is enabled for the resource
151
     *     targeted by the request uri.
152
     *
153
     * @var InternalOrderByInfo|null
154
     */
155
    private $internalOrderByInfo;
156
157
    /**
158
     * Holds the parsed details for $skiptoken option, this will
159
     * be NULL if $skiptoken option is absent.
160
     *
161
     * @var InternalSkipTokenInfo|null
162
     */
163
    private $internalSkipTokenInfo;
164
165
    /**
166
     * Holds the parsed details for $filter option, this will be NULL if $filter option is absent.
167
     *
168
     * @var FilterInfo|null
169
     */
170
    private $filterInfo;
171
172
    /**
173
     * Holds reference to the root of the tree describing expand
174
     * and select information, this field will be NULL if no
175
     * $expand or $select specified in the request uri.
176
     *
177
     * @var RootProjectionNode|null
178
     */
179
    private $rootProjectionNode;
180
181
    /**
182
     * Holds number of entities in the result set, if either $count or
183
     * $inlinecount=allpages is specified, otherwise NULL.
184
     *
185
     *
186
     * @var int|null
187
     */
188
    private $countValue;
189
190
    /**
191
     * Data of request from request body.
192
     *
193
     * @var array|string|ODataFeed|ODataEntry|null
194
     */
195
    private $data;
196
197
    /**
198
     * Flag indicating status of query execution.
199
     *
200
     * @var bool
201
     */
202
    private $isExecuted;
203
204
    /**
205
     * Reference to Uri processor.
206
     *
207
     * @var IUriProcessor
208
     */
209
    private $uriProcessor;
210
    /**
211
     * @var ODataReaderRegistry
212
     */
213
    private $readerRegistry;
214
215
    /**
216
     * @param  SegmentDescriptor[] $segmentDescriptors Description of segments
217
     *                                                 in the resource path
218
     * @param  Url                 $requestUri
219
     * @param  Version             $serviceMaxVersion
220
     * @param  string|null         $requestVersion
221
     * @param  string|null         $maxRequestVersion
222
     * @param  string|null         $dataType
223
     * @param  IHTTPRequest|null   $payload
224
     * @param  ODataReaderRegistry $readerRegistry
225
     * @throws ODataException
226
     */
227
    public function __construct(
228
        array $segmentDescriptors,
229
        Url $requestUri,
230
        Version $serviceMaxVersion,
231
        $requestVersion,
232
        $maxRequestVersion,
233
        $dataType = null,
234
        IHTTPRequest $payload = null,
235
        ODataReaderRegistry $readerRegistry = null
236
    ) {
237
        $this->readerRegistry = $readerRegistry;
238
        $this->segments       = $segmentDescriptors;
239
        $this->segmentCount   = count($this->segments);
240
        $this->requestUrl     = $requestUri;
241
        $this->lastSegment    = $segmentDescriptors[$this->segmentCount - 1];
242
        $this->queryType      = QueryType::ENTITIES();
243
        //we use this for validation checks down in validateVersions...
244
        //but maybe we should check that outside of this object...
245
        $this->maxServiceVersion = $serviceMaxVersion;
246
247
        //Per OData 1 & 2 spec we must return the smallest size
248
        //We start at 1.0 and move it up as features are requested
249
        $this->requiredMinResponseVersion = clone Version::v1();
250
        $this->requiredMinRequestVersion  = clone Version::v1();
251
252
        //see http://www.odata.org/documentation/odata-v2-documentation/overview/#ProtocolVersioning
253
        //if requestVersion isn't there, use Service Max Version
254
        $this->requestVersion = null === $requestVersion
255
            ? $serviceMaxVersion
256
            : self::parseVersionHeader($requestVersion, ODataConstants::ODATAVERSIONHEADER);
257
258
        //if max version isn't there, use the request version
259
        $this->requestMaxVersion = null === $maxRequestVersion
260
            ? $this->requestVersion
261
            : self::parseVersionHeader($maxRequestVersion, ODataConstants::ODATAMAXVERSIONHEADER);
262
263
        //if it's OData v3..things change a bit
264
        if ($this->maxServiceVersion == Version::v3()) {
265
            if (null === $maxRequestVersion) {
266
                //if max request version isn't specified we use the service max version instead of the request version
267
                //thus we favour newer versions
268
                $this->requestMaxVersion = $this->maxServiceVersion;
269
            }
270
271
            //also we change min response version to be the max version, again favoring later things
272
            //note that if the request max version is specified, it is still respected
273
            $this->requiredMinResponseVersion = clone $this->requestMaxVersion;
274
        }
275
276
        $this->containerName         = null;
277
        $this->skipCount             = null;
278
        $this->topCount              = null;
279
        $this->topOptionCount        = null;
280
        $this->internalOrderByInfo   = null;
281
        $this->internalSkipTokenInfo = null;
282
283
        $this->filterInfo = null;
284
        $this->countValue = null;
285
        $this->isExecuted = false;
286
        $this->data       = isset($payload) ? $payload->getAllInput() : null;
287
288
        // Define data from request body
289
        if (null !== $dataType) {
290
            $this->readData($dataType);
291
        }
292
    }
293
294
    /**
295
     * Validates the given version in string format and returns the version as instance of Version.
296
     *
297
     * @param string $versionHeader The DataServiceVersion or MaxDataServiceVersion header value
298
     * @param string $headerName    The name of the header
299
     *
300
     * @throws ODataException If the version is malformed or not supported
301
     * @return Version
302
     */
303
    private static function parseVersionHeader($versionHeader, $headerName)
304
    {
305
        $versionHeader = trim($versionHeader);
306
        $libNameIndex  = strpos($versionHeader, ';');
307
        if (false === $libNameIndex) {
308
            $libNameIndex = strlen($versionHeader);
309
        }
310
311
        $dotIndex      = -1;
312
        $badVersionMsg = Messages::requestDescriptionInvalidVersionHeader(
313
            $versionHeader,
314
            $headerName
315
        );
316
        for ($i = 0; $i < $libNameIndex; ++$i) {
317
            if ($versionHeader[$i] == '.') {
318
                //Throw an exception if we find more than 1 dot
319
                if ($dotIndex != -1) {
320
                    throw ODataException::createBadRequestError($badVersionMsg);
321
                }
322
323
                $dotIndex = $i;
324
            } elseif ($versionHeader[$i] < '0' || $versionHeader[$i] > '9') {
325
                throw ODataException::createBadRequestError($badVersionMsg);
326
            }
327
        }
328
329
        $major = intval(substr($versionHeader, 0, $dotIndex));
330
        $minor = 0;
331
332
        //Apparently the . is optional
333
        if ($dotIndex != -1) {
334
            if ($dotIndex == 0) {
335
                //If it starts with a ., throw an exception
336
                throw ODataException::createBadRequestError($badVersionMsg);
337
            }
338
            $minor = intval(substr($versionHeader, $dotIndex + 1, $libNameIndex));
339
        }
340
341
        $version = new Version($major, $minor);
342
343
        //TODO: move this somewhere...
344
        //$this->validateVersions();
345
        $isSupportedVersion = false;
346
        foreach (self::getKnownDataServiceVersions() as $version1) {
347
            if ($version->compare($version1) == 0) {
348
                $isSupportedVersion = true;
349
                break;
350
            }
351
        }
352
353
        if (!$isSupportedVersion) {
354
            $availableVersions = null;
355
            foreach (self::getKnownDataServiceVersions() as $version1) {
356
                $availableVersions .= $version1->toString() . ', ';
357
            }
358
359
            $availableVersions = rtrim($availableVersions, ', ');
0 ignored issues
show
Bug introduced by
It seems like $availableVersions can also be of type null; however, parameter $string of rtrim() does only seem to accept string, 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

359
            $availableVersions = rtrim(/** @scrutinizer ignore-type */ $availableVersions, ', ');
Loading history...
360
            throw ODataException::createBadRequestError(
361
                Messages::requestDescriptionUnSupportedVersion(
362
                    $headerName,
363
                    $versionHeader,
364
                    $availableVersions
365
                )
366
            );
367
        }
368
369
        return $version;
370
    }
371
372
    /**
373
     * Gets collection of known data service versions, currently 1.0, 2.0 and 3.0.
374
     *
375
     * @return Version[]
376
     */
377
    public static function getKnownDataServiceVersions()
378
    {
379
        if (null === self::$knownDataServiceVersions) {
0 ignored issues
show
introduced by
The condition null === self::knownDataServiceVersions is always false.
Loading history...
380
            self::$knownDataServiceVersions = [
381
                new Version(1, 0),
382
                new Version(2, 0),
383
                new Version(3, 0),
384
            ];
385
        }
386
387
        return self::$knownDataServiceVersions;
388
    }
389
390
    /**
391
     * Define request data from body.
392
     *
393
     * @param  string $dataType
394
     * @return void
395
     */
396
    private function readData($dataType)
397
    {
398
        if (null === $this->data) {
399
            return;
400
        }
401
        $string = $this->data;
402
        if ($dataType === MimeTypes::MIME_APPLICATION_JSON) {
403
            $data       = !is_array($string) ? json_decode($string, true) : $string;
0 ignored issues
show
Bug introduced by
It seems like $string can also be of type POData\ObjectModel\ODataEntry and POData\ObjectModel\ODataFeed; however, parameter $json of json_decode() does only seem to accept string, 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

403
            $data       = !is_array($string) ? json_decode(/** @scrutinizer ignore-type */ $string, true) : $string;
Loading history...
404
            $this->data = $data;
405
            return;
406
        }
407
408
        $reader = $this->readerRegistry->getReader($this->requestVersion, $dataType);
409
        if ($reader !== null) {
410
            if (is_array($string) && 1 == count($string)) {
411
                $string = $string[0];
412
            }
413
            if (0 == strlen(trim($string))) {
414
                return;
415
            }
416
            $this->data = $reader->read($string);
417
        }
418
    }
419
420
    /**
421
     * Get request data from body.
422
     */
423
    public function getData()
424
    {
425
        return $this->data;
426
    }
427
428
    /**
429
     * Raise the minimum client version requirement for this request and
430
     * perform capability negotiation.
431
     *
432
     * @param int $major The major segment of the version
433
     * @param int $minor The minor segment of the version
434
     *
435
     * @throws ODataException If capability negotiation fails
436
     */
437
    public function raiseMinVersionRequirement($major, $minor)
438
    {
439
        if ($this->requiredMinRequestVersion->raiseVersion($major, $minor)) {
440
            $this->validateVersions();
441
        }
442
    }
443
444
    /**
445
     * This function is used to perform following checking (validation)
446
     * for capability negotiation.
447
     *  (1) Check client request's 'DataServiceVersion' header value is
448
     *      less than or equal to the minimum version required to intercept
449
     *      the response
450
     *  (2) Check client request's 'MaxDataServiceVersion' header value is
451
     *      less than or equal to the version of protocol required to generate
452
     *      the response
453
     *  (3) Check the configured maximum protocol version is less than or equal
454
     *      to the version of protocol required to generate the response
455
     *  In addition to these checking, this function is also responsible for
456
     *  initializing the properties representing 'DataServiceVersion' and
457
     *  'MaxDataServiceVersion'.
458
     *
459
     *
460
     * @throws ODataException If any of the above 3 check fails
461
     */
462
    public function validateVersions()
463
    {
464
465
        //If the request version is below the minimum version required by supplied request arguments..throw an exception
466
        if ($this->requestVersion->compare($this->requiredMinRequestVersion) < 0) {
467
            throw ODataException::createBadRequestError(
468
                Messages::requestVersionTooLow(
469
                    $this->requestVersion->toString(),
470
                    $this->requiredMinRequestVersion->toString()
471
                )
472
            );
473
        }
474
475
        //If the requested max version is below the version required to fulfill the response...throw an exception
476
        if ($this->requestMaxVersion->compare($this->requiredMinResponseVersion) < 0) {
477
            throw ODataException::createBadRequestError(
478
                Messages::requestVersionTooLow(
479
                    $this->requestMaxVersion->toString(),
480
                    $this->requiredMinResponseVersion->toString()
481
                )
482
            );
483
        }
484
485
        //If the max version supported by the service is below the version required to fulfill the response..
486
        //throw an exception
487
        if ($this->maxServiceVersion->compare($this->requiredMinResponseVersion) < 0) {
488
            throw ODataException::createBadRequestError(
489
                Messages::requestVersionIsBiggerThanProtocolVersion(
490
                    $this->requiredMinResponseVersion->toString(),
491
                    $this->maxServiceVersion->toString()
492
                )
493
            );
494
        }
495
    }
496
497
    /**
498
     * Raise the response version for this request and perform capability negotiation.
499
     *
500
     *
501
     * @param int $major The major segment of the version
502
     * @param int $minor The minor segment of the version
503
     *
504
     * @throws ODataException If capability negotiation fails
505
     */
506
    public function raiseResponseVersion($major, $minor)
507
    {
508
        if ($this->requiredMinResponseVersion->raiseVersion($major, $minor)) {
509
            $this->validateVersions();
510
        }
511
    }
512
513
    /**
514
     * Gets collection of segment descriptors containing information about
515
     * each segment in the resource path part of the request uri.
516
     *
517
     * @return SegmentDescriptor[]
518
     */
519
    public function getSegments()
520
    {
521
        return $this->segments;
522
    }
523
524
    /**
525
     * Gets reference to the descriptor of last segment.
526
     *
527
     * @return SegmentDescriptor
528
     */
529
    public function getLastSegment()
530
    {
531
        return $this->lastSegment;
532
    }
533
534
    /**
535
     * Gets kind of resource targeted by the resource path.
536
     *
537
     * @return TargetKind
538
     */
539
    public function getTargetKind()
540
    {
541
        return $this->lastSegment->getTargetKind();
542
    }
543
544
    /**
545
     * Gets kind of 'source of data' targeted by the resource path.
546
     *
547
     * @return TargetSource
548
     */
549
    public function getTargetSource()
550
    {
551
        return $this->lastSegment->getTargetSource();
552
    }
553
554
    /**
555
     * Gets reference to the ResourceSetWrapper instance targeted by
556
     * the resource path, ResourceSetWrapper will present in the
557
     * following cases:
558
     * if the last segment descriptor describes
559
     *      (a) resource set
560
     *          http://server/NW.svc/Customers
561
     *          http://server/NW.svc/Customers('ALFKI')
562
     *          http://server/NW.svc/Customers('ALFKI')/Orders
563
     *          http://server/NW.svc/Customers('ALFKI')/Orders(123)
564
     *          http://server/NW.svc/Customers('ALFKI')/$links/Orders
565
     *      (b) resource set reference
566
     *          http://server/NW.svc/Orders(123)/Customer
567
     *          http://server/NW.svc/Orders(123)/$links/Customer
568
     *      (c) $count
569
     *          http://server/NW.svc/Customers/$count
570
     * ResourceSet wrapper will be absent (NULL) in the following cases:
571
     * if the last segment descriptor describes
572
     *      (a) Primitive
573
     *          http://server/NW.svc/Customers('ALFKI')/Country
574
     *      (b) $value on primitive type
575
     *          http://server/NW.svc/Customers('ALFKI')/Country/$value
576
     *      (c) Complex
577
     *          http://server/NW.svc/Customers('ALFKI')/Address
578
     *      (d) Bag
579
     *          http://server/NW.svc/Employees(123)/Emails
580
     *      (e) MLE
581
     *          http://server/NW.svc/Employees(123)/$value
582
     *      (f) Named Stream
583
     *          http://server/NW.svc/Employees(123)/Thumbnail48_48
584
     *      (g) metadata
585
     *          http://server/NW.svc/$metadata
586
     *      (h) service directory
587
     *          http://server/NW.svc
588
     *      (i) $bath
589
     *          http://server/NW.svc/$batch.
590
     *
591
     * @return ResourceSetWrapper|null
592
     */
593
    public function getTargetResourceSetWrapper()
594
    {
595
        return $this->lastSegment->getTargetResourceSetWrapper();
596
    }
597
598
    /**
599
     * Gets reference to the ResourceProperty instance targeted by
600
     * the resource path, ResourceProperty will present in the
601
     * following cases:
602
     * if the last segment descriptor describes
603
     *      (a) resource set (after 1 level)
604
     *          http://server/NW.svc/Customers('ALFKI')/Orders
605
     *          http://server/NW.svc/Customers('ALFKI')/Orders(123)
606
     *          http://server/NW.svc/Customers('ALFKI')/$links/Orders
607
     *      (b) resource set reference
608
     *          http://server/NW.svc/Orders(123)/Customer
609
     *          http://server/NW.svc/Orders(123)/$links/Customer
610
     *      (c) $count
611
     *          http://server/NW.svc/Customers/$count
612
     *      (d) Primitive
613
     *          http://server/NW.svc/Customers('ALFKI')/Country
614
     *      (e) $value on primitive type
615
     *          http://server/NW.svc/Customers('ALFKI')/Country/$value
616
     *      (f) Complex
617
     *          http://server/NW.svc/Customers('ALFKI')/Address
618
     *      (g) Bag
619
     *          http://server/NW.svc/Employees(123)/Emails
620
     *      (h) MLE
621
     *          http://server/NW.svc/Employees(123)/$value.
622
     *
623
     * ResourceType will be absent (NULL) in the following cases:
624
     * if the last segment descriptor describes
625
     *      (a) If last segment is the only segment pointing to
626
     *          ResourceSet (single or multiple)
627
     *          http://server/NW.svc/Customers
628
     *          http://server/NW.svc/Customers('ALFKI')
629
     *      (b) Named Stream
630
     *          http://server/NW.svc/Employees(123)/Thumbnail48_48
631
     *      (c) metadata
632
     *          http://server/NW.svc/$metadata
633
     *      (d) service directory
634
     *          http://server/NW.svc
635
     *      (e) $bath
636
     *          http://server/NW.svc/$batch
637
     *
638
     * @return ResourceProperty|null
639
     */
640
    public function getProjectedProperty()
641
    {
642
        return $this->lastSegment->getProjectedProperty();
643
    }
644
645
    /**
646
     * Gets the name of the container for results.
647
     *
648
     * @return string
649
     */
650
    public function getContainerName()
651
    {
652
        return $this->containerName;
653
    }
654
655
    /**
656
     * Sets the name of the container for results.
657
     *
658
     * @param string $containerName The container name
659
     */
660
    public function setContainerName($containerName)
661
    {
662
        $this->containerName = $containerName;
663
    }
664
665
    /**
666
     * Whether thr request targets a single result or not.
667
     *
668
     * @return bool
669
     */
670
    public function isSingleResult()
671
    {
672
        return $this->lastSegment->isSingleResult();
673
    }
674
675
    /**
676
     * Gets the identifier associated with the the resource path.
677
     *
678
     * @return string
679
     */
680
    public function getIdentifier()
681
    {
682
        return $this->lastSegment->getIdentifier();
683
    }
684
685
    /**
686
     * Gets the request uri.
687
     *
688
     * @return Url
689
     */
690
    public function getRequestUrl()
691
    {
692
        return $this->requestUrl;
693
    }
694
695
    /**
696
     * Gets the value of $skip query option.
697
     *
698
     * @return int|null The value of $skip query option, NULL if $skip is absent
699
     */
700
    public function getSkipCount()
701
    {
702
        return $this->skipCount;
703
    }
704
705
    /**
706
     * Sets skip value.
707
     *
708
     * @param int $skipCount The value of $skip query option
709
     */
710
    public function setSkipCount($skipCount)
711
    {
712
        $this->skipCount = $skipCount;
713
    }
714
715
    /**
716
     * Gets the value of take count.
717
     *
718
     * @return int|null The value of take, NULL if no take to be applied
719
     */
720
    public function getTopCount()
721
    {
722
        return $this->topCount;
723
    }
724
725
    /**
726
     * Sets the value of take count.
727
     *
728
     * @param int $topCount The value of take query option
729
     */
730
    public function setTopCount($topCount)
731
    {
732
        $this->topCount = $topCount;
733
    }
734
735
    /**
736
     * Gets the value of $top query option.
737
     *
738
     * @return int|null The value of $top query option, NULL if $top is absent
739
     */
740
    public function getTopOptionCount()
741
    {
742
        return $this->topOptionCount;
743
    }
744
745
    /**
746
     * Sets top value.
747
     *
748
     * @param int $topOptionCount The value of $top query option
749
     */
750
    public function setTopOptionCount($topOptionCount)
751
    {
752
        $this->topOptionCount = $topOptionCount;
753
    }
754
755
    /**
756
     * Gets sorting (orderby) information, this function return
757
     * sorting information in 3 cases:
758
     * (1) if $orderby option is specified in the request uri
759
     * (2) if $skip or $top option is specified in the request uri
760
     * (3) if server side paging is enabled for the resource targeted
761
     *     by the request uri.
762
     *
763
     * @return InternalOrderByInfo|null
764
     */
765
    public function getInternalOrderByInfo()
766
    {
767
        return $this->internalOrderByInfo;
768
    }
769
770
    /**
771
     * Sets sorting (orderby) information.
772
     *
773
     * @param InternalOrderByInfo &$internalOrderByInfo The sorting information
774
     */
775
    public function setInternalOrderByInfo(InternalOrderByInfo &$internalOrderByInfo)
776
    {
777
        $this->internalOrderByInfo = $internalOrderByInfo;
778
    }
779
780
    /**
781
     * Gets the parsed details for $skiptoken option.
782
     *
783
     * @return InternalSkipTokenInfo|null Returns parsed details of $skiptoken option, NULL if $skiptoken is absent
784
     */
785
    public function getInternalSkipTokenInfo()
786
    {
787
        return $this->internalSkipTokenInfo;
788
    }
789
790
    /**
791
     * Sets $skiptoken information.
792
     *
793
     * @param InternalSkipTokenInfo &$internalSkipTokenInfo The paging information
794
     */
795
    public function setInternalSkipTokenInfo(
796
        InternalSkipTokenInfo &$internalSkipTokenInfo
797
    ) {
798
        $this->internalSkipTokenInfo = $internalSkipTokenInfo;
799
    }
800
801
    /**
802
     * @return FilterInfo|null Returns parsed details of $filter option, NULL if $filter is absent
803
     */
804
    public function getFilterInfo()
805
    {
806
        return $this->filterInfo;
807
    }
808
809
    /**
810
     * @param FilterInfo $filterInfo The filter information
811
     */
812
    public function setFilterInfo(FilterInfo $filterInfo)
813
    {
814
        $this->filterInfo = $filterInfo;
815
    }
816
817
    /**
818
     * Gets the root of the tree describing expand and select options,.
819
     *
820
     * @return RootProjectionNode|null Returns parsed details of $expand
821
     *                                 and $select options, NULL if
822
     *                                 $both options are absent
823
     */
824
    public function getRootProjectionNode()
825
    {
826
        return $this->rootProjectionNode;
827
    }
828
829
    /**
830
     * Sets $expand and $select information.
831
     *
832
     * @param RootProjectionNode &$rootProjectionNode Root of the projection tree
833
     */
834
    public function setRootProjectionNode(RootProjectionNode &$rootProjectionNode)
835
    {
836
        $this->rootProjectionNode = $rootProjectionNode;
837
    }
838
839
    /**
840
     * Gets the count of result set if $count or $inlinecount=allpages
841
     * has been applied otherwise NULL.
842
     *
843
     * @return int|null
844
     */
845
    public function getCountValue()
846
    {
847
        return $this->countValue;
848
    }
849
850
    /**
851
     * Sets the count of result set.
852
     *
853
     * @param int $countValue The count value
854
     */
855
    public function setCountValue($countValue)
856
    {
857
        $this->countValue = $countValue;
858
    }
859
860
    /**
861
     * To set the flag indicating the execution status as true.
862
     */
863
    public function setExecuted()
864
    {
865
        $this->isExecuted = true;
866
    }
867
868
    /**
869
     * To check whether to execute the query using IDSQP.
870
     *
871
     * @return bool True if query need to be executed, False otherwise
872
     */
873
    public function needExecution()
874
    {
875
        return !$this->isExecuted
876
            && ($this->lastSegment->getTargetKind() != TargetKind::METADATA())
877
            && ($this->lastSegment->getTargetKind() != TargetKind::SERVICE_DIRECTORY());
878
    }
879
880
    /**
881
     * Get ResourceStreamInfo for the media link entry or named stream request.
882
     *
883
     * @return ResourceStreamInfo|null Instance of ResourceStreamInfo if the
884
     *                                 current request targets named stream, NULL for MLE
885
     */
886
    public function getResourceStreamInfo()
887
    {
888
        //assert($this->isMediaResource)
889
        if ($this->isNamedStream()) {
890
            return $this->getTargetResourceType()
891
                ->tryResolveNamedStreamByName(
892
                    $this->lastSegment->getIdentifier()
893
                );
894
        }
895
        return null;
896
    }
897
898
    /**
899
     * To check if the resource path is a request for named stream.
900
     *
901
     * @return bool True if request is for named stream else false
902
     */
903
    public function isNamedStream()
904
    {
905
        return $this->isMediaResource() && !($this->lastSegment->getIdentifier() === ODataConstants::URI_VALUE_SEGMENT);
906
    }
907
908
    /**
909
     * To check if the resource path is a request for media resource.
910
     *
911
     * @return bool True if request is for media resource else false
912
     */
913
    public function isMediaResource()
914
    {
915
        return $this->lastSegment->getTargetKind() == TargetKind::MEDIA_RESOURCE();
916
    }
917
918
    /**
919
     * Gets reference to the ResourceType instance targeted by
920
     * the resource path, ResourceType will present in the
921
     * following cases:
922
     * if the last segment descriptor describes
923
     *      (a) resource set
924
     *          http://server/NW.svc/Customers
925
     *          http://server/NW.svc/Customers('ALFKI')
926
     *          http://server/NW.svc/Customers('ALFKI')/Orders
927
     *          http://server/NW.svc/Customers('ALFKI')/Orders(123)
928
     *          http://server/NW.svc/Customers('ALFKI')/$links/Orders
929
     *      (b) resource set reference
930
     *          http://server/NW.svc/Orders(123)/Customer
931
     *          http://server/NW.svc/Orders(123)/$links/Customer
932
     *      (c) $count
933
     *          http://server/NW.svc/Customers/$count
934
     *      (d) Primitive
935
     *          http://server/NW.svc/Customers('ALFKI')/Country
936
     *      (e) $value on primitive type
937
     *          http://server/NW.svc/Customers('ALFKI')/Country/$value
938
     *      (f) Complex
939
     *          http://server/NW.svc/Customers('ALFKI')/Address
940
     *      (g) Bag
941
     *          http://server/NW.svc/Employees(123)/Emails
942
     *      (h) MLE
943
     *          http://server/NW.svc/Employees(123)/$value
944
     *      (i) Named Stream
945
     *          http://server/NW.svc/Employees(123)/Thumbnail48_48
946
     * ResourceType will be absent (NULL) in the following cases:
947
     * if the last segment descriptor describes
948
     *      (a) metadata
949
     *          http://server/NW.svc/$metadata
950
     *      (b) service directory
951
     *          http://server/NW.svc
952
     *      (c) $bath
953
     *          http://server/NW.svc/$batch.
954
     *
955
     * @return ResourceType|null
956
     */
957
    public function getTargetResourceType()
958
    {
959
        return $this->lastSegment->getTargetResourceType();
960
    }
961
962
    /**
963
     * Gets the resource instance targeted by the request uri.
964
     * Note: This value will be populated after query execution only.
965
     *
966
     * @return mixed
967
     */
968
    public function getTargetResult()
969
    {
970
        return $this->lastSegment->getResult();
971
    }
972
973
    /**
974
     * Gets the OData version the server used to generate the response.
975
     *
976
     * @return Version
977
     */
978
    public function getResponseVersion()
979
    {
980
        return $this->requiredMinResponseVersion;
981
    }
982
983
    /**
984
     * Checks whether etag headers are allowed for this request.
985
     *
986
     * @return bool True if ETag header (If-Match or If-NoneMatch)
987
     *              is allowed for the request, False otherwise
988
     */
989
    public function isETagHeaderAllowed()
990
    {
991
        return $this->lastSegment->isSingleResult()
992
            && ($this->queryType != QueryType::COUNT())
993
            && !$this->isLinkUri()
994
            && (
995
                null === $this->rootProjectionNode
996
                || !($this->rootProjectionNode->isExpansionSpecified())
997
            );
998
    }
999
1000
    /**
1001
     * To check if the resource path is a request for link uri.
1002
     *
1003
     * @return bool True if request is for link uri else false
1004
     */
1005
    public function isLinkUri()
1006
    {
1007
        return ($this->segmentCount > 2)
1008
            && ($this->segments[$this->segmentCount - 2]->getTargetKind() == TargetKind::LINK());
1009
    }
1010
1011
    /**
1012
     * Gets reference to the IUriProcessor instance.
1013
     *
1014
     * @return IUriProcessor
1015
     */
1016
    public function getUriProcessor()
1017
    {
1018
        return $this->uriProcessor;
1019
    }
1020
1021
    /**
1022
     * Set reference to IUriProcessor instance.
1023
     *
1024
     * @param IUriProcessor $uriProcessor Reference to the UriProcessor
1025
     */
1026
    public function setUriProcessor(IUriProcessor $uriProcessor)
1027
    {
1028
        $this->uriProcessor = $uriProcessor;
1029
    }
1030
}
1031