Completed
Push — master ( 408c7c...047bc0 )
by Chad
42s queued 30s
created

Filterer::execute()   C

Complexity

Conditions 10
Paths 60

Size

Total Lines 76

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 76
rs 6.6569
c 0
b 0
f 0
cc 10
nc 60
nop 1

How to fix   Long Method    Complexity   

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:

1
<?php
2
3
namespace TraderInteractive;
4
5
use Exception;
6
use InvalidArgumentException;
7
use Throwable;
8
use TraderInteractive\Exceptions\FilterException;
9
10
/**
11
 * Class to filter an array of input.
12
 */
13
final class Filterer implements FiltererInterface
14
{
15
    /**
16
     * @var array
17
     */
18
    const DEFAULT_FILTER_ALIASES = [
19
        'array' => '\\TraderInteractive\\Filter\\Arrays::filter',
20
        'arrayize' => '\\TraderInteractive\\Filter\\Arrays::arrayize',
21
        'bool' => '\\TraderInteractive\\Filter\\Booleans::filter',
22
        'bool-convert' => '\\TraderInteractive\\Filter\\Booleans::convert',
23
        'compress-string' => '\\TraderInteractive\\Filter\\Strings::compress',
24
        'concat' => '\\TraderInteractive\\Filter\\Strings::concat',
25
        'date' => '\\TraderInteractive\\Filter\\DateTime::filter',
26
        'date-format' => '\\TraderInteractive\\Filter\\DateTime::format',
27
        'email' => '\\TraderInteractive\\Filter\\Email::filter',
28
        'explode' => '\\TraderInteractive\\Filter\\Strings::explode',
29
        'flatten' => '\\TraderInteractive\\Filter\\Arrays::flatten',
30
        'float' => '\\TraderInteractive\\Filter\\Floats::filter',
31
        'in' => '\\TraderInteractive\\Filter\\Arrays::in',
32
        'int' => '\\TraderInteractive\\Filter\\Ints::filter',
33
        'ofArray' => '\\TraderInteractive\\Filterer::ofArray',
34
        'ofArrays' => '\\TraderInteractive\\Filterer::ofArrays',
35
        'ofScalars' => '\\TraderInteractive\\Filterer::ofScalars',
36
        'redact' => '\\TraderInteractive\\Filter\\Strings::redact',
37
        'string' => '\\TraderInteractive\\Filter\\Strings::filter',
38
        'strip-tags' => '\\TraderInteractive\\Filter\\Strings::stripTags',
39
        'timezone' => '\\TraderInteractive\\Filter\\DateTimeZone::filter',
40
        'translate' => '\\TraderInteractive\\Filter\\Strings::translate',
41
        'uint' => '\\TraderInteractive\\Filter\\UnsignedInt::filter',
42
        'url' => '\\TraderInteractive\\Filter\\Url::filter',
43
    ];
44
45
    /**
46
     * @var array
47
     */
48
    const DEFAULT_OPTIONS = [
49
        FiltererOptions::ALLOW_UNKNOWNS => false,
50
        FiltererOptions::DEFAULT_REQUIRED => false,
51
        FiltererOptions::RESPONSE_TYPE => self::RESPONSE_TYPE_ARRAY,
52
    ];
53
54
    /**
55
     * @var string
56
     */
57
    const RESPONSE_TYPE_ARRAY = 'array';
58
59
    /**
60
     * @var string
61
     */
62
    const RESPONSE_TYPE_FILTER = FilterResponse::class;
63
64
    /**
65
     * @var string
66
     */
67
    const INVALID_THROW_ON_ERROR_VALUE_ERROR_FORMAT = (
68
        FilterOptions::THROW_ON_ERROR . " for field '%s' was not a boolean value"
69
    );
70
71
    /**
72
     * @var array
73
     */
74
    private static $registeredFilterAliases = self::DEFAULT_FILTER_ALIASES;
75
76
    /**
77
     * @var array|null
78
     */
79
    private $filterAliases;
80
81
    /**
82
     * @var array
83
     */
84
    private $specification;
85
86
    /**
87
     * @var bool
88
     */
89
    private $allowUnknowns;
90
91
    /**
92
     * @var bool
93
     */
94
    private $defaultRequired;
95
96
    /**
97
     * @param array      $specification The specification to apply to the value.
98
     * @param array      $options       The options apply during filtering.
99
     *                                  'allowUnknowns' (default false) true to allow or false to treat as error.
100
     *                                  'defaultRequired' (default false) true to make fields required by default.
101
     * @param array|null $filterAliases The filter aliases to accept.
102
     *
103
     * @throws InvalidArgumentException if 'allowUnknowns' option was not a bool
104
     * @throws InvalidArgumentException if 'defaultRequired' option was not a bool
105
     */
106
    public function __construct(array $specification, array $options = [], array $filterAliases = null)
107
    {
108
        $options += self::DEFAULT_OPTIONS;
109
110
        $this->specification = $specification;
111
        $this->filterAliases = $filterAliases;
112
        $this->allowUnknowns = self::getAllowUnknowns($options);
113
        $this->defaultRequired = self::getDefaultRequired($options);
114
    }
115
116
    /**
117
     * @param mixed $input The input to filter.
118
     *
119
     * @return FilterResponse
120
     *
121
     * @throws InvalidArgumentException Thrown if the filters for a field were not an array.
122
     * @throws InvalidArgumentException Thrown if any one filter for a field was not an array.
123
     * @throws InvalidArgumentException Thrown if the 'required' value for a field was not a bool.
124
     */
125
    public function execute(array $input) : FilterResponse
126
    {
127
        $filterAliases = $this->getAliases();
128
        $inputToFilter = [];
129
        $leftOverSpec = [];
130
131
        foreach ($this->specification as $field => $specification) {
132
            if (array_key_exists($field, $input)) {
133
                $inputToFilter[$field] = $input[$field];
134
                continue;
135
            }
136
137
            $leftOverSpec[$field] = $specification;
138
        }
139
140
        $leftOverInput = array_diff_key($input, $inputToFilter);
141
142
        $filteredInput = [];
143
        $errors = [];
144
        $conflicts = [];
145
        foreach ($inputToFilter as $field => $input) {
146
            $filters = $this->specification[$field];
147
            self::assertFiltersIsAnArray($filters, $field);
148
            $customError = self::validateCustomError($filters, $field);
149
            $throwOnError = self::validateThrowOnError($filters, $field);
150
            unset($filters[FilterOptions::IS_REQUIRED]);//doesn't matter if required since we have this one
151
            unset($filters[FilterOptions::DEFAULT_VALUE]);//doesn't matter if there is a default since we have a value
152
            $conflicts = self::extractConflicts($filters, $field, $conflicts);
153
154
            foreach ($filters as $filter) {
155
                self::assertFilterIsArray($filter, $field);
156
157
                if (empty($filter)) {
158
                    continue;
159
                }
160
161
                $uses = self::extractUses($filter);
162
163
                $function = array_shift($filter);
164
                $function = self::handleFilterAliases($function, $filterAliases);
165
166
                self::assertFunctionIsCallable($function, $field);
167
168
                array_unshift($filter, $input);
169
                try {
170
                    $this->addUsedInputToFilter($uses, $filteredInput, $field, $filter);
171
                    $input = call_user_func_array($function, $filter);
172
                } catch (Exception $exception) {
173
                    if ($throwOnError) {
174
                        throw $exception;
175
                    }
176
177
                    $errors = self::handleCustomError($field, $input, $exception, $errors, $customError);
178
                    continue 2;//next field
179
                }
180
            }
181
182
            $filteredInput[$field] = $input;
183
        }
184
185
        foreach ($leftOverSpec as $field => $filters) {
186
            self::assertFiltersIsAnArray($filters, $field);
187
            $required = self::getRequired($filters, $this->defaultRequired, $field);
188
            if (array_key_exists(FilterOptions::DEFAULT_VALUE, $filters)) {
189
                $filteredInput[$field] = $filters[FilterOptions::DEFAULT_VALUE];
190
                continue;
191
            }
192
193
            $errors = self::handleRequiredFields($required, $field, $errors);
194
        }
195
196
        $errors = self::handleAllowUnknowns($this->allowUnknowns, $leftOverInput, $errors);
197
        $errors = self::handleConflicts($filteredInput, $conflicts, $errors);
198
199
        return new FilterResponse($filteredInput, $errors, $leftOverInput);
200
    }
201
202
    /**
203
     * @return array
204
     *
205
     * @see FiltererInterface::getAliases
206
     */
207
    public function getAliases() : array
208
    {
209
        return $this->filterAliases ?? self::$registeredFilterAliases;
210
    }
211
212
    private static function extractConflicts(array &$filters, string $field, array $conflicts) : array
213
    {
214
        $conflictsWith = $filters[FilterOptions::CONFLICTS_WITH] ?? null;
215
        unset($filters[FilterOptions::CONFLICTS_WITH]);
216
        if ($conflictsWith === null) {
217
            return $conflicts;
218
        }
219
220
        if (!is_array($conflictsWith)) {
221
            $conflictsWith = [$conflictsWith];
222
        }
223
224
        $conflicts[$field] = $conflictsWith;
225
226
        return $conflicts;
227
    }
228
229
    private static function handleConflicts(array $inputToFilter, array $conflicts, array $errors)
230
    {
231
        foreach (array_keys($inputToFilter) as $field) {
232
            if (!array_key_exists($field, $conflicts)) {
233
                continue;
234
            }
235
236
            foreach ($conflicts[$field] as $conflictsWith) {
237
                if (array_key_exists($conflictsWith, $inputToFilter)) {
238
                    $errors[] = "Field '{$field}' cannot be given if field '{$conflictsWith}' is present.";
239
                }
240
            }
241
        }
242
243
        return $errors;
244
    }
245
246
    private static function extractUses(&$filters)
247
    {
248
        $uses = $filters[FilterOptions::USES] ?? [];
249
        unset($filters[FilterOptions::USES]);
250
        return is_array($uses) ? $uses : [$uses];
251
    }
252
253
    /**
254
     * @return array
255
     *
256
     * @see FiltererInterface::getSpecification
257
     */
258
    public function getSpecification() : array
259
    {
260
        return $this->specification;
261
    }
262
263
    /**
264
     * @param array $filterAliases
265
     *
266
     * @return FiltererInterface
267
     *
268
     * @see FiltererInterface::withAliases
269
     */
270
    public function withAliases(array $filterAliases) : FiltererInterface
271
    {
272
        return new Filterer($this->specification, $this->getOptions(), $filterAliases);
273
    }
274
275
    /**
276
     * @param array $specification
277
     *
278
     * @return FiltererInterface
279
     *
280
     * @see FiltererInterface::withSpecification
281
     */
282
    public function withSpecification(array $specification) : FiltererInterface
283
    {
284
        return new Filterer($specification, $this->getOptions(), $this->filterAliases);
285
    }
286
287
    /**
288
     * @return array
289
     */
290
    private function getOptions() : array
291
    {
292
        return [
293
            FiltererOptions::DEFAULT_REQUIRED => $this->defaultRequired,
294
            FiltererOptions::ALLOW_UNKNOWNS => $this->allowUnknowns,
295
        ];
296
    }
297
298
    /**
299
     * Example:
300
     * <pre>
301
     * <?php
302
     * class AppendFilter
303
     * {
304
     *     public function filter($value, $extraArg)
305
     *     {
306
     *         return $value . $extraArg;
307
     *     }
308
     * }
309
     * $appendFilter = new AppendFilter();
310
     *
311
     * $trimFunc = function($val) { return trim($val); };
312
     *
313
     * list($status, $result, $error, $unknowns) = TraderInteractive\Filterer::filter(
314
     *     [
315
     *         'field one' => [[$trimFunc], ['substr', 0, 3], [[$appendFilter, 'filter'], 'boo']],
316
     *         'field two' => ['required' => true, ['floatval']],
317
     *         'field three' => ['required' => false, ['float']],
318
     *         'field four' => ['required' => true, 'default' => 1, ['uint']],
319
     *     ],
320
     *     ['field one' => ' abcd', 'field two' => '3.14']
321
     * );
322
     *
323
     * var_dump($status);
324
     * var_dump($result);
325
     * var_dump($error);
326
     * var_dump($unknowns);
327
     * </pre>
328
     * prints:
329
     * <pre>
330
     * bool(true)
331
     * array(3) {
332
     *   'field one' =>
333
     *   string(6) "abcboo"
334
     *   'field two' =>
335
     *   double(3.14)
336
     *   'field four' =>
337
     *   int(1)
338
     * }
339
     * NULL
340
     * array(0) {
341
     * }
342
     * </pre>
343
     *
344
     * @param array $specification The specification to apply to the input.
345
     * @param array $input          The input the apply the specification to.
346
     * @param array $options        The options apply during filtering.
347
     *                              'allowUnknowns' (default false) true to allow or false to treat as error.
348
     *                              'defaultRequired' (default false) true to make fields required by default.
349
     *                              'responseType' (default RESPONSE_TYPE_ARRAY)
350
     *                                  Determines the return type, as described in the return section.
351
     *
352
     * @return array|FilterResponse If 'responseType' option is RESPONSE_TYPE_ARRAY:
353
     *                                  On success: [true, $input filtered, null, array of unknown fields]
354
     *                                  On error: [false, null, 'error message', array of unknown fields]
355
     *                              If 'responseType' option is RESPONSE_TYPE_FILTER: a FilterResponse instance
356
     *
357
     * @throws Exception
358
     * @throws InvalidArgumentException Thrown if the 'allowUnknowns' option was not a bool
359
     * @throws InvalidArgumentException Thrown if the 'defaultRequired' option was not a bool
360
     * @throws InvalidArgumentException Thrown if the 'responseType' option was not a recognized type.
361
     * @throws InvalidArgumentException Thrown if the filters for a field were not an array.
362
     * @throws InvalidArgumentException Thrown if any one filter for a field was not an array.
363
     * @throws InvalidArgumentException Thrown if the 'required' value for a field was not a bool.
364
     *
365
     * @see FiltererInterface::getSpecification For more information on specifications.
366
     */
367
    public static function filter(array $specification, array $input, array $options = [])
368
    {
369
        $options += self::DEFAULT_OPTIONS;
370
        $responseType = $options[FiltererOptions::RESPONSE_TYPE];
371
372
        $filterer = new Filterer($specification, $options);
373
        $filterResponse = $filterer->execute($input);
374
375
        return self::generateFilterResponse($responseType, $filterResponse);
376
    }
377
378
    /**
379
     * Return the filter aliases.
380
     *
381
     * @return array array where keys are aliases and values pass is_callable().
382
     */
383
    public static function getFilterAliases() : array
384
    {
385
        return self::$registeredFilterAliases;
386
    }
387
388
    /**
389
     * Set the filter aliases.
390
     *
391
     * @param array $aliases array where keys are aliases and values pass is_callable().
392
     * @return void
393
     *
394
     * @throws Exception Thrown if any of the given $aliases is not valid. @see registerAlias()
395
     */
396
    public static function setFilterAliases(array $aliases)
397
    {
398
        $originalAliases = self::$registeredFilterAliases;
399
        self::$registeredFilterAliases = [];
400
        try {
401
            foreach ($aliases as $alias => $callback) {
402
                self::registerAlias($alias, $callback);
403
            }
404
        } catch (Throwable $throwable) {
405
            self::$registeredFilterAliases = $originalAliases;
406
            throw $throwable;
407
        }
408
    }
409
410
    /**
411
     * Register a new alias with the Filterer
412
     *
413
     * @param string|int $alias the alias to register
414
     * @param callable $filter the aliased callable filter
415
     * @param bool $overwrite Flag to overwrite existing alias if it exists
416
     *
417
     * @return void
418
     *
419
     * @throws \InvalidArgumentException if $alias was not a string or int
420
     * @throws Exception if $overwrite is false and $alias exists
421
     */
422
    public static function registerAlias($alias, callable $filter, bool $overwrite = false)
423
    {
424
        self::assertIfStringOrInt($alias);
425
        self::assertIfAliasExists($alias, $overwrite);
426
        self::$registeredFilterAliases[$alias] = $filter;
427
    }
428
429
    /**
430
     * Filter an array by applying filters to each member
431
     *
432
     * @param array $values an array to be filtered. Use the Arrays::filter() before this method to ensure counts when
433
     *                      you pass into Filterer
434
     * @param array $filters filters with each specified the same as in @see self::filter.
435
     *                       Eg [['string', false, 2], ['uint']]
436
     *
437
     * @return array the filtered $values
438
     *
439
     * @throws FilterException if any member of $values fails filtering
440
     */
441
    public static function ofScalars(array $values, array $filters) : array
442
    {
443
        $wrappedFilters = [];
444
        foreach ($values as $key => $item) {
445
            $wrappedFilters[$key] = $filters;
446
        }
447
448
        list($status, $result, $error) = self::filter($wrappedFilters, $values);
449
        if (!$status) {
450
            throw new FilterException($error);
451
        }
452
453
        return $result;
454
    }
455
456
    /**
457
     * Filter an array by applying filters to each member
458
     *
459
     * @param array $values as array to be filtered. Use the Arrays::filter() before this method to ensure counts when
460
     *                      you pass into Filterer
461
     * @param array $spec spec to apply to each $values member, specified the same as in @see self::filter.
462
     *     Eg ['key' => ['required' => true, ['string', false], ['unit']], 'key2' => ...]
463
     *
464
     * @return array the filtered $values
465
     *
466
     * @throws Exception if any member of $values fails filtering
467
     */
468
    public static function ofArrays(array $values, array $spec) : array
469
    {
470
        $results = [];
471
        $errors = [];
472
        foreach ($values as $key => $item) {
473
            if (!is_array($item)) {
474
                $errors[] = "Value at position '{$key}' was not an array";
475
                continue;
476
            }
477
478
            list($status, $result, $error) = self::filter($spec, $item);
479
            if (!$status) {
480
                $errors[] = $error;
481
                continue;
482
            }
483
484
            $results[$key] = $result;
485
        }
486
487
        if (!empty($errors)) {
488
            throw new FilterException(implode("\n", $errors));
489
        }
490
491
        return $results;
492
    }
493
494
    /**
495
     * Filter $value by using a Filterer $spec and Filterer's default options.
496
     *
497
     * @param array $value array to be filtered. Use the Arrays::filter() before this method to ensure counts when you
498
     *                     pass into Filterer
499
     * @param array $spec spec to apply to $value, specified the same as in @see self::filter.
500
     *     Eg ['key' => ['required' => true, ['string', false], ['unit']], 'key2' => ...]
501
     *
502
     * @return array the filtered $value
503
     *
504
     * @throws FilterException if $value fails filtering
505
     */
506
    public static function ofArray(array $value, array $spec) : array
507
    {
508
        list($status, $result, $error) = self::filter($spec, $value);
509
        if (!$status) {
510
            throw new FilterException($error);
511
        }
512
513
        return $result;
514
    }
515
516
    private static function assertIfStringOrInt($alias)
517
    {
518
        if (!is_string($alias) && !is_int($alias)) {
519
            throw new InvalidArgumentException('$alias was not a string or int');
520
        }
521
    }
522
523
    private static function assertIfAliasExists($alias, bool $overwrite)
524
    {
525
        if (array_key_exists($alias, self::$registeredFilterAliases) && !$overwrite) {
526
            throw new Exception("Alias '{$alias}' exists");
527
        }
528
    }
529
530
    private static function checkForUnknowns(array $leftOverInput, array $errors) : array
531
    {
532
        foreach ($leftOverInput as $field => $value) {
533
            $errors[$field] = "Field '{$field}' with value '" . trim(var_export($value, true), "'") . "' is unknown";
534
        }
535
536
        return $errors;
537
    }
538
539
    private static function handleAllowUnknowns(bool $allowUnknowns, array $leftOverInput, array $errors) : array
540
    {
541
        if (!$allowUnknowns) {
542
            $errors = self::checkForUnknowns($leftOverInput, $errors);
543
        }
544
545
        return $errors;
546
    }
547
548
    private static function handleRequiredFields(bool $required, string $field, array $errors) : array
549
    {
550
        if ($required) {
551
            $errors[$field] = "Field '{$field}' was required and not present";
552
        }
553
        return $errors;
554
    }
555
556
    private static function getRequired($filters, $defaultRequired, $field) : bool
557
    {
558
        $required = $filters[FilterOptions::IS_REQUIRED] ?? $defaultRequired;
559
        if ($required !== false && $required !== true) {
560
            throw new InvalidArgumentException(
561
                sprintf("'%s' for field '%s' was not a bool", FilterOptions::IS_REQUIRED, $field)
562
            );
563
        }
564
565
        return $required;
566
    }
567
568
    private static function assertFiltersIsAnArray($filters, string $field)
569
    {
570
        if (!is_array($filters)) {
571
            throw new InvalidArgumentException("filters for field '{$field}' was not a array");
572
        }
573
    }
574
575
    private static function handleCustomError(
576
        string $field,
577
        $value,
578
        Throwable $e,
579
        array $errors,
580
        string $customError = null
581
    ) : array {
582
        $error = $customError;
583
        if ($error === null) {
584
            $errorFormat = "Field '%s' with value '{value}' failed filtering, message '%s'";
585
            $error = sprintf($errorFormat, $field, $e->getMessage());
586
        }
587
588
        $errors[$field] = str_replace('{value}', trim(var_export($value, true), "'"), $error);
589
        return $errors;
590
    }
591
592
    private static function assertFunctionIsCallable($function, string $field)
593
    {
594
        if (!is_callable($function)) {
595
            throw new Exception(
596
                "Function '" . trim(var_export($function, true), "'") . "' for field '{$field}' is not callable"
597
            );
598
        }
599
    }
600
601
    private static function handleFilterAliases($function, $filterAliases)
602
    {
603
        if ((is_string($function) || is_int($function)) && array_key_exists($function, $filterAliases)) {
604
            $function = $filterAliases[$function];
605
        }
606
607
        return $function;
608
    }
609
610
    private static function assertFilterIsArray($filter, string $field)
611
    {
612
        if (!is_array($filter)) {
613
            throw new InvalidArgumentException("filter for field '{$field}' was not a array");
614
        }
615
    }
616
617
    private static function validateThrowOnError(array &$filters, string $field) : bool
618
    {
619
        if (!array_key_exists(FilterOptions::THROW_ON_ERROR, $filters)) {
620
            return false;
621
        }
622
623
        $throwOnError = $filters[FilterOptions::THROW_ON_ERROR];
624
        if ($throwOnError !== true && $throwOnError !== false) {
625
            throw new InvalidArgumentException(
626
                sprintf(self::INVALID_THROW_ON_ERROR_VALUE_ERROR_FORMAT, $field)
627
            );
628
        }
629
630
        unset($filters[FilterOptions::THROW_ON_ERROR]);
631
632
        return $throwOnError;
633
    }
634
635
    private static function validateCustomError(array &$filters, string $field)
636
    {
637
        $customError = null;
638
        if (array_key_exists(FilterOptions::CUSTOM_ERROR, $filters)) {
639
            $customError = $filters[FilterOptions::CUSTOM_ERROR];
640
            if (!is_string($customError) || trim($customError) === '') {
641
                throw new InvalidArgumentException(
642
                    sprintf("%s for field '%s' was not a non-empty string", FilterOptions::CUSTOM_ERROR, $field)
643
                );
644
            }
645
646
            unset($filters[FilterOptions::CUSTOM_ERROR]);//unset so its not used as a filter
647
        }
648
649
        return $customError;
650
    }
651
652 View Code Duplication
    private static function getAllowUnknowns(array $options) : bool
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...
653
    {
654
        $allowUnknowns = $options[FiltererOptions::ALLOW_UNKNOWNS];
655
        if ($allowUnknowns !== false && $allowUnknowns !== true) {
656
            throw new InvalidArgumentException(sprintf("'%s' option was not a bool", FiltererOptions::ALLOW_UNKNOWNS));
657
        }
658
659
        return $allowUnknowns;
660
    }
661
662 View Code Duplication
    private static function getDefaultRequired(array $options) : bool
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...
663
    {
664
        $defaultRequired = $options[FiltererOptions::DEFAULT_REQUIRED];
665
        if ($defaultRequired !== false && $defaultRequired !== true) {
666
            throw new InvalidArgumentException(
667
                sprintf("'%s' option was not a bool", FiltererOptions::DEFAULT_REQUIRED)
668
            );
669
        }
670
671
        return $defaultRequired;
672
    }
673
674
    /**
675
     * @param string         $responseType   The type of object that should be returned.
676
     * @param FilterResponse $filterResponse The filter response to generate the typed response from.
677
     *
678
     * @return array|FilterResponse
679
     *
680
     * @see filter For more information on how responseType is handled and returns are structured.
681
     */
682
    private static function generateFilterResponse(string $responseType, FilterResponse $filterResponse)
683
    {
684
        if ($responseType === self::RESPONSE_TYPE_FILTER) {
685
            return $filterResponse;
686
        }
687
688
        if ($responseType === self::RESPONSE_TYPE_ARRAY) {
689
            return [
690
                $filterResponse->success,
691
                $filterResponse->success ? $filterResponse->filteredValue : null,
692
                $filterResponse->errorMessage,
693
                $filterResponse->unknowns
694
            ];
695
        }
696
697
        throw new InvalidArgumentException(sprintf("'%s' was not a recognized value", FiltererOptions::RESPONSE_TYPE));
698
    }
699
700
    private function addUsedInputToFilter(array $uses, array $filteredInput, string $field, array &$filter)
701
    {
702
        foreach ($uses as $usedField) {
703
            if (array_key_exists($usedField, $filteredInput)) {
704
                array_push($filter, $filteredInput[$usedField]);
705
                continue;
706
            }
707
708
            throw new FilterException(
709
                "{$field} uses {$usedField} but {$usedField} was not given."
710
            );
711
        }
712
    }
713
}
714