Test Setup Failed
Push — master ( 903e2f...3c4145 )
by Mehmet
01:56
created

Router   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 181
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 21
lcom 1
cbo 3
dl 0
loc 181
ccs 0
cts 33
cp 0
rs 10
c 0
b 0
f 0

9 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 4
A withSubFolder() 0 6 1
A withCacheFile() 0 6 1
A extractFolder() 0 10 3
A add() 0 18 4
A __call() 0 11 1
A determineReturnType() 0 7 4
A checkRequestMethodIsValid() 0 7 2
A getRoute() 0 8 1
1
<?php
2
/**
3
 * Selami Router
4
 * PHP version 7.1+
5
 *
6
 * @category Library
7
 * @package  Router
8
 * @author   Mehmet Korkmaz <[email protected]>
9
 * @license  https://github.com/selamiphp/router/blob/master/LICENSE (MIT License)
10
 * @link     https://github.com/selamiphp/router
11
 */
12
13
declare(strict_types = 1);
14
15
namespace Selami\Router;
16
17
use Selami\Router\Exceptions\InvalidRequestMethodException;
18
19
/**
20
 * Router
21
 *
22
 * This class is responsible for registering route objects,
23
 * determining aliases if available and finding requested route
24
 */
25
final class Router
26
{
27
    public const HTML = 1;
28
    public const JSON = 2;
29
    public const TEXT = 3;
30
    public const XML = 4;
31
    public const REDIRECT = 5;
32
    public const DOWNLOAD = 6;
33
    public const CUSTOM = 7;
34
35
    public const OPTIONS = 'OPTIONS';
36
    public const HEAD = 'HEAD';
37
    public const GET = 'GET';
38
    public const POST = 'POST';
39
    public const PUT = 'PUT';
40
    public const DELETE = 'DELETE';
41
    public const PATCH = 'PATCH';
42
43
    /**
44
     * Routes array to be registered.
45
     * Some routes may have aliases to be used in templating system
46
     * Route item can be defined using array key as an alias key.
47
     * Each route item is an array has items respectively: Request Method, Request Uri, Controller/Action, Return Type.
48
     *
49
     * @var array
50
     */
51
    private $routes = [];
52
53
    /**
54
     * Aliases array to be registered.
55
     *
56
     * @var array
57
     */
58
    private $aliases = [];
59
60
    /**
61
     * HTTP request Method
62
     *
63
     * @var string
64
     */
65
    private $method;
66
67
    /**
68
     * Request Uri
69
     *
70
     * @var string
71
     */
72
    private $requestedPath;
73
74
    /**
75
     * Default return type if not noted in the $routes
76
     *
77
     * @var int
78
     */
79
    private $defaultReturnType;
80
81
    /**
82
     * @var null|string
83
     */
84
    private $cachedFile;
85
86
    /**
87
     * Valid Request Methods array.
88
     * Make sures about requested methods.
89
     *
90
     * @var array
91
     */
92
    private static $validRequestMethods = [
93
        'GET',
94
        'OPTIONS',
95
        'HEAD',
96
        'POST',
97
        'PUT',
98
        'DELETE',
99
        'PATCH'
100
    ];
101
102
    /*
103
     * Router constructor.
104
     * Create new router.
105
106
     */
107
    public function __construct(
108
        int $defaultReturnType,
109
        string $method,
110
        string $requestedPath
111
    ) {
112
        if (!in_array($method, self::$validRequestMethods, true)) {
113
            $message = sprintf('%s is not valid Http request method.', $method);
114
            throw new InvalidRequestMethodException($message);
115
        }
116
        $this->method = $method;
117
        $this->requestedPath = $requestedPath;
118
        $this->defaultReturnType = ($defaultReturnType >=1 && $defaultReturnType <=7) ? $defaultReturnType : self::HTML;
119
    }
120
121
    public function withSubFolder(string $folder) : self
122
    {
123
        $new = clone $this;
124
        $new->requestedPath = $this->extractFolder($this->requestedPath, $folder);
125
        return $new;
126
    }
127
    public function withCacheFile(string $fileName) : self
128
    {
129
        $new = clone $this;
130
        $new->cachedFile = $fileName;
131
        return $new;
132
    }
133
134
    /*
135
     * Remove sub folder from requestedPath if defined
136
     */
137
    private function extractFolder(string $requestPath, string $folder) : string
138
    {
139
        if (!empty($folder)) {
140
            $requestPath = '/' . trim((string) preg_replace('#^/' . $folder . '#msi', '/', $requestPath), '/');
141
        }
142
        if ($requestPath === '') {
143
            $requestPath = '/';
144
        }
145
        return $requestPath;
146
    }
147
148
149
    public function add(
150
        $requestMethods,
151
        string $route,
152
        $action,
153
        ?int $returnType = null,
154
        ?string $alias = null
155
    ) : void {
156
    
157
        $requestMethodsGiven = is_array($requestMethods) ? $requestMethods : [$requestMethods];
158
        $returnType = $this->determineReturnType($returnType);
159
        foreach ($requestMethodsGiven as $requestMethod) {
160
            $this->checkRequestMethodIsValid($requestMethod);
161
            if ($alias !== null) {
162
                $this->aliases[$alias] = $route;
163
            }
164
            $this->routes[] = [strtoupper($requestMethod), $route, $action, $returnType];
165
        }
166
    }
167
168
169
    public function __call(string $method, array $args) : void
170
    {
171
        $defaults = [
172
            null,
173
            null,
174
            $this->defaultReturnType,
175
            null
176
        ];
177
        [$route, $action, $returnType, $alias] = array_merge($args, $defaults);
178
        $this->add($method, $route, $action, $returnType, $alias);
179
    }
180
181
    private function determineReturnType(?int $returnType) : int
182
    {
183
        if ($returnType === null) {
184
            return $this->defaultReturnType;
185
        }
186
        return ($returnType >=1 && $returnType <=7) ? $returnType : self::HTML;
187
    }
188
189
    private function checkRequestMethodIsValid(string $requestMethod) : void
190
    {
191
        if (!in_array(strtoupper($requestMethod), self::$validRequestMethods, true)) {
192
            $message = sprintf('%s is not valid Http request method.', $requestMethod);
193
            throw new InvalidRequestMethodException($message);
194
        }
195
    }
196
197
    public function getRoute() : Route
198
    {
199
        $selamiDispatcher = new Dispatcher($this->routes, $this->defaultReturnType, $this->cachedFile);
200
        $routeInfo = $selamiDispatcher->dispatcher()
201
            ->dispatch($this->method, $this->requestedPath);
202
        return $selamiDispatcher->runDispatcher($routeInfo)
203
            ->withAliases($this->aliases);
204
    }
205
}
206