Completed
Push — master ( 8e0131...9ee977 )
by Jacob
9s
created

RestRequest::getQueryCriteria()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 16
rs 9.4285
cc 3
eloc 10
nc 3
nop 0
1
<?php
2
3
namespace As3\Modlr\Rest;
4
5
/**
6
 * The REST Request object.
7
 * Is created/parsed from a core Request object.
8
 *
9
 * @author Jacob Bare <[email protected]>
10
 */
11
class RestRequest
12
{
13
    /**
14
     * Request parameter (query string) constants.
15
     */
16
    const PARAM_INCLUSIONS = 'include';
17
    const PARAM_FIELDSETS  = 'fields';
18
    const PARAM_SORTING    = 'sort';
19
    const PARAM_PAGINATION = 'page';
20
    const PARAM_FILTERING  = 'filter';
21
22
    /**
23
     * Filter parameters.
24
     */
25
    const FILTER_AUTOCOMPLETE = 'autocomplete';
26
    const FILTER_AUTOCOMPLETE_KEY = 'key';
27
    const FILTER_AUTOCOMPLETE_VALUE = 'value';
28
    const FILTER_QUERY = 'query';
29
    const FILTER_QUERY_CRITERIA = 'criteria';
30
31
    /**
32
     * The request method, such as GET, POST, PATCH, etc.
33
     *
34
     * @var string
35
     */
36
    private $requestMethod;
37
38
    /**
39
     * The parsed URL/URI, via PHP's parse_url().
40
     *
41
     * @var array
42
     */
43
    private $parsedUri = [];
44
45
    /**
46
     * The entity type requested.
47
     *
48
     * @var string
49
     */
50
    private $entityType;
51
52
    /**
53
     * The entity identifier (id) value, if sent.
54
     *
55
     * @var string|null
56
     */
57
    private $identifier;
58
59
    /**
60
     * The entity relationship properties, if sent.
61
     *
62
     * @var array
63
     */
64
    private $relationship = [];
65
66
    /**
67
     * Relationship fields to include with the response.
68
     * AKA: sideloading the entities of relationships.
69
     * Either a associative array of relationshipKeys => true to specifically include.
70
     * Or a single associative key of '*' => true if all should be included.
71
     *
72
     * @var array
73
     */
74
    private $inclusions = [];
75
76
    /**
77
     * Sorting criteria.
78
     *
79
     * @var array
80
     */
81
    private $sorting = [];
82
83
    /**
84
     * Fields to only include with the response.
85
     *
86
     * @var array
87
     */
88
    private $fields = [];
89
90
    /**
91
     * Pagination (limit/skip) criteria.
92
     *
93
     * @var array
94
     */
95
    private $pagination = [];
96
97
    /**
98
     * Any request filters, such as quering, search, autocomplete, etc.
99
     * Must ultimately be handled by the Adapter to function.
100
     *
101
     * @var array
102
     */
103
    private $filters = [];
104
105
    /**
106
     * The request payload, if sent.
107
     * Used for updating/creating entities.
108
     *
109
     * @var RestPayload|null
110
     */
111
    private $payload;
112
113
    /**
114
     * The REST configuration.
115
     *
116
     * @var RestConfiguration
117
     */
118
    private $config;
119
120
    /**
121
     * Constructor.
122
     *
123
     * @param   RestConfiguration   $config     The REST configuration.
124
     * @param   string              $method     The request method.
125
     * @param   string              $uri        The complete URI (URL) of the request, included scheme, host, path, and query string.
126
     * @param   string|null         $payload    The request payload (body).
127
     */
128
    public function __construct(RestConfiguration $config, $method, $uri, $payload = null)
129
    {
130
        $this->config = $config;
131
        $this->requestMethod = strtoupper($method);
132
133
        $this->sorting      = $config->getDefaultSorting();
134
        $this->pagination   = $config->getDefaultPagination();
135
136
        $this->parse($uri);
137
        $this->payload = empty($payload) ? null : new RestPayload($payload);
138
139
        // Re-configure the config based on the actually request.
140
        $this->config->setHost($this->getHost());
141
        $this->config->setScheme($this->getScheme());
142
    }
143
144
    /**
145
     * Gets the scheme, such as http or https.
146
     *
147
     * @return  string
148
     */
149
    public function getScheme()
150
    {
151
        return $this->parsedUri['scheme'];
152
    }
153
154
    /**
155
     * Gets the hostname.
156
     *
157
     * @return  string
158
     */
159
    public function getHost()
160
    {
161
        return $this->parsedUri['host'];
162
    }
163
164
    /**
165
     * Gets the request method, such as GET, POST, PATCH, etc.
166
     *
167
     * @return  string
168
     */
169
    public function getMethod()
170
    {
171
        return $this->requestMethod;
172
    }
173
174
    /**
175
     * Gets the requested entity type.
176
     *
177
     * @return  string
178
     */
179
    public function getEntityType()
180
    {
181
        return $this->entityType;
182
    }
183
184
    /**
185
     * Gets the requested entity identifier (id), if sent.
186
     *
187
     * @return  string|null
188
     */
189
    public function getIdentifier()
190
    {
191
        return $this->identifier;
192
    }
193
194
    /**
195
     * Determines if an entity identifier (id) was sent with the request.
196
     *
197
     * @return  bool
198
     */
199
    public function hasIdentifier()
200
    {
201
        return null !== $this->getIdentifier();
202
    }
203
204
    /**
205
     * Determines if this is an entity relationship request.
206
     *
207
     * @return  bool
208
     */
209
    public function isRelationship()
210
    {
211
        return !empty($this->relationship);
212
    }
213
214
    /**
215
     * Gets the entity relationship request.
216
     *
217
     * @return  array
218
     */
219
    public function getRelationship()
220
    {
221
        return $this->relationship;
222
    }
223
224
    /**
225
     * Gets the entity relationship field key.
226
     *
227
     * @return  string|null
228
     */
229
    public function getRelationshipFieldKey()
230
    {
231
        if (false === $this->isRelationship()) {
232
            return null;
233
        }
234
        return $this->getRelationship()['field'];
235
    }
236
237
    /**
238
     * Determines if this is an entity relationship retrieve request.
239
     *
240
     * @return  bool
241
     */
242 View Code Duplication
    public function isRelationshipRetrieve()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
243
    {
244
        if (false === $this->isRelationship()) {
245
            return false;
246
        }
247
        return 'self' === $this->getRelationship()['type'];
248
    }
249
250
    /**
251
     * Determines if this is an entity relationship modify (create/update/delete) request.
252
     *
253
     * @return  bool
254
     */
255 View Code Duplication
    public function isRelationshipModify()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
256
    {
257
        if (false === $this->isRelationship()) {
258
            return false;
259
        }
260
        return 'related' === $this->getRelationship()['type'];
261
    }
262
263
    /**
264
     * Determines if this has an autocomplete filter enabled.
265
     *
266
     * @return  bool
267
     */
268 View Code Duplication
    public function isAutocomplete()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
269
    {
270
        if (false === $this->hasFilter(self::FILTER_AUTOCOMPLETE)) {
271
            return false;
272
        }
273
        $autocomplete = $this->getFilter(self::FILTER_AUTOCOMPLETE);
274
        return isset($autocomplete[self::FILTER_AUTOCOMPLETE_KEY]) && isset($autocomplete[self::FILTER_AUTOCOMPLETE_VALUE]);
275
    }
276
277
    /**
278
     * Gets the autocomplete attribute key.
279
     *
280
     * @return  string|null
281
     */
282 View Code Duplication
    public function getAutocompleteKey()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
283
    {
284
        if (false === $this->isAutocomplete()) {
285
            return null;
286
        }
287
        return $this->getFilter(self::FILTER_AUTOCOMPLETE)[self::FILTER_AUTOCOMPLETE_KEY];
288
    }
289
290
    /**
291
     * Gets the autocomplete search value.
292
     *
293
     * @return  string|null
294
     */
295 View Code Duplication
    public function getAutocompleteValue()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
296
    {
297
        if (false === $this->isAutocomplete()) {
298
            return null;
299
        }
300
        return $this->getFilter(self::FILTER_AUTOCOMPLETE)[self::FILTER_AUTOCOMPLETE_VALUE];
301
    }
302
303
    /**
304
     * Determines if this has the database query filter enabled.
305
     *
306
     * @return  bool
307
     */
308 View Code Duplication
    public function isQuery()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
    {
310
        if (false === $this->hasFilter(self::FILTER_QUERY)) {
311
            return false;
312
        }
313
        $autocomplete = $this->getFilter(self::FILTER_QUERY);
314
        return isset($autocomplete[self::FILTER_QUERY_CRITERIA]);
315
    }
316
317
    /**
318
     * Gets the query criteria value.
319
     *
320
     * @return  array
321
     */
322
    public function getQueryCriteria()
323
    {
324
        if (false === $this->isQuery()) {
325
            return [];
326
        }
327
328
        $queryKey = self::FILTER_QUERY;
329
        $criteriaKey = self::FILTER_QUERY_CRITERIA;
330
331
        $decoded = @json_decode($this->getFilter($queryKey)[$criteriaKey], true);
332
        if (!is_array($decoded)) {
333
            $param = sprintf('%s[%s][%s]', self::PARAM_FILTERING, $queryKey, $criteriaKey);
334
            throw RestException::invalidQueryParam($param, 'Was the value sent as valid JSON?');
335
        }
336
        return $decoded;
337
    }
338
339
    /**
340
     * Determines if specific sideloaded include fields were requested.
341
     *
342
     * @return  bool
343
     */
344
    public function hasInclusions()
345
    {
346
        $value = $this->getInclusions();
347
        return !empty($value);
348
    }
349
350
    /**
351
     * Gets specific sideloaded relationship fields to include.
352
     *
353
     * @return  array
354
     */
355
    public function getInclusions()
356
    {
357
        return $this->inclusions;
358
    }
359
360
    /**
361
     * Determines if a specific return fieldset has been specified.
362
     *
363
     * @return  bool
364
     */
365
    public function hasFieldset()
366
    {
367
        $value = $this->getFieldset();
368
        return !empty($value);
369
    }
370
371
    /**
372
     * Gets the return fieldset to use.
373
     *
374
     * @return  array
375
     */
376
    public function getFieldset()
377
    {
378
        return $this->fields;
379
    }
380
381
    /**
382
     * Determines if the request has specified sorting criteria.
383
     *
384
     * @return  bool
385
     */
386
    public function hasSorting()
387
    {
388
        $value = $this->getSorting();
389
        return !empty($value);
390
    }
391
392
    /**
393
     * Gets the sorting criteria.
394
     *
395
     * @return  array
396
     */
397
    public function getSorting()
398
    {
399
        return $this->sorting;
400
    }
401
402
    /**
403
     * Determines if the request has specified pagination (limit/skip) criteria.
404
     *
405
     * @return  bool
406
     */
407
    public function hasPagination()
408
    {
409
        $value = $this->getPagination();
410
        return !empty($value);
411
    }
412
413
    /**
414
     * Gets the pagination (limit/skip) criteria.
415
     *
416
     * @return  array
417
     */
418
    public function getPagination()
419
    {
420
        return $this->pagination;
421
    }
422
423
    /**
424
     * Determines if the request has any filtering criteria.
425
     *
426
     * @return  bool
427
     */
428
    public function hasFilters()
429
    {
430
        return !empty($this->filters);
431
    }
432
433
    /**
434
     * Determines if a specific filter exists, by key
435
     *
436
     * @param   string  $key
437
     * @return  bool
438
     */
439
    public function hasFilter($key)
440
    {
441
        return null !== $this->getFilter($key);
442
    }
443
444
    /**
445
     * Gets a specific filter, by key.
446
     *
447
     * @param   string  $key
448
     * @return  mixed|null
449
     */
450
    public function getFilter($key)
451
    {
452
        if (!isset($this->filters[$key])) {
453
            return null;
454
        }
455
        return $this->filters[$key];
456
    }
457
458
    /**
459
     * Gets the request payload.
460
     *
461
     * @return  RestPayload|null
462
     */
463
    public function getPayload()
464
    {
465
        return $this->payload;
466
    }
467
468
    /**
469
     * Determines if a request payload is present.
470
     *
471
     * @return  bool
472
     */
473
    public function hasPayload()
474
    {
475
        return $this->getPayload() instanceof RestPayload;
476
    }
477
478
    /**
479
     * Parses the incoming request URI/URL and sets the appropriate properties on this RestRequest object.
480
     *
481
     * @param   string  $uri
482
     * @return  self
483
     * @throws  RestException
484
     */
485
    private function parse($uri)
486
    {
487
        $this->parsedUri = parse_url($uri);
0 ignored issues
show
Documentation Bug introduced by
It seems like parse_url($uri) can also be of type false. However, the property $parsedUri is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

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

}

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

$account_id = false;

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

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
488
489
        if (false === strstr($this->parsedUri['path'], $this->config->getRootEndpoint())) {
490
            throw RestException::invalidEndpoint($this->parsedUri['path']);
491
        }
492
493
        $this->parsedUri['path'] = str_replace($this->config->getRootEndpoint(), '', $this->parsedUri['path']);
494
        $this->parsePath($this->parsedUri['path']);
495
496
        $this->parsedUri['query'] = isset($this->parsedUri['query']) ? $this->parsedUri['query'] : '';
497
        $this->parseQueryString($this->parsedUri['query']);
498
499
        return $this;
500
    }
501
502
    /**
503
     * Parses the incoming request path and sets appropriate properties on this RestRequest object.
504
     *
505
     * @param   string  $path
506
     * @return  self
507
     * @throws  RestException
508
     */
509
    private function parsePath($path)
510
    {
511
        $parts = explode('/', trim($path, '/'));
512
        for ($i = 0; $i < 1; $i++) {
513
            // All paths must contain /{workspace_entityType}
514
            if (false === $this->issetNotEmpty($i, $parts)) {
515
                throw RestException::invalidEndpoint($path);
516
            }
517
        }
518
        $this->extractEntityType($parts);
519
        $this->extractIdentifier($parts);
520
        $this->extractRelationship($parts);
521
        return $this;
522
    }
523
524
    /**
525
     * Extracts the entity type from an array of path parts.
526
     *
527
     * @param   array   $parts
528
     * @return  self
529
     */
530
    private function extractEntityType(array $parts)
531
    {
532
        $this->entityType = $parts[0];
533
        return $this;
534
    }
535
536
    /**
537
     * Extracts the entity identifier (id) from an array of path parts.
538
     *
539
     * @param   array   $parts
540
     * @return  self
541
     */
542
    private function extractIdentifier(array $parts)
543
    {
544
        if (isset($parts[1])) {
545
            $this->identifier = $parts[1];
546
        }
547
        return $this;
548
    }
549
550
    /**
551
     * Extracts the entity relationship properties from an array of path parts.
552
     *
553
     * @param   array   $parts
554
     * @return  self
555
     */
556
    private function extractRelationship(array $parts)
557
    {
558
        if (isset($parts[2])) {
559
            if ('relationships' === $parts[2]) {
560
                if (!isset($parts[3])) {
561
                    throw RestException::invalidRelationshipEndpoint($this->parsedUri['path']);
562
                }
563
                $this->relationship = [
564
                    'type'  => 'self',
565
                    'field' => $parts[3],
566
                ];
567
            } else {
568
                $this->relationship = [
569
                    'type'  => 'related',
570
                    'field' => $parts[2],
571
                ];
572
            }
573
        }
574
        return $this;
575
    }
576
577
    /**
578
     * Parses the incoming request query string and sets appropriate properties on this RestRequest object.
579
     *
580
     * @param   string  $queryString
581
     * @return  self
582
     * @throws  RestException
583
     */
584
    private function parseQueryString($queryString)
585
    {
586
        parse_str($queryString, $parsed);
587
588
        $supported = $this->getSupportedParams();
589
        foreach ($parsed as $param => $value) {
0 ignored issues
show
Bug introduced by
The expression $parsed of type null|array is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
590
            if (!isset($supported[$param])) {
591
                throw RestException::unsupportedQueryParam($param, array_keys($supported));
592
            }
593
        }
594
595
        $this->extractInclusions($parsed);
0 ignored issues
show
Bug introduced by
It seems like $parsed can also be of type null; however, As3\Modlr\Rest\RestRequest::extractInclusions() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
596
        $this->extractSorting($parsed);
0 ignored issues
show
Bug introduced by
It seems like $parsed can also be of type null; however, As3\Modlr\Rest\RestRequest::extractSorting() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
597
        $this->extractFields($parsed);
0 ignored issues
show
Bug introduced by
It seems like $parsed can also be of type null; however, As3\Modlr\Rest\RestRequest::extractFields() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
598
        $this->extractPagination($parsed);
0 ignored issues
show
Bug introduced by
It seems like $parsed can also be of type null; however, As3\Modlr\Rest\RestRequest::extractPagination() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
599
        $this->extractFilters($parsed);
0 ignored issues
show
Bug introduced by
It seems like $parsed can also be of type null; however, As3\Modlr\Rest\RestRequest::extractFilters() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
600
        return $this;
601
    }
602
603
    /**
604
     * Extracts relationship inclusions from an array of query params.
605
     *
606
     * @param   array   $params
607
     * @return  self
608
     */
609
    private function extractInclusions(array $params)
610
    {
611
        if (false === $this->issetNotEmpty(self::PARAM_INCLUSIONS, $params)) {
612
            if (true === $this->config->includeAllByDefault()) {
613
                $this->inclusions = ['*' => true];
614
            }
615
            return $this;
616
        }
617
        $inclusions = explode(',', $params[self::PARAM_INCLUSIONS]);
618
        foreach ($inclusions as $inclusion) {
619
            if (false !== stristr($inclusion, '.')) {
620
                throw RestException::invalidParamValue(self::PARAM_INCLUSIONS, sprintf('Inclusion via a relationship path, e.g. "%s" is currently not supported.', $inclusion));
621
            }
622
            $this->inclusions[$inclusion] = true;
623
        }
624
        return $this;
625
    }
626
627
    /**
628
     * Extracts sorting criteria from an array of query params.
629
     *
630
     * @param   array   $params
631
     * @return  self
632
     */
633
    private function extractSorting(array $params)
634
    {
635
        if (false === $this->issetNotEmpty(self::PARAM_SORTING, $params)) {
636
            return $this;
637
        }
638
        $sort = explode(',', $params[self::PARAM_SORTING]);
639
        foreach ($sort as $field) {
640
            $direction = 1;
641
            if (0 === strpos($field, '-')) {
642
                $direction = -1;
643
                $field = str_replace('-', '', $field);
644
            }
645
            $this->sorting[$field] = $direction;
646
        }
647
        return $this;
648
    }
649
650
    /**
651
     * Extracts fields to return from an array of query params.
652
     *
653
     * @param   array   $params
654
     * @return  self
655
     */
656 View Code Duplication
    private function extractFields(array $params)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
657
    {
658
        if (false === $this->issetNotEmpty(self::PARAM_FIELDSETS, $params)) {
659
            return $this;
660
        }
661
        $fields = $params[self::PARAM_FIELDSETS];
662
        if (!is_array($fields)) {
663
            throw RestException::invalidQueryParam(self::PARAM_FIELDSETS, 'The field parameter must be an array of entity type keys to fields.');
664
        }
665
        foreach ($fields as $entityType => $string) {
666
            $this->fields[$entityType] = explode(',', $string);
667
        }
668
        return $this;
669
    }
670
671
    /**
672
     * Extracts pagination criteria from an array of query params.
673
     *
674
     * @param   array   $params
675
     * @return  self
676
     */
677
    private function extractPagination(array $params)
678
    {
679
        if (false === $this->issetNotEmpty(self::PARAM_PAGINATION, $params)) {
680
            return $this;
681
        }
682
        $page = $params[self::PARAM_PAGINATION];
683
        if (!is_array($page) || !isset($page['limit'])) {
684
            throw RestException::invalidQueryParam(self::PARAM_PAGINATION, 'The page parameter must be an array containing at least a limit.');
685
        }
686
        $this->pagination = [
687
            'offset'    => isset($page['offset']) ? (Integer) $page['offset'] : 0,
688
            'limit'     => (Integer) $page['limit'],
689
        ];
690
        return $this;
691
    }
692
693
    /**
694
     * Extracts filtering criteria from an array of query params.
695
     *
696
     * @param   array   $params
697
     * @return  self
698
     */
699 View Code Duplication
    private function extractFilters(array $params)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
700
    {
701
        if (false === $this->issetNotEmpty(self::PARAM_FILTERING, $params)) {
702
            return $this;
703
        }
704
        $filters = $params[self::PARAM_FILTERING];
705
        if (!is_array($filters)) {
706
            throw RestException::invalidQueryParam(self::PARAM_FILTERING, 'The filter parameter must be an array keyed by filter name and value.');
707
        }
708
        foreach ($filters as $key => $value) {
709
            $this->filters[$key] = $value;
710
        }
711
        return $this;
712
    }
713
714
    /**
715
     * Gets query string parameters that this request supports.
716
     *
717
     * @return  array
718
     */
719
    public function getSupportedParams()
720
    {
721
        return [
722
            self::PARAM_INCLUSIONS  => true,
723
            self::PARAM_FIELDSETS   => true,
724
            self::PARAM_SORTING     => true,
725
            self::PARAM_PAGINATION  => true,
726
            self::PARAM_FILTERING   => true,
727
        ];
728
    }
729
730
    /**
731
     * Helper that determines if a key and value is set and is not empty.
732
     *
733
     * @param   string  $key
734
     * @param   mixed   $value
735
     * @return  bool
736
     */
737
    private function issetNotEmpty($key, $value)
738
    {
739
        return isset($value[$key]) && !empty($value[$key]);
740
    }
741
}
742