Test Failed
Branch dev (494019)
by Alex
03:13
created

Route::hasParam()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 1
1
<?php
2
3
/**
4
 * Codeburner Framework.
5
 *
6
 * @author Alex Rohleder <[email protected]>
7
 * @copyright 2016 Alex Rohleder
8
 * @license http://opensource.org/licenses/MIT
9
 */
10
11
namespace Codeburner\Router;
12
13
use Codeburner\Router\Exceptions\BadRouteException;
14
use Codeburner\Router\Strategies\MatcherAwareInterface;
15
use Codeburner\Router\Strategies\StrategyInterface;
16
17
/**
18
 * Route representation, a route must be able to chang and execute itself.
19
 *
20
 * @author Alex Rohleder <[email protected]>
21
 */
22
23
class Route
24
{
25
26
    /**
27
     * @var Collector
28
     */
29
30
    protected $collector;
31
    
32
    /**
33
     * @var string
34
     */
35
36
    protected $method;
37
    
38
    /**
39
     * @var string
40
     */
41
42
    protected $pattern;
43
    
44
    /**
45
     * @var string|array|\Closure
46
     */
47
48
    protected $action;
49
    
50
    /**
51
     * @var string
52
     */
53
54
    protected $namespace;
55
56
    /**
57
     * @var string[]
58
     */
59
60
    protected $params;
61
62
    /**
63
     * Defaults are parameters set by the user, and don't
64
     * appear on the pattern.
65
     *
66
     * @var array
67
     */
68
69
    protected $defaults;
70
71
    /**
72
     * Metadata can be set to be used on filters, dispatch strategies
73
     * or anywhere the route object is used.
74
     *
75
     * @var array
76
     */
77
78
    protected $metadata;
79
80
    /**
81
     * @var string|StrategyInterface
82
     */
83
84
    protected $strategy;
85
86
    /**
87
     * Blocked routes are dynamic routes selected to pass by the matcher.
88
     *
89
     * @var boolean
90
     */
91
92
    protected $blocked;
93
94
    /**
95
     * The matcher that dispatched this route.
96
     *
97
     * @var Matcher $matcher
98
     */
99
100
    protected $matcher;
101
102
    /**
103
     * @param Collector $collector
104
     * @param string $method
105
     * @param string $pattern
106
     * @param string|array|\Closure $action
107
     */
108
109
    public function __construct(Collector $collector, $method, $pattern, $action)
110
    {
111
        $this->collector = $collector;
112
        $this->method    = $method;
113
        $this->pattern   = $pattern;
114
        $this->action    = $action;
115
        $this->namespace = "";
116
        $this->params    = [];
117
        $this->defaults  = [];
118
        $this->metadata  = [];
119
        $this->strategy  = null;
120
        $this->blocked   = false;
121
    }
122
123
    /**
124
     * Clone this route and set it into the collector.
125
     *
126
     * @return Route
127
     */
128
129
    public function reset()
130
    {
131
        return $this->collector->set($this->method, $this->pattern, $this->action)->nth(0)
132
                               ->setStrategy($this->strategy)->setParams($this->params)
133
                               ->setDefaults($this->defaults)->setMetadataArray($this->metadata);
134
    }
135
136
    /**
137
     * Remove this route from the collector.
138
     *
139
     * @return self
140
     */
141
142
    public function forget()
143
    {
144
        $this->collector->forget($this->method, $this->pattern);
145
        return $this;
146
    }
147
148
    /**
149
     * Blocking a route indicate that that route have been selected and
150
     * parsed, now it will be given to the matcher.
151
     *
152
     * @return self
153
     */
154
155
    public function block()
156
    {
157
        $this->blocked = true;
158
        return $this;
159
    }
160
161
    /**
162
     * Verify if a Route have already been blocked.
163
     *
164
     * @return boolean
165
     */
166
167
    public function blocked()
168
    {
169
        return $this->blocked;
170
    }
171
172
    /**
173
     * Execute the route action, if no strategy was provided the action
174
     * will be executed by the call_user_func PHP function.
175
     *
176
     * @throws BadRouteException
177
     * @return mixed
178
     */
179
180
    public function call()
181
    {
182
        $this->action = $this->parseCallable($this->action);
183
184
        if ($this->strategy === null) {
185
            return call_user_func_array($this->action, array_merge($this->defaults, $this->params));
186
        }
187
188
        if (!is_object($this->strategy)) {
189
            $strategy = new $this->strategy;
190
191
            if ($strategy instanceof StrategyInterface) {
192
                if ($strategy instanceof MatcherAwareInterface) {
193
                    $strategy->setMatcher($this->matcher);
194
                }
195
196
                return $strategy->call($this);
197
            }
198
        }
199
200
        throw new BadRouteException("`$this->strategy` is not a valid route dispatch strategy, ".
201
                                    "it must implement the `Codeburner\Router\Strategies\StrategyInterface` interface.");
202
    }
203
204
    /**
205
     * Seek for dynamic content on callables. eg. routes action controller#action
206
     * syntax allow to use the variables to build the string like: {controller}@{action}
207
     *
208
     * @param string|array|\Closure $callable
209
     * @return string|array|\Closure
210
     */
211
212
    private function parseCallable($callable)
213
    {
214
        if (is_string($callable) && strpos($callable, "@")) {
215
            $callable = explode("@", $callable);
216
        }
217
218
        if (is_array($callable)) {
219
            if (is_string($callable[0])) {
220
                   $callable[0] = rtrim($this->namespace, "\\") . "\\" . $this->parseCallablePlaceholders($callable[0]);
221
                   $callable[1] = $this->parseCallablePlaceholders($callable[1]);
222
            } else $callable[1] = $this->parseCallablePlaceholders($callable[1]);
223
        }
224
225
        return $callable;
226
    }
227
228
    /**
229
     * Parse and replace dynamic content on route action.
230
     *
231
     * @param  string $fragment Part of callable
232
     * @return string
233
     */
234
235
    private function parseCallablePlaceholders($fragment)
236
    {
237
        if (strpos($fragment, "{") !== false) {
238
            foreach ($this->params as $placeholder => $value) {
239
                if (strpos($fragment, "{" . $placeholder . "}") !== false) {
240
                    $fragment = str_replace("{" . $placeholder . "}", ucwords(str_replace("-", " ", $value)), $fragment);
241
                }
242
            }
243
        }
244
245
        return $fragment;
246
    }
247
248
    /**
249
     * @return Collector
250
     */
251
252
    public function getCollector()
253
    {
254
        return $this->collector;
255
    }
256
257
    /**
258
     * @return string
259
     */
260
261
    public function getMethod()
262
    {
263
        return $this->method;
264
    }
265
266
    /**
267
     * @return string
268
     */
269
270
    public function getPattern()
271
    {
272
        return $this->pattern;
273
    }
274
275
    /**
276
     * @return string[]
277
     */
278
279
    public function getSegments()
280
    {
281
        return explode("/", $this->pattern);
282
    }
283
284
    /**
285
     * @return string|array|\Closure
286
     */
287
288
    public function getAction()
289
    {
290
        return $this->action;
291
    }
292
293
    /**
294
     * @return string
295
     */
296
297
    public function getNamespace()
298
    {
299
        return $this->namespace;
300
    }
301
302
    /**
303
     * @return string[]
304
     */
305
306
    public function getParams()
307
    {
308
        return $this->params;
309
    }
310
311
    /**
312
     * @param string $key
313
     * @return string
314
     */
315
316
    public function getParam($key)
317
    {
318
        return $this->params[$key];
319
    }
320
321
    /**
322
     * @return array
323
     */
324
325
    public function getDefaults()
326
    {
327
        return $this->defaults;
328
    }
329
330
    /**
331
     * @param string $key
332
     * @return mixed
333
     */
334
335
    public function getDefault($key)
336
    {
337
        return $this->defaults[$key];
338
    }
339
340
    /**
341
     * @return array
342
     */
343
344
    public function getMetadataArray()
345
    {
346
        return $this->metadata;
347
    }
348
349
    /**
350
     * @param string $key
351
     * @return mixed
352
     */
353
354
    public function getMetadata($key)
355
    {
356
        return $this->metadata[$key];
357
    }
358
359
    /**
360
     * @return string|null
361
     */
362
363
    public function getStrategy()
364
    {
365
        if ($this->strategy instanceof StrategyInterface) {
366
            return get_class($this->strategy);
367
        }
368
369
        return $this->strategy;
370
    }
371
372
    /**
373
     * @inheritdoc
374
     */
375
376
    public function getMatcher()
377
    {
378
        return $this->matcher;
379
    }
380
381
    /**
382
     * @param string $method
383
     * @return Route
384
     */
385
386
    public function setMethod($method)
387
    {
388
        $this->forget();
389
        $this->method = $method;
390
        return $this->reset();
391
    }
392
393
    /**
394
     * @param string $pattern
395
     * @return Route
396
     */
397
398
    public function setPattern($pattern)
399
    {
400
        $this->forget();
401
        $this->pattern = $pattern;
402
        return $this->reset();
403
    }
404
405
    /**
406
     * @param string $pattern
407
     * @return self
408
     */
409
410
    public function setPatternWithoutReset($pattern)
411
    {
412
        $this->pattern = $pattern;
413
        return $this;
414
    }
415
416
    /**
417
     * @param string $action
418
     * @return self
419
     */
420
421
    public function setAction($action)
422
    {
423
        $this->action = $action;
424
        return $this;
425
    }
426
427
    /**
428
     * @param string $namespace
429
     * @return self
430
     */
431
432
    public function setNamespace($namespace)
433
    {
434
        $this->namespace = $namespace;
435
        return $this;
436
    }
437
438
    /**
439
     * @param string[] $params
440
     * @return self
441
     */
442
443
    public function setParams(array $params)
444
    {
445
        $this->params = $params;
446
        return $this;
447
    }
448
449
    /**
450
     * @param string $key
451
     * @param string $value
452
     *
453
     * @return self
454
     */
455
456
    public function setParam($key, $value)
457
    {
458
        $this->params[$key] = $value;
459
        return $this;
460
    }
461
462
    /**
463
     * @param mixed[] $defaults
464
     * @return self
465
     */
466
467
    public function setDefaults(array $defaults)
468
    {
469
        $this->defaults = $defaults;
470
        return $this;
471
    }
472
473
    /**
474
     * @param string $key
475
     * @param mixed $value
476
     *
477
     * @return self
478
     */
479
480
    public function setDefault($key, $value)
481
    {
482
        $this->defaults[$key] = $value;
483
        return $this;
484
    }
485
486
    /**
487
     * @param mixed[] $metadata
488
     * @return self
489
     */
490
491
    public function setMetadataArray(array $metadata)
492
    {
493
        $this->metadata = $metadata;
494
        return $this;
495
    }
496
497
    /**
498
     * @param string $key
499
     * @param mixed $value
500
     *
501
     * @return $this
502
     */
503
504
    public function setMetadata($key, $value)
505
    {
506
        $this->metadata[$key] = $value;
507
        return $this;
508
    }
509
510
    /**
511
     * @param string|StrategyInterface $strategy
512
     * @return self
513
     */
514
515
    public function setStrategy($strategy)
516
    {
517
        $this->strategy = $strategy;
518
        return $this;
519
    }
520
521
    /**
522
     * @inheritdoc
523
     */
524
525
    public function setMatcher(Matcher $matcher)
526
    {
527
        $this->matcher = $matcher;
528
    }
529
530
    /**
531
     * @param string $key
532
     * @return bool
533
     */
534
535
    public function hasParam($key)
536
    {
537
        return isset($this->params[$key]);
538
    }
539
540
    /**
541
     * @param string $key
542
     * @return bool
543
     */
544
545
    public function hasDefault($key)
546
    {
547
        return isset($this->defaults[$key]);
548
    }
549
550
    /**
551
     * @param string $key
552
     * @return bool
553
     */
554
555
    public function hasMetadata($key)
556
    {
557
        return isset($this->metadata[$key]);
558
    }
559
560
}
561