Test Failed
Push — master ( 95d817...af60fe )
by Divine Niiquaye
02:49
created

PrototypeTrait::set()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
nc 1
nop 2
dl 0
loc 3
ccs 1
cts 1
cp 1
crap 1
rs 10
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
     * @throws \UnexpectedValueException if bind method is called used for route
37
     *
38
     * @return $this
39 4
     */
40
    public function prototype(array $routeData)
41 4
    {
42 4
        foreach ($routeData as $routeMethod => $arguments) {
43
            $arguments = \is_array($arguments) ? $arguments : [$arguments];
44 4
45 1
            if (null === $this->route && 'bind' === $routeMethod) {
46
                throw new \UnexpectedValueException(\sprintf('Binding the name "%s" is only supported on routes.', $arguments[0]));
47 1
            }
48
49
            if ('s' === $routeMethod[-1]) {
50 4
                $arguments = [$arguments];
51 1
            }
52
53
            $this->doPrototype($routeMethod, $arguments);
54 3
        }
55
56
        return $this;
57 2
    }
58
59
    /**
60
     * This method performs two functions.
61
     *
62
     * - Unmounts a group collection to continue routes stalk.
63
     * - Adds a route into collection's stack.
64
     *
65
     * @return $this
66
     */
67
    public function end()
68 10
    {
69
        if (null !== $this->route) {
70 10
            $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...
71 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...
72 9
73
            $defaultIndex = $this->defaultIndex;
74 9
            $this->defaultIndex = 0;
75 9
76
            if ($defaultIndex >= 0) {
77 9
                return $this;
78 7
            }
79
        }
80
81
        return $this->parent ?? $this;
82 5
    }
83
84
    /**
85
     * Prototype a unique name to a route.
86
     *
87
     * @see Route::bind() for more information
88
     *
89
     * @throws \UnderflowException if route doesn't exist
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 a handler to a route.
106
     *
107
     * @param mixed $to PHP class, object or callable that returns the response when matched
108
     *
109
     * @throws \UnderflowException if route doesn't exist
110
     *
111 1
     * @return $this
112
     */
113 1
    public function run($to)
114 1
    {
115
        if (null === $this->route) {
116
            throw new \UnderflowException(sprintf('Binding a handler with type of "%s", is only supported on routes.', \get_debug_type($to)));
117 1
        }
118
119 1
        $this->route->run($to);
120
121
        return $this;
122
    }
123
124
    /**
125
     * Prototype optional default values to route(s)
126
     *
127
     * @param mixed $default The default value
128
     *
129
     * @see Route::default() for more information
130
     *
131 4
     * @return $this
132
     */
133 4
    public function default(string $variable, $default)
134
    {
135
        return $this->doPrototype(__FUNCTION__, \func_get_args());
136
    }
137
138
    /**
139
     * Prototype optional default values to route(s)
140
     *
141
     * @param array<string,mixed> $values
142
     *
143
     * @see Route::defaults() for more information
144
     *
145 1
     * @return $this
146
     */
147 1
    public function defaults(array $values)
148
    {
149
        return $this->doPrototype(__FUNCTION__, \func_get_args());
150
    }
151
152
    /**
153
     * Prototype a rule to a named placeholder in route pattern.
154
     *
155
     * @param string|string[] $regexp The regexp to apply
156
     *
157
     * @see Route::assert() for more information
158
     *
159 5
     * @return $this
160
     */
161 5
    public function assert(string $variable, $regexp)
162
    {
163
        return $this->doPrototype(__FUNCTION__, \func_get_args());
164
    }
165
166
    /**
167
     * Prototype a set of rules to a named placeholder in route pattern.
168
     *
169
     * @param array<string,string|string[]> $regexps The regexps to apply
170
     *
171
     * @see Route::asserts() for more information
172
     *
173 1
     * @return $this
174
     */
175 1
    public function asserts(array $regexps)
176
    {
177
        return $this->doPrototype(__FUNCTION__, \func_get_args());
178
    }
179
180
    /**
181
     * Prototype the parameter supplied to route handler's constructor/factory.
182
     *
183
     * @param mixed $value The parameter value
184
     *
185
     * @see Route::argument() for more information
186
     *
187 5
     * @return $this
188
     */
189 5
    public function argument(string $parameter, $value)
190
    {
191
        return $this->doPrototype(__FUNCTION__, \func_get_args());
192
    }
193
194
    /**
195
     * Prototype the parameters supplied to route handler's constructor/factory.
196
     *
197
     * @param array<int|string> $parameters The route handler parameters
198
     *
199
     * @see Route::arguments() for more information
200
     *
201 1
     * @return $this
202
     */
203 1
    public function arguments(array $parameters)
204
    {
205
        return $this->doPrototype(__FUNCTION__, \func_get_args());
206
    }
207
208
    /**
209
     * Prototype the missing namespace for all routes handlers.
210
     *
211
     * @see Route::namespace() for more information
212
     *
213 1
     * @return $this
214
     */
215 1
    public function namespace(string $namespace)
216
    {
217
        return $this->doPrototype(__FUNCTION__, \func_get_args());
218
    }
219
220
    /**
221
     * Prototype HTTP request method(s) to all routes.
222
     *
223
     * @see Route::method() for more information
224
     *
225 4
     * @return $this
226
     */
227 4
    public function method(string ...$methods)
228
    {
229
        return $this->doPrototype(__FUNCTION__, $methods);
230
    }
231
232
    /**
233
     * Prototype HTTP host scheme(s) to route(s)
234
     *
235
     * @see Route::scheme() for more information
236
     *
237 6
     * @return $this
238
     */
239 6
    public function scheme(string ...$schemes)
240
    {
241
        return $this->doPrototype(__FUNCTION__, $schemes);
242
    }
243
244
    /**
245
     * Prototype HTTP host name(s) to route(s)
246
     *
247
     * @see Route::domain() for more information
248
     *
249 9
     * @return $this
250
     */
251 9
    public function domain(string ...$hosts)
252
    {
253
        return $this->doPrototype(__FUNCTION__, $hosts);
254
    }
255
256
    /**
257
     * Prototype prefix path to route(s)
258
     *
259
     * @see Route::prefix() for more information
260
     *
261 9
     * @return $this
262
     */
263 9
    public function prefix(string $path)
264
    {
265
        return $this->doPrototype(__FUNCTION__, \func_get_args());
266
    }
267
268
    /**
269
     * Prototype a set of named grouped middleware(s) to route(s)
270
     *
271
     * @see Route::piped() for more information
272
     *
273 4
     * @return $this
274
     */
275 4
    public function piped(string ...$to)
276
    {
277
        return $this->doPrototype(__FUNCTION__, $to);
278
    }
279
280
    /**
281
     * Prototype a custom key and value to route(s)
282
     *
283 20
     * @param mixed $value
284
     *
285 20
     * @return $this
286 1
     */
287
    public function set(string $key, $value)
288
    {
289 20
        return $this->doPrototype('setData', \func_get_args());
290 15
    }
291 10
292 10
    /**
293
     * @param array<int,mixed> $arguments
294 6
     *
295 6
     * @return $this
296
     */
297
    protected function doPrototype(string $routeMethod, array $arguments)
298 6
    {
299 3
        if ($this->locked) {
300
            throw new \RuntimeException(\sprintf('Prototyping "%s" route method failed as routes collection is frozen.', $routeMethod));
301
        }
302
303 20
        if (null !== $this->route) {
304
            \call_user_func_array([$this->route, $routeMethod], $arguments);
305
        } elseif ($this->defaultIndex > 0 || \count($routes = $this->routes) < 1) {
306
            $this->prototypes[$routeMethod][] = $arguments;
307
        } else {
308
            foreach ($routes as $route) {
309
                \call_user_func_array([$route, $routeMethod], $arguments);
310
            }
311
312
            foreach ($this->groups as $group) {
313
                \call_user_func_array([$group, $routeMethod], $arguments);
314
            }
315
        }
316
317
        return $this;
318
    }
319
}
320