CustomRule   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 118
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 37
dl 0
loc 118
ccs 35
cts 35
cp 1
rs 10
c 0
b 0
f 0
wmc 13

4 Methods

Rating   Name   Duplication   Size   Complexity  
A parseAlias() 0 7 2
A parseClosureArgs() 0 19 5
A __construct() 0 11 2
A parseClosure() 0 20 4
1
<?php
2
3
/**
4
 * Linna Filter
5
 *
6
 * @author Sebastian Rapetti <[email protected]>
7
 * @copyright (c) 2018, Sebastian Rapetti
8
 * @license http://opensource.org/licenses/MIT MIT License
9
 */
10
declare(strict_types=1);
11
12
namespace Linna\Filter\Rules;
13
14
use Closure;
15
use InvalidArgumentException;
16
use ReflectionFunction;
17
18
/**
19
 * Add custom rule to filter.
20
 */
21
class CustomRule
22
{
23
    /**
24
     * @var RuleInterface Instance of concrete custom rule.
25
     */
26
    public $instance;
27
28
    /**
29
     * @var array Rule properties
30
     */
31
    private $config = [
32
        'full_class' => __CLASS__,
33
        'alias' => [],
34
        'args_count' => 0,
35
        'args_type' => [],
36
    ];
37
38
    /**
39
     * @var callable Rule custom function for validate method.
40
     */
41
    private $callback;
42
43
    /**
44
     * @var bool Filter type: false validate, true sanitize.
45
     */
46
    private $sanitize = false;
47
48
    /**
49
     * Class Constructor.
50
     *
51
     * @param array    $alias Rule aliases
52
     * @param Closure  $test  Rule custom function for validation
53
     */
54 11
    public function __construct(array $alias, Closure $test)
55
    {
56 11
        $this->parseAlias($alias);
57 10
        $this->parseClosure($test);
58
59 7
        $message = "Value provided not pass CustomRule ({$alias[0]}) test";
60
61 7
        $this->instance = new CustomValidate($test, $this->config, $message);
62
63 7
        if ($this->sanitize) {
64 1
            $this->instance = new CustomSanitize($test, $this->config, $message);
65
        }
66 7
    }
67
68
    /**
69
     * Parse alias
70
     *
71
     * @param array $alias
72
     *
73
     * @throws InvalidArgumentException if no alias provided for rule.
74
     */
75 11
    private function parseAlias(array $alias): void
76
    {
77 11
        if (\count($alias) === 0) {
78 1
            throw new InvalidArgumentException('Rule test function must have at least one alias.');
79
        }
80
81 10
        $this->config['alias'] = \array_map('strtolower', $alias);
82 10
    }
83
84
    /**
85
     * Parse test function for validate method.
86
     *
87
     * @param Closure $test
88
     *
89
     * @throws InvalidArgumentException if test function no dot have return type, if
90
     *                                  return type not bool or not void, if function do not
91
     *                                  have at least one parameter.
92
     */
93 10
    private function parseClosure(Closure $test): void
94
    {
95 10
        $reflection = new ReflectionFunction($test);
96 10
        $parameters = $reflection->getParameters();
97
98 10
        if (!$reflection->hasReturnType()) {
99 1
            throw new InvalidArgumentException('Rule test function do not have return type.');
100
        }
101
102 9
        if (!\in_array((string) $reflection->getReturnType(), ['bool', 'void'])) {
103 1
            throw new InvalidArgumentException('Rule test function return type must be bool or void.');
104
        }
105
106 8
        if (\count($parameters) === 0) {
107 1
            throw new InvalidArgumentException('Rule test function must have at least one argument.');
108
        }
109
110 7
        $this->parseClosureArgs($parameters);
111
112 7
        $this->callback = $test;
113 7
    }
114
115
    /**
116
     * Parse test function arguments.
117
     *
118
     * @param array $parameters
119
     */
120 7
    private function parseClosureArgs(array $parameters): void
121
    {
122
        //check for sanitizing
123 7
        if (($first = $parameters[0]) && $first->isPassedByReference()) {
124 1
            $this->sanitize = true;
125
        }
126
127
        //remove firs param, the received value
128 7
        \array_shift($parameters);
129
130 7
        $this->config['args_count'] = \count($parameters);
131
132 7
        foreach ($parameters as $param) {
133 3
            if (\in_array((string) $param->getType(), ['int', 'float'])) {
134 2
                $this->config['args_type'][] = 'number';
135 2
                continue;
136
            }
137
138 1
            $this->config['args_type'][] = 'string';
139
        }
140 7
    }
141
}
142