Passed
Push — master ( 67a6c5...5b4678 )
by Divine Niiquaye
24:01 queued 08:03
created

PrototypeTrait::doPrototype()   B

Complexity

Conditions 7
Paths 4

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 7

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 12
nc 4
nop 2
dl 0
loc 21
ccs 12
cts 12
cp 1
crap 7
rs 8.8333
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of Flight Routing.
7
 *
8
 * PHP version 7.4 and above required
9
 *
10
 * @author    Divine Niiquaye Ibok <[email protected]>
11
 * @copyright 2019 Biurad Group (https://biurad.com/)
12
 * @license   https://opensource.org/licenses/BSD-3-Clause License
13
 *
14
 * For the full copyright and license information, please view the LICENSE
15
 * file that was distributed with this source code.
16
 */
17
18
namespace Flight\Routing\Traits;
19
20
/**
21
 * A trait providing route method prototyping.
22
 *
23
 * @author Divine Niiquaye Ibok <[email protected]>
24
 */
25
trait PrototypeTrait
26
{
27
    private int $defaultIndex = 0;
28
29
    /** @var array<string,mixed[]> */
30
    private array $prototypes = [];
31
32
    /**
33
     * Allows a proxied method call to route's.
34
     *
35
     * @throws \RuntimeException if locked
36
     *
37
     * @return $this
38
     */
39 4
    public function prototype(array $routeData)
40
    {
41 4
        foreach ($routeData as $routeMethod => $arguments) {
42 4
            $arguments = \is_array($arguments) ? $arguments : [$arguments];
43
44 4
            if (null !== $this->route) {
45 1
                $this->route->{$routeMethod}(...$arguments);
46
47 1
                continue;
48
            }
49
50 4
            if ('bind' === $routeMethod) {
51 1
                throw new \UnexpectedValueException(\sprintf('Binding the name "%s" is only supported on routes.', $arguments[0]));
52
            }
53
54 3
            $this->doPrototype($routeMethod, $arguments);
55
        }
56
57 2
        return $this;
58
    }
59
60
    /**
61
     * This method performs two functions.
62
     *
63
     * - Unmounts a group collection to continue routes stalk.
64
     * - Adds a route into collection's stack.
65
     *
66
     * @return $this
67
     */
68 10
    public function end()
69
    {
70 10
        if (null !== $this->route) {
71 9
            $this->routes[] = $this->route;
0 ignored issues
show
Bug Best Practice introduced by
The property routes does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
72 9
            $this->route = null;
0 ignored issues
show
Bug Best Practice introduced by
The property route does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
73
74 9
            $defaultIndex = $this->defaultIndex;
75 9
            $this->defaultIndex = 0;
76
77 9
            if ($defaultIndex >= 0) {
78 7
                return $this;
79
            }
80
        }
81
82 5
        return $this->parent ?? $this;
83
    }
84
85
    /**
86
     * Prototype a name to a route, which is required for generating
87
     * url from named routes.
88
     *
89
     * @see Route::bind() for more information
90
     *
91
     * @return $this
92
     */
93 16
    public function bind(string $routeName)
94
    {
95 16
        if (null === $this->route) {
96 1
            throw new \UnderflowException(\sprintf('Binding the name "%s" is only supported on routes.', $routeName));
97
        }
98
99 15
        $this->route->bind($routeName);
100
101 15
        return $this;
102
    }
103
104
    /**
105
     * Prototype the route's handler executed when matched.
106
     *
107
     * @param mixed $to PHP class, object or callable that returns the response when matched
108
     *
109
     * @return $this
110
     */
111 1
    public function run($to)
112
    {
113 1
        if (null === $this->route) {
114 1
            throw new \UnderflowException(sprintf('Binding a handler with type of "%s", is only supported on routes.', \get_debug_type($to)));
115
        }
116
117 1
        $this->route->run($to);
118
119 1
        return $this;
120
    }
121
122
    /**
123
     * Prototype the optional default value which maybe required by routes.
124
     *
125
     * @param mixed $default The default value
126
     *
127
     * @see Route::default() for more information
128
     *
129
     * @return $this
130
     */
131 4
    public function default(string $variable, $default)
132
    {
133 4
        return $this->doPrototype(__FUNCTION__, \func_get_args());
134
    }
135
136
    /**
137
     * Prototype the optional default values which maybe required by routes.
138
     *
139
     * @param array<string,mixed> $values
140
     *
141
     * @see Route::defaults() for more information
142
     *
143
     * @return $this
144
     */
145 1
    public function defaults(array $values)
146
    {
147 1
        return $this->doPrototype(__FUNCTION__, \func_get_args());
148
    }
149
150
    /**
151
     * Prototype a rule to a named placeholder in route pattern.
152
     *
153
     * @param string|string[] $regexp The regexp to apply
154
     *
155
     * @see Route::assert() for more information
156
     *
157
     * @return $this
158
     */
159 5
    public function assert(string $variable, $regexp)
160
    {
161 5
        return $this->doPrototype(__FUNCTION__, \func_get_args());
162
    }
163
164
    /**
165
     * Prototype a set of rules to a named placeholder in route pattern.
166
     *
167
     * @param array<string,string|string[]> $regexps The regexps to apply
168
     *
169
     * @see Route::asserts() for more information
170
     *
171
     * @return $this
172
     */
173 1
    public function asserts(array $regexps)
174
    {
175 1
        return $this->doPrototype(__FUNCTION__, \func_get_args());
176
    }
177
178
    /**
179
     * Prototype the arguments supplied to route handler's constructor/factory.
180
     *
181
     * @param mixed $value The parameter value
182
     *
183
     * @see Route::argument() for more information
184
     *
185
     * @return $this
186
     */
187 5
    public function argument(string $parameter, $value)
188
    {
189 5
        return $this->doPrototype(__FUNCTION__, \func_get_args());
190
    }
191
192
    /**
193
     * Prototype the arguments supplied to route handler's constructor/factory.
194
     *
195
     * @param array<int|string> $parameters The route handler parameters
196
     *
197
     * @see Route::arguments() for more information
198
     *
199
     * @return $this
200
     */
201 1
    public function arguments(array $parameters)
202
    {
203 1
        return $this->doPrototype(__FUNCTION__, \func_get_args());
204
    }
205
206
    /**
207
     * Prototype the missing namespace for all routes handlers.
208
     *
209
     * @see Route::namespace() for more information
210
     *
211
     * @return $this
212
     */
213 1
    public function namespace(string $namespace)
214
    {
215 1
        return $this->doPrototype(__FUNCTION__, \func_get_args());
216
    }
217
218
    /**
219
     * Prototype HTTP request method(s) to all routes.
220
     *
221
     * @see Route::method() for more information
222
     *
223
     * @return $this
224
     */
225 4
    public function method(string ...$methods)
226
    {
227 4
        return $this->doPrototype(__FUNCTION__, \func_get_args());
228
    }
229
230
    /**
231
     * Prototype HTTP host scheme(s) to all routes.
232
     *
233
     * @see Route::scheme() for more information
234
     *
235
     * @return $this
236
     */
237 6
    public function scheme(string ...$schemes)
238
    {
239 6
        return $this->doPrototype(__FUNCTION__, \func_get_args());
240
    }
241
242
    /**
243
     * Prototype HTTP host scheme(s) to all routes.
244
     *
245
     * @see Route::scheme() for more information
246
     *
247
     * @return $this
248
     */
249 9
    public function domain(string ...$hosts)
250
    {
251 9
        return $this->doPrototype(__FUNCTION__, \func_get_args());
252
    }
253
254
    /**
255
     * Prototype a prefix prepended to route's path.
256
     *
257
     * @see Route::prefix() for more information
258
     *
259
     * @return $this
260
     */
261 9
    public function prefix(string $path)
262
    {
263 9
        return $this->doPrototype(__FUNCTION__, \func_get_args());
264
    }
265
266
    /**
267
     * Prototype named middleware group(s) to all routes.
268
     *
269
     * @see Route::piped() for more information
270
     *
271
     * @return $this
272
     */
273 4
    public function piped(string ...$to)
274
    {
275 4
        return $this->doPrototype(__FUNCTION__, \func_get_args());
276
    }
277
278
    /**
279
     * @param array<int,mixed> $arguments
280
     *
281
     * @return $this
282
     */
283 20
    protected function doPrototype(string $routeMethod, array $arguments)
284
    {
285 20
        if ($this->locked) {
286 1
            throw new \RuntimeException(\sprintf('Prototyping "%s" route method failed as routes collection is frozen.', $routeMethod));
287
        }
288
289 20
        if (null !== $this->route) {
290 15
            \call_user_func_array([$this->route, $routeMethod], $arguments);
291 10
        } elseif ($this->defaultIndex > 0 || \count($routes = $this->routes) < 1) {
292 10
            $this->prototypes[$routeMethod][] = $arguments;
293
        } else {
294 6
            foreach ($routes as $route) {
295 6
                \call_user_func_array([$route, $routeMethod], $arguments);
296
            }
297
298 6
            foreach ($this->groups as $group) {
299 3
                \call_user_func_array([$group, $routeMethod], $arguments);
300
            }
301
        }
302
303 20
        return $this;
304
    }
305
}
306