Completed
Push — master ( e55815...e6271c )
by Raffael
03:45
created

Route::camelCase2Dashes()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
declare(strict_types = 1);
3
4
/**
5
 * Micro
6
 *
7
 * @author    Raffael Sahli <[email protected]>
8
 * @copyright Copyright (c) 2017 gyselroth GmbH (https://gyselroth.com)
9
 * @license   MIT https://opensource.org/licenses/MIT
10
 */
11
12
namespace Micro\Http\Router;
13
14
use \Micro\Exception;
15
use \Micro\Http\Router;
16
17
class Route
18
{
19
    /**
20
     * Router
21
     *
22
     * @var Router
23
     */
24
    protected $router;
25
26
27
    /**
28
     * Continue propagation if match
29
     *
30
     * @var bool
31
     */
32
    protected $continue_propagation = false;
33
    
34
35
    /**
36
     * Route path
37
     *
38
     * @var string
39
     */
40
    protected $path;
41
42
43
    /**
44
     * Class to be instanced if route match was found
45
     *
46
     * @var string|object
47
     */
48
    protected $class;
49
50
51
    /**
52
     * Method to be executed if route match was found
53
     *
54
     * @var string
55
     */
56
    protected $method;
57
58
       
59
    /**
60
     * Found request parameters
61
     *
62
     * @var array
63
     */
64
    protected $params = [];
65
66
67
    /**
68
     * Instance route
69
     *
70
     * @param   string $path
71
     * @param   string $class
72
     * @param   string $method
73
     * @param   array $params
74
     * @return  void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
75
     */
76
    public function __construct(string $path, $class, ? string $method = null, array $params = [])
77
    {
78
        $this->setPath($path);
79
        $this->setClass($class);
80
        $this->setMethod($method);
81
        $this->setParams($params);
82
    }
83
84
85
    /**
86
     * Check if route does match the current http request
87
     *
88
     * @return bool
89
     */
90
    public function match(): bool
91
    {
92
        $regex = preg_replace_callback('#({([A-Z0-9a-z]+)\:\#(.+?)\#})|\{(.+?)\}#', function($match) {
93
            if (count($match) === 4) {
94
                return '(?<'.$match[2].'>'.$match[3].'+)';
95
            } else {
96
                return '(?<'.end($match).'>\w+)';
97
            }
98
        }, $this->path);
99
100
        if (preg_match('#^'.$regex.'#', $this->router->getPath(), $matches)) {
101
            foreach ($matches as $key => $value) {
102
                if (!is_int($key)) {
103
                    $this->params[$key] = $value;
104
                }
105
            }
106
            
107
            return true;
108
        }
109
        
110
        return false;
111
    }
112
   
113
114
    /**
115
     * Get callable
116
     *
117
     * @param  array $constructor
118
     * @return array
119
     */
120
    public function getCallable($constructor = []): array
121
    {
122
        if (is_object($this->class)) {
123
            $instance = $this->class;
124
        } else {
125
            $instance = new $this->class(...$constructor);
126
        }
127
128
        if ($this->method !== null) {
129
            return [&$instance, $this->method];
130
        }
131
132
        return [&$instance, $this->getMethod()];
133
    }
134
135
136
    /**
137
     * Build method name
138
     *
139
     * @param   string $name
140
     * @return  string
141
     */
142
    protected function buildMethodName(? string $name) : string
143
    {
144
        $result = $this->router->getVerb();
145
        
146
        if ($name !== null) {
147
            $split = explode('-', $name);
148
            foreach ($split as $part) {
149
                $result .= ucfirst($part);
150
            }
151
        }
152
153
        return $result;
154
    }
155
156
    
157
    /**
158
     * Get http router
159
     *
160
     * @return Router
161
     */
162
    public function getRouter(): Router
163
    {
164
        return $this->router;
165
    }
166
167
168
    /**
169
     * Set http router
170
     *
171
     * @param  Router $router
172
     * @return Route
173
     */
174
    public function setRouter(Router $router): Route
175
    {
176
        $this->router = $router;
177
        return $this;
178
    }
179
180
181
    /**
182
     * Get path
183
     *
184
     * @return string
185
     */
186
    public function getPath(): string
187
    {
188
        return $this->path;
189
    }
190
    
191
192
    /**
193
     * Set path
194
     *
195
     * @param  string $path
196
     * @return Route
197
     */
198
    public function setPath(string $path): Route
199
    {
200
        $this->path = (string)$path;
201
        return $this;
202
    }
203
204
205
    /**
206
     * Get class
207
     *
208
     * @return string
209
     */
210
    public function getClass(): string
211
    {
212
        if (is_object($this->class)) {
213
            return get_class($this->class);
214
        }
215
216
        return $this->class;
217
    }
218
219
220
    /**
221
     * Set clas
222
     *
223
     * @param   string|object $class
224
     * @return  Route
225
     */
226
    public function setClass($class): Route
227
    {
228
        $this->class = $class;
229
        return $this;
230
    }
231
232
233
    /**
234
     * Convert camelCase to dashes
235
     *
236
     * @param  string $value
237
     * @return string
238
     */
239
    protected function camelCase2Dashes(string $value): string
240
    {
241
        return strtolower(preg_replace('/([a-z])([A-Z])/', '$1-$2', $value));
242
    }
243
244
245
    /**
246
     * Get method
247
     *
248
     * @return string
249
     */
250
    public function getMethod(): string
251
    {
252
        if (substr($this->path, -1) === '$') {
253
            return $this->router->getVerb();
254
        }
255
256
        $path = $this->router->getPath();
257
        $action = substr($path, strrpos($path, '/') + 1);
258
259
        if (!in_array($action, $this->params)) {
260
            $this->method = $action;
261
        }
262
263
        $short = $this->camelCase2Dashes(substr($this->class, strrpos($this->class, '\\') + 1));
264
265
        if ($this->camelCase2Dashes($short) === $action) {
266
            $this->method = '';
267
        }
268
269
        return $this->buildMethodName($this->method);
270
    }
271
272
    
273
    /**
274
     * Set method
275
     *
276
     * @param   string $method
277
     * @return  Route
278
     */
279
    public function setMethod(? string $method) : Route
280
    {
281
        $this->method = $method;
282
        return $this;
283
    }
284
285
    
286
    /**
287
     * Set params
288
     *
289
     * @param   array $params
290
     * @return  Route
291
     */
292
    public function setParams(array $params): Route
293
    {
294
        $this->params = $params;
295
        return $this;
296
    }
297
298
299
    /**
300
     * Get translated regex variable values
301
     *
302
     * @return array
303
     */
304
    public function getParams(): array
305
    {
306
        return $this->params;
307
    }
308
309
310
    /**
311
     * Continue propagation after match
312
     *
313
     * @return bool
314
     */
315
    public function continueAfterMatch(): bool
316
    {
317
        return $this->continue_propagation;
318
    }
319
320
321
    /**
322
     * Halt propagation after match
323
     *
324
     * @param  bool $next
325
     * @return Route
326
     */
327
    public function continuePropagation($next = true): Route
328
    {
329
        $this->continue_propagation = (bool)$next;
330
        return $this;
331
    }
332
}
333