Passed
Push — master ( 492d83...a726fe )
by Alex
01:10
created

QueryProcessor::processSkipAndTop()   D

Complexity

Conditions 9
Paths 32

Size

Total Lines 37
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 37
rs 4.909
c 0
b 0
f 0
cc 9
eloc 23
nc 32
nop 0
1
<?php
2
3
namespace POData\UriProcessor\QueryProcessor;
4
5
use POData\Common\Messages;
6
use POData\Common\ODataConstants;
7
use POData\Common\ODataException;
8
use POData\IService;
9
use POData\Providers\Metadata\ResourceTypeKind;
10
use POData\Providers\Metadata\Type\Int32;
11
use POData\Providers\Query\QueryType;
12
use POData\UriProcessor\QueryProcessor\ExpandProjectionParser\ExpandProjectionParser;
13
use POData\UriProcessor\QueryProcessor\ExpressionParser\ExpressionParser2;
14
use POData\UriProcessor\QueryProcessor\OrderByParser\OrderByParser;
15
use POData\UriProcessor\QueryProcessor\SkipTokenParser\SkipTokenParser;
16
use POData\UriProcessor\RequestDescription;
17
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\TargetKind;
18
use POData\UriProcessor\ResourcePathProcessor\SegmentParser\TargetSource;
19
20
/**
21
 * Class QueryProcessor.
22
 */
23
class QueryProcessor
24
{
25
    /**
26
     * Holds details of the request that client has submitted.
27
     *
28
     * @var RequestDescription
29
     */
30
    private $request;
31
32
    /**
33
     * Holds reference to the underlying data service specific
34
     * instance.
35
     *
36
     * @var IService
37
     */
38
    private $service;
39
40
    /**
41
     * If $orderby, $skip, $top and $count options can be applied to the request.
42
     *
43
     * @var bool
44
     */
45
    private $setQueryApplicable;
46
47
    /**
48
     * Whether the top level request is a candidate for paging.
49
     *
50
     * @var bool
51
     */
52
    private $pagingApplicable;
53
54
    /**
55
     * Whether $expand, $select can be applied to the request.
56
     *
57
     * @var bool
58
     */
59
    private $expandSelectApplicable;
60
61
    /**
62
     * Creates new instance of QueryProcessor.
63
     *
64
     * @param RequestDescription $request Description of the request submitted by client
65
     * @param IService           $service Reference to the service implementation
66
     */
67
    private function __construct(RequestDescription $request, IService $service)
68
    {
69
        $this->request = $request;
70
        $this->service = $service;
71
72
        $isSingleResult = $request->isSingleResult();
73
74
        //$top, $skip, $order, $inlinecount & $count are only applicable if:
0 ignored issues
show
Unused Code Comprehensibility introduced by
48% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
75
        //The query targets a resource collection
76
        $this->setQueryApplicable = ($request->getTargetKind() == TargetKind::RESOURCE() && !$isSingleResult);
77
        //Or it's a $count resource (although $inlinecount isn't applicable in this case..
78
        //but there's a check somewhere else for this
79
        $this->setQueryApplicable |= $request->queryType == QueryType::COUNT();
80
81
        //Paging is allowed if
82
        //The request targets a resource collection
83
        //and the request isn't for a $count segment
84
        $this->pagingApplicable = $this->request->getTargetKind() == TargetKind::RESOURCE()
85
                                   && !$isSingleResult
86
                                   && ($request->queryType != QueryType::COUNT());
87
88
        $targetResourceType = $this->request->getTargetResourceType();
89
        $targetResourceSetWrapper = $this->request->getTargetResourceSetWrapper();
90
91
        $this->expandSelectApplicable = !is_null($targetResourceType)
92
            && !is_null($targetResourceSetWrapper)
93
            && $targetResourceType->getResourceTypeKind() == ResourceTypeKind::ENTITY
94
            && !$this->request->isLinkUri();
95
    }
96
97
    /**
98
     * Process the OData query options and update RequestDescription accordingly.
99
     *
100
     * @param RequestDescription $request Description of the request submitted by client
101
     * @param IService           $service Reference to the data service
102
     *
103
     * @throws ODataException
104
     */
105
    public static function process(RequestDescription $request, IService $service)
106
    {
107
        $queryProcessor = new self($request, $service);
108
        if ($request->getTargetSource() == TargetSource::NONE) {
109
            //A service directory, metadata or batch request
110
            $queryProcessor->checkForEmptyQueryArguments();
111
        } else {
112
            $queryProcessor->processQuery();
113
        }
114
115
        unset($queryProcessor);
116
    }
117
118
    /**
119
     * Processes the odata query options in the request uri and update the request description
120
     * instance with processed details.
121
     *
122
     * @throws ODataException If any error occured while processing the query options
123
     */
124
    private function processQuery()
125
    {
126
        $this->processSkipAndTop();
127
        $this->processOrderBy();
128
        $this->processFilter();
129
        $this->processCount();
130
        $this->processSkipToken();
131
        $this->processExpandAndSelect();
132
    }
133
134
    /**
135
     * Process $skip and $top options.
136
     *
137
     *
138
     * @throws ODataException Throws syntax error if the $skip or $top option
139
     *                        is specified with non-integer value, throws
140
     *                        bad request error if the $skip or $top option
141
     *                        is not applicable for the requested resource
142
     */
143
    private function processSkipAndTop()
144
    {
145
        $value = null;
146
        if ($this->readSkipOrTopOption(ODataConstants::HTTPQUERY_STRING_SKIP, $value)) {
147
            $this->request->setSkipCount($value);
148
        }
149
150
        $pageSize = 0;
151
        $isPagingRequired = $this->isSSPagingRequired();
152
        if ($isPagingRequired) {
153
            $pageSize = $this->request
154
                ->getTargetResourceSetWrapper()
155
                ->getResourceSetPageSize();
156
        }
157
158
        if ($this->readSkipOrTopOption(ODataConstants::HTTPQUERY_STRING_TOP, $value)) {
159
            $this->request->setTopOptionCount($value);
160
            if ($isPagingRequired && $pageSize < $value) {
161
                //If $top is greater than or equal to page size,
162
                //we will need a $skiptoken and thus our response
163
                //will be 2.0
164
                $this->request->raiseResponseVersion(2, 0);
165
                $this->request->setTopCount($pageSize);
166
            } else {
167
                $this->request->setTopCount($value);
168
            }
169
        } elseif ($isPagingRequired) {
170
            $this->request->raiseResponseVersion(2, 0);
171
            $this->request->setTopCount($pageSize);
172
        }
173
174
        if (!is_null($this->request->getSkipCount())
175
            || !is_null($this->request->getTopCount())
176
        ) {
177
            $this->checkSetQueryApplicable();
178
        }
179
    }
180
181
    /**
182
     * Process $orderby option, This function requires _processSkipAndTopOption
183
     * function to be already called as this function need to know whether
184
     * client has requested for skip, top or paging is enabled for the
185
     * requested resource in these cases function generates additional orderby
186
     * expression using keys.
187
     *
188
     *
189
     * @throws ODataException If any error occurs while parsing orderby option
190
     */
191
    private function processOrderBy()
192
    {
193
        $orderBy = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_ORDERBY);
194
195
        if (!is_null($orderBy)) {
196
            $this->checkSetQueryApplicable();
197
        }
198
199
        $targetResourceType = $this->request->getTargetResourceType();
200
        assert($targetResourceType != null, "Request target resource type must not be null");
201
        /*
202
         * We need to do sorting in the folowing cases, irrespective of
203
         * $orderby clause is present or not.
204
         * 1. If $top or $skip is specified
205
         *     skip and take will be applied on sorted list only. If $skip
206
         *     is specified then RequestDescription::getSkipCount will give
207
         *     non-null value. If $top is specified then
208
         *     RequestDescription::getTopCount will give non-null value.
209
         * 2. If server side paging is enabled for the requested resource
210
         *     If server-side paging is enabled for the requested resource then
211
         *     RequestDescription::getTopCount will give non-null value.
212
         *
213
         */
214
        if (!is_null($this->request->getSkipCount()) || !is_null($this->request->getTopCount())) {
215
            $orderBy = !is_null($orderBy) ? $orderBy . ', ' : null;
216
            $keys = array_keys($targetResourceType->getKeyProperties());
217
            //assert(!empty($keys))
0 ignored issues
show
Unused Code Comprehensibility introduced by
88% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
218
            foreach ($keys as $key) {
219
                $orderBy = $orderBy . $key . ', ';
220
            }
221
222
            $orderBy = rtrim($orderBy, ', ');
223
        }
224
225
        if (!is_null($orderBy)) {
226
            $setWrapper = $this->request->getTargetResourceSetWrapper();
227
            assert(null != $setWrapper, "Target resource set wrapper must not be null");
228
            $internalOrderByInfo = OrderByParser::parseOrderByClause(
229
                $setWrapper,
230
                $targetResourceType,
231
                $orderBy,
232
                $this->service->getProvidersWrapper()
233
            );
234
235
            $this->request->setInternalOrderByInfo(
236
                $internalOrderByInfo
237
            );
238
        }
239
    }
240
241
    /**
242
     * Process the $filter option in the request and update request decription.
243
     *
244
     *
245
     * @throws ODataException Throws error in the following cases:
246
     *                        (1) If $filter cannot be applied to the
247
     *                        resource targeted by the request uri
248
     *                        (2) If any error occured while parsing and
249
     *                        translating the odata $filter expression
250
     *                        to expression tree
251
     *                        (3) If any error occured while generating
252
     *                        php expression from expression tree
253
     */
254
    private function processFilter()
255
    {
256
        $filter = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_FILTER);
257
        if (is_null($filter)) {
258
            return;
259
        }
260
261
        $kind = $this->request->getTargetKind();
262
        if (!($kind == TargetKind::RESOURCE()
263
            || $kind == TargetKind::COMPLEX_OBJECT()
264
            || $this->request->queryType == QueryType::COUNT())
265
        ) {
266
            throw ODataException::createBadRequestError(
267
                Messages::queryProcessorQueryFilterOptionNotApplicable()
268
            );
269
        }
270
        $resourceType = $this->request->getTargetResourceType();
271
        $expressionProvider = $this->service->getProvidersWrapper()->getExpressionProvider();
272
        $filterInfo = ExpressionParser2::parseExpression2($filter, $resourceType, $expressionProvider);
0 ignored issues
show
Bug introduced by
It seems like $resourceType defined by $this->request->getTargetResourceType() on line 270 can be null; however, POData\UriProcessor\Quer...er2::parseExpression2() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
273
        $this->request->setFilterInfo($filterInfo);
274
    }
275
276
    /**
277
     * Process the $inlinecount option and update the request description.
278
     *
279
     *
280
     * @throws ODataException Throws bad request error in the following cases
281
     *                        (1) If $inlinecount is disabled by the developer
282
     *                        (2) If both $count and $inlinecount specified
283
     *                        (3) If $inlinecount value is unknown
284
     *                        (4) If capability negotiation over version fails
285
     */
286
    private function processCount()
287
    {
288
        $inlineCount = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_INLINECOUNT);
289
290
        //If it's not specified, we're done
291
        if (is_null($inlineCount)) {
292
            return;
293
        }
294
295
        //If the service doesn't allow count requests..then throw an exception
296
        if (!$this->service->getConfiguration()->getAcceptCountRequests()) {
297
            throw ODataException::createBadRequestError(
298
                Messages::configurationCountNotAccepted()
299
            );
300
        }
301
302
        $inlineCount = trim($inlineCount);
303
304
        //if it's set to none, we don't do inline counts
305
        if ($inlineCount === ODataConstants::URI_ROWCOUNT_OFFOPTION) {
306
            return;
307
        }
308
309
        //You can't specify $count & $inlinecount together
310
        //TODO: ensure there's a test for this case see #55
311
        if ($this->request->queryType == QueryType::COUNT()) {
312
            throw ODataException::createBadRequestError(
313
                Messages::queryProcessorInlineCountWithValueCount()
314
            );
315
        }
316
317
        $this->checkSetQueryApplicable(); //TODO: why do we do this check?
318
319
        if ($inlineCount === ODataConstants::URI_ROWCOUNT_ALLOPTION) {
320
            $this->request->queryType = QueryType::ENTITIES_WITH_COUNT();
321
322
            $this->request->raiseMinVersionRequirement(2, 0);
323
            $this->request->raiseResponseVersion(2, 0);
324
        } else {
325
            throw ODataException::createBadRequestError(
326
                Messages::queryProcessorInvalidInlineCountOptionError()
327
            );
328
        }
329
    }
330
331
    /**
332
     * Process the $skiptoken option in the request and update the request
333
     * description, this function requires _processOrderBy method to be
334
     * already invoked.
335
     *
336
     *
337
     * @throws ODataException Throws bad request error in the following cases
338
     *                        (1) If $skiptoken cannot be applied to the
339
     *                        resource targeted by the request uri
340
     *                        (2) If paging is not enabled for the resource
341
     *                        targeted by the request uri
342
     *                        (3) If parsing of $skiptoken fails
343
     *                        (4) If capability negotiation over version fails
344
     */
345
    private function processSkipToken()
346
    {
347
        $skipToken = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SKIPTOKEN);
348
        if (is_null($skipToken)) {
349
            return;
350
        }
351
352
        if (!$this->pagingApplicable) {
353
            throw ODataException::createBadRequestError(
354
                Messages::queryProcessorSkipTokenNotAllowed()
355
            );
356
        }
357
358
        if (!$this->isSSPagingRequired()) {
359
            throw ODataException::createBadRequestError(
360
                Messages::queryProcessorSkipTokenCannotBeAppliedForNonPagedResourceSet(
361
                    $this->request->getTargetResourceSetWrapper()
0 ignored issues
show
Documentation introduced by
$this->request->getTargetResourceSetWrapper() is of type object<POData\Providers\...esourceSetWrapper>|null, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
362
                )
363
            );
364
        }
365
366
        $internalOrderByInfo = $this->request->getInternalOrderByInfo();
367
        assert($internalOrderByInfo != null, "Internal order info must not be null");
368
        $targetResourceType = $this->request->getTargetResourceType();
369
        assert($targetResourceType != null, "Request target resource type must not be null");
370
371
        $internalSkipTokenInfo = SkipTokenParser::parseSkipTokenClause(
372
            $targetResourceType,
373
            $internalOrderByInfo,
374
            $skipToken
375
        );
376
        $this->request->setInternalSkipTokenInfo($internalSkipTokenInfo);
377
        $this->request->raiseMinVersionRequirement(2, 0);
378
        $this->request->raiseResponseVersion(2, 0);
379
    }
380
381
    /**
382
     * Process the $expand and $select option and update the request description.
383
     *
384
     *
385
     * @throws ODataException Throws bad request error in the following cases
386
     *                        (1) If $expand or select cannot be applied to the
387
     *                        requested resource.
388
     *                        (2) If projection is disabled by the developer
389
     *                        (3) If some error occurs while parsing the options
390
     */
391
    private function processExpandAndSelect()
392
    {
393
        $expand = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_EXPAND);
394
395
        if (!is_null($expand)) {
396
            $this->checkExpandOrSelectApplicable(ODataConstants::HTTPQUERY_STRING_EXPAND);
397
        }
398
399
        $select = $this->service->getHost()->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SELECT);
400
401
        if (!is_null($select)) {
402
            if (!$this->service->getConfiguration()->getAcceptProjectionRequests()) {
403
                throw ODataException::createBadRequestError(Messages::configurationProjectionsNotAccepted());
404
            }
405
406
            $this->checkExpandOrSelectApplicable(ODataConstants::HTTPQUERY_STRING_SELECT);
407
        }
408
409
        // We will generate RootProjectionNode in case of $link request also, but
410
        // expand and select in this case must be null (we are ensuring this above)
411
        // 'RootProjectionNode' is required while generating next page Link
412
        if ($this->expandSelectApplicable || $this->request->isLinkUri()) {
413
            $rootProjectionNode = ExpandProjectionParser::parseExpandAndSelectClause(
414
                $this->request->getTargetResourceSetWrapper(),
0 ignored issues
show
Bug introduced by
It seems like $this->request->getTargetResourceSetWrapper() can be null; however, parseExpandAndSelectClause() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
415
                $this->request->getTargetResourceType(),
0 ignored issues
show
Bug introduced by
It seems like $this->request->getTargetResourceType() can be null; however, parseExpandAndSelectClause() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
416
                $this->request->getInternalOrderByInfo(),
0 ignored issues
show
Bug introduced by
It seems like $this->request->getInternalOrderByInfo() can be null; however, parseExpandAndSelectClause() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
417
                $this->request->getSkipCount(),
418
                $this->request->getTopCount(),
419
                $expand,
420
                $select,
421
                $this->service->getProvidersWrapper()
422
            );
423
            if ($rootProjectionNode->isSelectionSpecified()) {
424
                $this->request->raiseMinVersionRequirement(2, 0);
425
            }
426
427
            if ($rootProjectionNode->hasPagedExpandedResult()) {
428
                $this->request->raiseResponseVersion(2, 0);
429
            }
430
            $this->request->setRootProjectionNode($rootProjectionNode);
431
        }
432
    }
433
434
    /**
435
     * Is server side paging is configured, this function return true
436
     * if the resource targeted by the resource path is applicable
437
     * for paging and paging is enabled for the targeted resource set
438
     * else false.
439
     *
440
     * @return bool
441
     */
442
    private function isSSPagingRequired()
443
    {
444
        if ($this->pagingApplicable) {
445
            $targetResourceSetWrapper = $this->request->getTargetResourceSetWrapper();
446
            //assert($targetResourceSetWrapper != NULL)
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
447
            return 0 != $targetResourceSetWrapper->getResourceSetPageSize();
448
        }
449
450
        return false;
451
    }
452
453
    /**
454
     * Read skip or top query option value which is expected to be positive
455
     * integer.
456
     *
457
     * @param string $queryItem The name of the query item to read from request
458
     *                          uri ($skip or $top)
459
     * @param int    &$value    On return, If the requested query item is
460
     *                          present with a valid integer value then this
461
     *                          argument will holds that integer value
462
     *                          otherwise holds zero
463
     *
464
     * @throws ODataException Throws syntax error if the requested argument
465
     *                        is present and it is not an integer
466
     *
467
     * @return bool True     If the requested query item with valid integer
468
     *              value is present in the request, false query
469
     *              item is absent in the request uri
470
     */
471
    private function readSkipOrTopOption($queryItem, &$value)
472
    {
473
        $value = $this->service->getHost()->getQueryStringItem($queryItem);
474
        if (!is_null($value)) {
475
            $int = new Int32();
476
            if (!$int->validate($value, $outValue)) {
477
                throw ODataException::createSyntaxError(
478
                    Messages::queryProcessorIncorrectArgumentFormat(
479
                        $queryItem,
480
                        $value
481
                    )
482
                );
483
            }
484
485
            $value = intval($value);
486
            if (0 > $value) {
487
                throw ODataException::createSyntaxError(
488
                    Messages::queryProcessorIncorrectArgumentFormat(
489
                        $queryItem,
490
                        $value
491
                    )
492
                );
493
            }
494
495
            return true;
496
        }
497
498
        $value = 0;
499
500
        return false;
501
    }
502
503
    /**
504
     * Checks whether client request contains any odata query options.
505
     *
506
     *
507
     * @throws ODataException Throws bad request error if client request
508
     *                        includes any odata query option
509
     */
510
    private function checkForEmptyQueryArguments()
511
    {
512
        $serviceHost = $this->service->getHost();
513
        if (!is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_FILTER))
514
            || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_EXPAND))
515
            || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_INLINECOUNT))
516
            || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_ORDERBY))
517
            || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SELECT))
518
            || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SKIP))
519
            || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_SKIPTOKEN))
520
            || !is_null($serviceHost->getQueryStringItem(ODataConstants::HTTPQUERY_STRING_TOP))
521
        ) {
522
            throw ODataException::createBadRequestError(
523
                Messages::queryProcessorNoQueryOptionsApplicable()
524
            );
525
        }
526
    }
527
528
    /**
529
     * To check whether the the query options $orderby, $inlinecount, $skip
530
     * or $top is applicable for the current requested resource.
531
     *
532
     *
533
     * @throws ODataException Throws bad request error if any of the query options $orderby, $inlinecount,
534
     * $skip or $top cannot be applied to the requested resource
535
     */
536
    private function checkSetQueryApplicable()
537
    {
538
        if (!$this->setQueryApplicable) {
539
            throw ODataException::createBadRequestError(
540
                Messages::queryProcessorQuerySetOptionsNotApplicable()
541
            );
542
        }
543
    }
544
545
    /**
546
     * To check whether the the query options $select, $expand
547
     * is applicable for the current requested resource.
548
     *
549
     * @param string $queryItem The query option to check
550
     *
551
     * @throws ODataException Throws bad request error if the query
552
     *                        options $select, $expand cannot be
553
     *                        applied to the requested resource
554
     */
555
    private function checkExpandOrSelectApplicable($queryItem)
556
    {
557
        if (!$this->expandSelectApplicable) {
558
            throw ODataException::createBadRequestError(
559
                Messages::queryProcessorSelectOrExpandOptionNotApplicable($queryItem)
560
            );
561
        }
562
    }
563
}
564