Test Failed
Pull Request — master (#26)
by Divine Niiquaye
02:27
created

PrototypeTrait::bind()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 9
rs 10
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
    public function prototype(array $routeData)
40
    {
41
        foreach ($routeData as $routeMethod => $arguments) {
42
            $arguments = \is_array($arguments) ? $arguments : [$arguments];
43
44
            if (null !== $this->route) {
45
                $this->route->{$routeMethod}(...$arguments);
46
47
                continue;
48
            }
49
50
            if ('bind' === $routeMethod) {
51
                throw new \UnexpectedValueException(\sprintf('Binding the name "%s" is only supported on routes.', $arguments[0]));
52
            }
53
54
            $this->doPrototype($routeMethod, $arguments);
55
        }
56
57
        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
    public function end()
69
    {
70
        if (null !== $this->route) {
71
            $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
            $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
            $defaultIndex = $this->defaultIndex;
75
            $this->defaultIndex = 0;
76
77
            if ($defaultIndex >= 0) {
78
                return $this;
79
            }
80
        }
81
82
        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
    public function bind(string $routeName)
94
    {
95
        if (null === $this->route) {
96
            throw new \UnderflowException(\sprintf('Binding the name "%s" is only supported on routes.', $routeName));
97
        }
98
99
        $this->route->bind($routeName);
100
101
        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
    public function run($to)
112
    {
113
        if (null === $this->route) {
114
            throw new \UnderflowException(sprintf('Binding a handler with type of "%s", is only supported on routes.', \get_debug_type($to)));
115
        }
116
117
        $this->route->run($to);
118
119
        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
    public function default(string $variable, $default)
132
    {
133
        if (null !== $this->route) {
134
            $this->route->default($variable, $default);
135
136
            return $this;
137
        }
138
139
        return $this->doPrototype(__FUNCTION__, \func_get_args());
140
    }
141
142
    /**
143
     * Prototype the optional default values which maybe required by routes.
144
     *
145
     * @param array<string,mixed> $values
146
     *
147
     * @see Route::defaults() for more information
148
     *
149
     * @return $this
150
     */
151
    public function defaults(array $values)
152
    {
153
        if (null !== $this->route) {
154
            $this->route->defaults($values);
155
156
            return $this;
157
        }
158
159
        return $this->doPrototype(__FUNCTION__, \func_get_args());
160
    }
161
162
    /**
163
     * Prototype a rule to a named placeholder in route pattern.
164
     *
165
     * @param string|string[] $regexp The regexp to apply
166
     *
167
     * @see Route::assert() for more information
168
     *
169
     * @return $this
170
     */
171
    public function assert(string $variable, $regexp)
172
    {
173
        if (null !== $this->route) {
174
            $this->route->assert($variable, $regexp);
175
176
            return $this;
177
        }
178
179
        return $this->doPrototype(__FUNCTION__, \func_get_args());
180
    }
181
182
    /**
183
     * Prototype a set of rules to a named placeholder in route pattern.
184
     *
185
     * @param array<string,string|string[]> $regexps The regexps to apply
186
     *
187
     * @see Route::asserts() for more information
188
     *
189
     * @return $this
190
     */
191
    public function asserts(array $regexps)
192
    {
193
        if (null !== $this->route) {
194
            $this->route->asserts($regexps);
195
196
            return $this;
197
        }
198
199
        return $this->doPrototype(__FUNCTION__, \func_get_args());
200
    }
201
202
    /**
203
     * Prototype the arguments supplied to route handler's constructor/factory.
204
     *
205
     * @param mixed $value The parameter value
206
     *
207
     * @see Route::argument() for more information
208
     *
209
     * @return $this
210
     */
211
    public function argument(string $parameter, $value)
212
    {
213
        if (null !== $this->route) {
214
            $this->route->argument($parameter, $value);
215
216
            return $this;
217
        }
218
219
        return $this->doPrototype(__FUNCTION__, \func_get_args());
220
    }
221
222
    /**
223
     * Prototype the arguments supplied to route handler's constructor/factory.
224
     *
225
     * @param array<int|string> $parameters The route handler parameters
226
     *
227
     * @see Route::arguments() for more information
228
     *
229
     * @return $this
230
     */
231
    public function arguments(array $parameters)
232
    {
233
        if (null !== $this->route) {
234
            $this->route->arguments($parameters);
235
236
            return $this;
237
        }
238
239
        return $this->doPrototype(__FUNCTION__, \func_get_args());
240
    }
241
242
    /**
243
     * Prototype the missing namespace for all routes handlers.
244
     *
245
     * @see Route::namespace() for more information
246
     *
247
     * @return $this
248
     */
249
    public function namespace(string $namespace)
250
    {
251
        if (null !== $this->route) {
252
            $this->route->namespace($namespace);
253
254
            return $this;
255
        }
256
257
        return $this->doPrototype(__FUNCTION__, \func_get_args());
258
    }
259
260
    /**
261
     * Prototype HTTP request method(s) to all routes.
262
     *
263
     * @see Route::method() for more information
264
     *
265
     * @return $this
266
     */
267
    public function method(string ...$methods)
268
    {
269
        if (null !== $this->route) {
270
            $this->route->method(...$methods);
271
272
            return $this;
273
        }
274
275
        return $this->doPrototype(__FUNCTION__, \func_get_args());
276
    }
277
278
    /**
279
     * Prototype HTTP host scheme(s) to all routes.
280
     *
281
     * @see Route::scheme() for more information
282
     *
283
     * @return $this
284
     */
285
    public function scheme(string ...$schemes)
286
    {
287
        if (null !== $this->route) {
288
            $this->route->scheme(...$schemes);
289
290
            return $this;
291
        }
292
293
        return $this->doPrototype(__FUNCTION__, \func_get_args());
294
    }
295
296
    /**
297
     * Prototype HTTP host scheme(s) to all routes.
298
     *
299
     * @see Route::scheme() for more information
300
     *
301
     * @return $this
302
     */
303
    public function domain(string ...$hosts)
304
    {
305
        if (null !== $this->route) {
306
            $this->route->domain(...$hosts);
307
308
            return $this;
309
        }
310
311
        return $this->doPrototype(__FUNCTION__, \func_get_args());
312
    }
313
314
    /**
315
     * Prototype a prefix prepended to route's path.
316
     *
317
     * @see Route::prefix() for more information
318
     *
319
     * @return $this
320
     */
321
    public function prefix(string $path)
322
    {
323
        if (null !== $this->route) {
324
            $this->route->prefix($path);
325
326
            return $this;
327
        }
328
329
        return $this->doPrototype(__FUNCTION__, \func_get_args());
330
    }
331
332
    /**
333
     * Prototype named middleware group(s) to all routes.
334
     *
335
     * @see Route::piped() for more information
336
     *
337
     * @return $this
338
     */
339
    public function piped(string ...$to)
340
    {
341
        if (null !== $this->route) {
342
            $this->route->piped(...$to);
343
344
            return $this;
345
        }
346
347
        return $this->doPrototype(__FUNCTION__, \func_get_args());
348
    }
349
350
    /**
351
     * @param array<int,mixed> $arguments
352
     *
353
     * @return $this
354
     */
355
    protected function doPrototype(string $routeMethod, array $arguments)
356
    {
357
        if ($this->locked) {
358
            throw new \RuntimeException(\sprintf('Prototyping "%s" route method failed as routes collection is frozen.', $routeMethod));
359
        }
360
361
        if ($this->defaultIndex > 0 || \count($routes = $this->routes) < 1) {
362
            $this->prototypes[$routeMethod][] = $arguments;
363
        } else {
364
            foreach ($routes as $route) {
365
                \call_user_func_array([$route, $routeMethod], $arguments);
366
            }
367
368
            foreach ($this->groups as $group) {
369
                \call_user_func_array([$group, $routeMethod], $arguments);
370
            }
371
        }
372
373
        return $this;
374
    }
375
}
376