Completed
Push — master ( 5e2812...881bca )
by Joschi
02:44
created

Route::getAction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
/**
4
 * apparat-server
5
 *
6
 * @category    Apparat
7
 * @package     Apparat\Server
8
 * @subpackage  Apparat\Server\Ports
9
 * @author      Joschi Kuphal <[email protected]> / @jkphl
10
 * @copyright   Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
11
 * @license     http://opensource.org/licenses/MIT The MIT License (MIT)
12
 */
13
14
/***********************************************************************************
15
 *  The MIT License (MIT)
16
 *
17
 *  Copyright © 2016 Joschi Kuphal <[email protected]> / @jkphl
18
 *
19
 *  Permission is hereby granted, free of charge, to any person obtaining a copy of
20
 *  this software and associated documentation files (the "Software"), to deal in
21
 *  the Software without restriction, including without limitation the rights to
22
 *  use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
23
 *  the Software, and to permit persons to whom the Software is furnished to do so,
24
 *  subject to the following conditions:
25
 *
26
 *  The above copyright notice and this permission notice shall be included in all
27
 *  copies or substantial portions of the Software.
28
 *
29
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30
 *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
31
 *  FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
32
 *  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
33
 *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
34
 *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35
 ***********************************************************************************/
36
37
namespace Apparat\Server\Ports;
38
39
use Apparat\Server\Ports\Action\ActionInterface;
40
use Apparat\Server\Ports\Contract\RouteInterface;
41
42
/**
43
 * Route
44
 *
45
 * @package Apparat\Server
46
 * @subpackage Apparat\Server\Ports
47
 */
48
class Route implements RouteInterface
49
{
50
    /**
51
     * GET request
52
     *
53
     * @var string
54
     */
55
    const GET = 'GET';
56
    /**
57
     * POST request
58
     *
59
     * @var string
60
     */
61
    const POST = 'POST';
62
    /**
63
     * PATCH request
64
     *
65
     * @var string
66
     */
67
    const PATCH = 'PATCH';
68
    /**
69
     * DELETE request
70
     *
71
     * @var string
72
     */
73
    const DELETE = 'DELETE';
74
    /**
75
     * OPTIONS request
76
     *
77
     * @var string
78
     */
79
    const OPTIONS = 'OPTIONS';
80
    /**
81
     * HEAD request
82
     *
83
     * @var string
84
     */
85
    const HEAD = 'HEAD';
86
    /**
87
     * Year route
88
     *
89
     * @var string
90
     */
91
    const YEAR = 'year';
92
    /**
93
     * Month route
94
     *
95
     * @var string
96
     */
97
    const MONTH = 'month';
98
    /**
99
     * Day route
100
     *
101
     * @var string
102
     */
103
    const DAY = 'day';
104
    /**
105
     * Hour route
106
     *
107
     * @var string
108
     */
109
    const HOUR = 'hour';
110
    /**
111
     * Minute route
112
     *
113
     * @var string
114
     */
115
    const MINUTE = 'minute';
116
    /**
117
     * Second route
118
     *
119
     * @var string
120
     */
121
    const SECOND = 'second';
122
    /**
123
     * Object
124
     *
125
     * @var string
126
     */
127
    const OBJECT = 'object';
128
    /**
129
     * Type
130
     *
131
     * @var string
132
     */
133
    const TYPE = 'type';
134
    /**
135
     * Allowed HTTP verbs
136
     *
137
     * @var array
138
     */
139
    protected static $validVerbs = [
140
        self::GET => true,
141
        self::POST => true,
142
        self::PATCH => true,
143
        self::DELETE => true,
144
        self::OPTIONS => true,
145
        self::HEAD => true
146
    ];
147
    /**
148
     * Route name
149
     *
150
     * @var string
151
     */
152
    protected $name;
153
    /**
154
     * Route path
155
     *
156
     * @var string
157
     */
158
    protected $path;
159
    /**
160
     * Route action
161
     *
162
     * @var string|callable
163
     */
164
    protected $action;
165
    /**
166
     * Route tokens
167
     *
168
     * @var array
169
     */
170
    protected $tokens = [];
171
    /**
172
     * Route default values
173
     *
174
     * @var array
175
     */
176
    protected $defaults = [];
177
    /**
178
     * Route wildcard name
179
     *
180
     * @var string|null
181
     */
182
    protected $wildcard = null;
183
    /**
184
     * Route host
185
     *
186
     * @var string|null
187
     */
188
    protected $host = null;
189
    /**
190
     * Allowed accept headers
191
     *
192
     * @var array
193
     */
194
    protected $accepts = [];
195
    /**
196
     * Allowed HTTP verbs
197
     *
198
     * @var array
199
     */
200
    protected $verbs = [];
201
    /**
202
     * Secure protocol behaviour
203
     *
204
     * @var boolean|null
205
     */
206
    protected $secure = false;
207
    /**
208
     * Authentication parameters
209
     *
210
     * @var mixed
211
     */
212
    protected $auth = null;
213
    /**
214
     * Custom extra parameters
215
     *
216
     * @var array
217
     */
218
    protected $extras = [];
219
    /**
220
     * Default route
221
     *
222
     * @var bool
223
     */
224
    protected $default = false;
225
226
    /**
227
     * Route constructor
228
     *
229
     * @param string|array $verbs Allowed HTTP verbs
230
     * @param string $name Route name
231
     * @param string $path Route path
232
     * @param string $action Route action
233
     * @param bool $default Default route
234
     */
235 2
    public function __construct($verbs, $name, $path, $action, $default = false)
236
    {
237
        // Set and validate the allowed HTTP verbs
238 2
        $this->setAndValidateVerbs($verbs);
239
240
        // Set and validate the route name
241 2
        $this->setAndValidateName($name);
242
243
        // Set and validate the route path
244 2
        $this->setAndValidatePath($path);
245
246
        // Set and validate the route action
247 2
        $this->setAndValidateAction($action);
248
249
        // Set whether this is a default route
250 2
        $this->default = !!$default;
251 2
    }
252
253
    /**
254
     * Validate the allowed HTTP verbs
255
     *
256
     * @param string|array $verbs Allowed HTTP verbs
257
     * @throws InvalidArgumentException If the HTTP verb list is empty
258
     * @throws InvalidArgumentException If the HTTP verb is invalid
259
     */
260 2
    protected function setAndValidateVerbs($verbs)
261
    {
262 2
        $this->verbs = array_map('strtoupper', array_filter((array)$verbs));
263
264
        // If the HTTP verb list is empty
265 2
        if (!count($this->verbs)) {
266
            throw new InvalidArgumentException(
267
                'Empty route HTTP verbs',
268
                InvalidArgumentException::EMPTY_ROUTE_HTTP_VERBS
269
            );
270
        }
271
272
        // Run through all registered HTTP verbs
273 2
        foreach ($this->verbs as $verb) {
274
            // If the HTTP verb is invalid
275 2
            if (!array_key_exists($verb, self::$validVerbs)) {
276
                throw new InvalidArgumentException(
277
                    sprintf('Invalid route HTTP verb "%s"', $verb),
278
                    InvalidArgumentException::INVALID_ROUTE_HTTP_VERB
279
                );
280
            }
281 2
        }
282 2
    }
283
284
    /**
285
     * Set and validate the route name
286
     *
287
     * @param string $name Route name
288
     * @throws InvalidArgumentException If the route name is empty
289
     */
290 2
    protected function setAndValidateName($name)
291
    {
292 2
        $this->name = trim($name);
293
        // If the route name is empty
294 2
        if (!strlen($this->name)) {
295
            throw new InvalidArgumentException(
296
                'Route name must not be empty',
297
                InvalidArgumentException::EMPTY_ROUTE_NAME
298
            );
299
        }
300 2
    }
301
302
    /**
303
     * Set and validate the route path
304
     *
305
     * @param string $path Route path
306
     * @throws InvalidArgumentException If the route path is empty
307
     */
308 2
    protected function setAndValidatePath($path)
309
    {
310 2
        $this->path = trim($path);
311
        // If the route path is empty
312 2
        if (!strlen($this->path)) {
313
            throw new InvalidArgumentException(
314
                'Route path must not be empty',
315
                InvalidArgumentException::EMPTY_ROUTE_NAME
316
            );
317
        }
318 2
    }
319
320
    /**
321
     * Set and validate the route action
322
     *
323
     * @param string $action Route action
324
     * @throws InvalidArgumentException If the route action is empty
325
     * @throws InvalidArgumentException If the route action is not a class name
326
     * @throws InvalidArgumentException If the route action is neither a callable nor an ActionInterface
327
     */
328 2
    protected function setAndValidateAction($action)
329
    {
330
        // If the action is given as string
331 2
        if (is_string($action)) {
332 2
            $this->action = trim($action);
333
334
            // If the route action is empty
335 2
            if (!strlen($this->action)) {
336
                throw new InvalidArgumentException(
337
                    'Route action must not be empty',
338
                    InvalidArgumentException::EMPTY_ROUTE_ACTION
339
                );
340
            }
341
342
            // If the route action is not a class name
343 2
            if (!class_exists($this->action)) {
344
                throw new InvalidArgumentException(
345
                    'Route action must be an existing class name',
346
                    InvalidArgumentException::ROUTE_ACTION_MUST_BE_CLASSNAME
347
                );
348
            }
349
350
            // If the route action doesn't implement the ActionInterface
351 2
            $actionReflection = new \ReflectionClass($this->action);
352 2
            if (!$actionReflection->implementsInterface(ActionInterface::class)) {
353
                throw new InvalidArgumentException(
354
                    'Route action must implement '.ActionInterface::class,
355
                    InvalidArgumentException::ROUTE_ACTION_MUST_IMPLEMENT_ACTION_INTERFACE
356
                );
357
            }
358
359 2
            return;
360
        }
361
362
        // If the action is given as callable
363
        if (is_callable($action)) {
364
            $this->action = $action;
365
            return;
366
        }
367
368
        // If the route action is neither a callable nor an ActionInterface
369
        throw new InvalidArgumentException(
370
            'Route action must be a callable or '.ActionInterface::class,
371
            InvalidArgumentException::ROUTE_ACTION_NOT_CALLABLE_OR_ACTION_INTERFACE
372
        );
373
    }
374
375
    /**
376
     * Get the route name
377
     *
378
     * @return string Route name
379
     */
380 2
    public function getName()
381
    {
382 2
        return $this->name;
383
    }
384
385
    /**
386
     * Get the route path
387
     *
388
     * @return string Route path
389
     */
390 2
    public function getPath()
391
    {
392 2
        return $this->path;
393
    }
394
395
    /**
396
     * Get the route action
397
     *
398
     * @return callable|string Route action
399
     */
400 2
    public function getAction()
401
    {
402 2
        return $this->action;
403
    }
404
405
    /**
406
     * Get the route tokens
407
     *
408
     * @return array Route tokens
409
     */
410 2
    public function getTokens()
411
    {
412 2
        return $this->tokens;
413
    }
414
415
    /**
416
     * Set the route tokens
417
     *
418
     * @param array $tokens Route tokens
419
     * @return Route Self reference
420
     */
421 2
    public function setTokens(array $tokens)
422
    {
423 2
        $this->tokens = $tokens;
424 2
        return $this;
425
    }
426
427
    /**
428
     * Get the route defaults
429
     *
430
     * @return array Route defaults
431
     */
432 2
    public function getDefaults()
433
    {
434 2
        return $this->defaults;
435
    }
436
437
    /**
438
     * Set the route defaults
439
     *
440
     * @param array $defaults Route defaults
441
     * @return Route Self reference
442
     */
443
    public function setDefaults(array $defaults)
444
    {
445
        $this->defaults = $defaults;
446
        return $this;
447
    }
448
449
    /**
450
     * Set the route wildcard name
451
     *
452
     * @return null|string
453
     */
454 2
    public function getWildcard()
455
    {
456 2
        return $this->wildcard;
457
    }
458
459
    /**
460
     * Get the route wildcard name
461
     *
462
     * @param null|string $wildcard Wildcard name
463
     * @return Route Self reference
464
     */
465
    public function setWildcard($wildcard)
466
    {
467
        $this->wildcard = $wildcard;
468
        return $this;
469
    }
470
471
    /**
472
     * Get the route host
473
     *
474
     * @return null|string Route host
475
     */
476 2
    public function getHost()
477
    {
478 2
        return $this->host;
479
    }
480
481
    /**
482
     * Set the route host
483
     *
484
     * @param null|string $host Route host
485
     * @return Route Self reference
486
     */
487
    public function setHost($host)
488
    {
489
        $this->host = $host;
490
        return $this;
491
    }
492
493
    /**
494
     * Get the allowed Accept headers
495
     *
496
     * @return array Allowed Accept headers
497
     */
498 2
    public function getAccepts()
499
    {
500 2
        return $this->accepts;
501
    }
502
503
    /**
504
     * Set the allowed Accept headers
505
     *
506
     * @param array $accepts Allowed Accept headers
507
     * @return Route Self reference
508
     */
509
    public function setAccepts(array $accepts)
510
    {
511
        $this->accepts = $accepts;
512
        return $this;
513
    }
514
515
    /**
516
     * Get the allowed HTTP verbs
517
     *
518
     * @return array Allowed HTTP verbs
519
     */
520 2
    public function getVerbs()
521
    {
522 2
        return $this->verbs;
523
    }
524
525
    /**
526
     * Set the allowed HTTP verbs
527
     *
528
     * @param array $verbs Allowed HTTP verbs
529
     * @return Route Self reference
530
     */
531
    public function setVerbs(array $verbs)
532
    {
533
        $this->verbs = $verbs;
534
        return $this;
535
    }
536
537
    /**
538
     * Get the secure protocol mode
539
     *
540
     * @return boolean|null Secure protocol mode
541
     */
542 2
    public function getSecure()
543
    {
544 2
        return $this->secure;
545
    }
546
547
    /**
548
     * Set the secure protocol mode
549
     *
550
     * @param boolean|null $secure Secure protocol mode
551
     * @return Route Self reference
552
     */
553
    public function setSecure($secure)
554
    {
555
        $this->secure = $secure;
556
        return $this;
557
    }
558
559
    /**
560
     * Get the authentication information
561
     *
562
     * @return mixed Authentication information
563
     */
564 2
    public function getAuth()
565
    {
566 2
        return $this->auth;
567
    }
568
569
    /**
570
     * Set the authentication information
571
     *
572
     * @param mixed $auth Authentication information
573
     * @return Route Self reference
574
     */
575
    public function setAuth($auth)
576
    {
577
        $this->auth = $auth;
578
        return $this;
579
    }
580
581
    /**
582
     * Get the custom extra information
583
     *
584
     * @return array Custom extra information
585
     */
586 2
    public function getExtras()
587
    {
588 2
        return $this->extras;
589
    }
590
591
    /**
592
     * Set the custom extra information
593
     *
594
     * @param array $extras Custom extra information
595
     * @return Route Self reference
596
     */
597
    public function setExtras(array $extras)
598
    {
599
        $this->extras = $extras;
600
        return $this;
601
    }
602
603
    /**
604
     * Return whether this is a default route
605
     *
606
     * @return boolean Default route
607
     */
608 2
    public function isDefault()
609
    {
610 2
        return $this->default;
611
    }
612
}
613