Completed
Push — b0.3.0 ( 326260...c79ea7 )
by Sebastian
02:52
created

CustomRule::parseAlias()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 1
dl 0
loc 7
ccs 0
cts 6
cp 0
crap 6
rs 10
c 0
b 0
f 0
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 implements RuleValidateInterface
22
{
23
    /**
24
     * @var array Rule properties
25
     */
26
    public $config = [
27
        'full_class' => __CLASS__,
28
        'alias' => [],
29
        'args_count' => 0,
30
        'args_type' => [],
31
    ];
32
33
    /**
34
     * @var callable Rule custom function for validate method.
35
     */
36
    private $callback;
37
38
    /**
39
     * @var string Error message
40
     */
41
    private $message = '';
42
43
    /**
44
     * Class Constructor.
45
     *
46
     * @param array    $alias Rule aliases
47
     * @param Closure  $test  Rule custom function for validation
48
     */
49
    public function __construct(array $alias, Closure $test)
50
    {
51
        $this->parseAlias($alias);
52
        $this->parseClosure($test);
53
54
        $this->message = "Value provided not pass CustomRule ({$alias[0]}) test";
55
    }
56
57
    /**
58
     * Parse alias
59
     *
60
     * @param array $alias
61
     *
62
     * @throws InvalidArgumentException if no alias provided for rule.
63
     */
64
    private function parseAlias(array $alias): void
65
    {
66
        if (count($alias) === 0) {
67
            throw new InvalidArgumentException('Rule test function must have at least one alias.');
68
        }
69
70
        $this->config['alias'] = array_map('strtolower', $alias);
71
    }
72
73
    /**
74
     * Parse test function for validate method.
75
     *
76
     * @param Closure $test
77
     *
78
     * @throws InvalidArgumentException if test function no dot have return type, if
79
     *                                  return type not bool or not void, if function do not
80
     *                                  have at least one parameter.
81
     */
82
    private function parseClosure(Closure $test): void
83
    {
84
        $reflection = new ReflectionFunction($test);
85
86
        if (!$reflection->hasReturnType()) {
87
            throw new InvalidArgumentException('Rule test function do not have return type.');
88
        }
89
90
        if (!in_array((string) $reflection->getReturnType(), ['bool', 'void'])) {
91
            throw new InvalidArgumentException('Rule test function return type must be bool or void.');
92
        }
93
94
        $this->parseClosureParams($reflection);
95
96
        $this->callback = $test;
97
    }
98
99
    private function parseClosureParams(ReflectionFunction &$reflection): void
100
    {
101
        $parameters = $reflection->getParameters();
102
103
        if (count($parameters) === 0) {
104
            throw new InvalidArgumentException('Rule test function must have at least one parameter.');
105
        }
106
107
        //remove firs param, the received value
108
        array_shift($parameters);
109
110
        $this->config['args_count'] = count($parameters);
111
112
        foreach ($parameters as $param) {
113
            if ($param->hasType()) {
114
                if (in_array((string) $param->getType(), ['int', 'float'])) {
115
                    $this->config['args_type'][] = 'number';
116
                }
117
            }
118
119
            $this->config['args_type'][] = 'string';
120
        }
121
    }
122
123
    /**
124
     * Validate.
125
     *
126
     * @return bool
127
     */
128
    public function validate(): bool
129
    {
130
        $args = func_get_args();
131
132
        return !call_user_func_array($this->callback, $args);
133
    }
134
135
    /**
136
     * Return error message.
137
     *
138
     * @return string Error message
139
     */
140
    public function getMessage(): string
141
    {
142
        return $this->message;
143
    }
144
}
145