ArgumentHelper   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 234
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 29
lcom 1
cbo 1
dl 0
loc 234
ccs 0
cts 142
cp 0
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A closure() 0 22 3
A callable() 0 28 5
A transformer() 0 28 3
A mergeCallable() 0 11 2
A mergeClosure() 0 7 1
A mergeParameters() 0 11 2
B interpretFunction() 0 35 7
B argType() 0 25 6
1
<?php
2
3
/**
4
 * @author    Flipbox Factory
5
 * @copyright Copyright (c) 2017, Flipbox Digital
6
 * @link      https://github.com/flipbox/transform/releases/latest
7
 * @license   https://github.com/flipbox/transform/blob/master/LICENSE
8
 */
9
10
namespace Flipbox\Transform\Helpers;
11
12
use Flipbox\Transform\Transformers\TransformerInterface;
13
14
/**
15
 * @author Flipbox Factory <[email protected]>
16
 * @since 3.0.0
17
 */
18
class ArgumentHelper
19
{
20
    /**
21
     * Extracts all of the valid arguments for a provided Closure.
22
     *
23
     * @param $transformer
24
     * @param array $params
25
     * @return array
26
     */
27
    public static function closure(\Closure $transformer, array $params): array
28
    {
29
        if (empty($params)) {
30
            return $params;
31
        }
32
33
        try {
34
            list($args, $extra) = self::interpretFunction(
35
                new \ReflectionFunction($transformer),
36
                $params
37
            );
38
39
            return array_merge(
40
                $args,
41
                $extra
42
            );
43
        } catch (\ReflectionException $e) {
44
            // Sorry
45
        }
46
47
        return [];
48
    }
49
50
    /**
51
     * Extracts all of the valid arguments for a provided callable.
52
     *
53
     * @param callable $transformer
54
     * @param array $params
55
     * @param string $method
56
     * @return array
57
     */
58
    public static function callable(callable $transformer, array $params, string $method = '__invoke'): array
59
    {
60
        if (TransformerHelper::isClosure($transformer)) {
61
            return static::closure($transformer, $params);
62
        }
63
64
        if (empty($params)) {
65
            return $params;
66
        }
67
68
        try {
69
            if (is_array($transformer)) {
70
                $method = $transformer[1] ?? $method;
71
                $transformer = $transformer[0] ?? $transformer;
72
            }
73
74
            list($one) = self::interpretFunction(
75
                new \ReflectionMethod($transformer, $method),
76
                $params
77
            );
78
79
            return $one;
80
        } catch (\ReflectionException $e) {
81
            // Sorry
82
        }
83
84
        return [];
85
    }
86
87
    /**
88
     * Extracts all of the valid arguments for a provided callable.
89
     *
90
     * @param TransformerInterface $transformer
91
     * @param array $params
92
     * @return array
93
     */
94
    public static function transformer(TransformerInterface $transformer, array $params): array
95
    {
96
        if (empty($params)) {
97
            return $params;
98
        }
99
100
        try {
101
            list($extra, $variadic) = self::interpretFunction(
102
                new \ReflectionMethod($transformer, 'transform'),
103
                $params
104
            );
105
106
            list($args) = self::interpretFunction(
107
                new \ReflectionMethod($transformer, '__invoke'),
108
                $params
109
            );
110
111
            return array_merge(
112
                $args,
113
                $extra,
114
                $variadic
115
            );
116
        } catch (\ReflectionException $e) {
117
            // Sorry
118
        }
119
120
        return [];
121
    }
122
123
    /**
124
     * Merges an indexed array of arguments values with their name.  Note, the orders MUST match.
125
     *
126
     * @param callable $transformer
127
     * @param array $params
128
     * @param string $method
129
     * @return array
130
     * @throws \ReflectionException
131
     */
132
    public static function mergeCallable(callable $transformer, array $params, string $method = 'transform'): array
133
    {
134
        if (TransformerHelper::isClosure($transformer)) {
135
            return static::mergeClosure($transformer, $params);
136
        }
137
138
        return self::mergeParameters(
139
            new \ReflectionMethod($transformer, $method),
140
            $params
141
        );
142
    }
143
144
    /**
145
     * Merges an indexed array of arguments values with their name.  Note, the orders MUST match.
146
     *
147
     * @param callable $transformer
148
     * @param array $params
149
     * @return array
150
     * @throws \ReflectionException
151
     */
152
    public static function mergeClosure(callable $transformer, array $params): array
153
    {
154
        return self::mergeParameters(
155
            new \ReflectionFunction($transformer),
156
            $params
157
        );
158
    }
159
160
161
    /**
162
     * @param \ReflectionFunctionAbstract $function
163
     * @param array $params
164
     * @return array
165
     */
166
    private static function mergeParameters(\ReflectionFunctionAbstract $function, array $params): array
167
    {
168
        $args = [];
169
170
        foreach ($function->getParameters() as $key => $param) {
171
            $name = $param->name;
172
            $args[$name] = $params[$key] ?? null;
173
        }
174
175
        return $args;
176
    }
177
178
    /**
179
     * @param \ReflectionFunctionAbstract $function
180
     * @param array $params
181
     * @param array $ignore
182
     * @return array
183
     * @throws \InvalidArgumentException
184
     */
185
    private static function interpretFunction(
186
        \ReflectionFunctionAbstract $function,
187
        array $params,
188
        array $ignore = []
189
    ): array {
190
        $args = $missing = $variadic = [];
191
        foreach ($function->getParameters() as $param) {
192
            $name = $param->name;
193
            if (true === in_array($name, $ignore, true)) {
194
                continue;
195
            }
196
197
            if (array_key_exists($name, $params)) {
198
                $args[$name] = self::argType($param, $params[$name]);
199
            } elseif ($param->isDefaultValueAvailable()) {
200
                $args[$name] = $param->getDefaultValue();
201
            } elseif ($param->isVariadic()) {
202
                $variadic = array_diff_key(
203
                    ${$param->name},
204
                    $args
205
                );
206
            } else {
207
                $missing[] = $name;
208
            }
209
        }
210
211
        if (!empty($missing)) {
212
            throw new \InvalidArgumentException(sprintf(
213
                'Missing required parameters "%s".',
214
                implode(', ', $missing)
215
            ));
216
        }
217
218
        return [array_values($args), $variadic];
219
    }
220
221
    /**
222
     * @param \ReflectionParameter $param
223
     * @param $value
224
     * @return mixed
225
     */
226
    private static function argType(
227
        \ReflectionParameter $param,
228
        $value
229
    ) {
230
        if (!$param->hasType()) {
231
            return $value;
232
        }
233
234
        if ($param->isArray()) {
235
            return (array)$value;
236
        }
237
238
        if ($param->isCallable() && is_callable($value)) {
239
            return $value;
240
        }
241
242
        if (!is_array($value)) {
243
            return $value;
244
        }
245
246
        throw new \InvalidArgumentException(sprintf(
247
            'Invalid data received for parameter "%s".',
248
            $param->name
249
        ));
250
    }
251
}
252