Router   A
last analyzed

Complexity

Total Complexity 17

Size/Duplication

Total Lines 200
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
wmc 17
lcom 1
cbo 6
dl 0
loc 200
rs 10
c 0
b 0
f 0

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A addRoute() 0 12 1
A setBaseHost() 0 6 1
A process() 0 19 3
A handleRoute() 0 28 3
A filterParameters() 0 12 3
A extractHostParameters() 0 13 2
A cleanHostName() 0 15 3
1
<?php
2
/*
3
 MIT License
4
 Copyright (c) 2010 - 2018 Peter Petermann
5
6
 Permission is hereby granted, free of charge, to any person
7
 obtaining a copy of this software and associated documentation
8
 files (the "Software"), to deal in the Software without
9
 restriction, including without limitation the rights to use,
10
 copy, modify, merge, publish, distribute, sublicense, and/or sell
11
 copies of the Software, and to permit persons to whom the
12
 Software is furnished to do so, subject to the following
13
 conditions:
14
15
 The above copyright notice and this permission notice shall be
16
 included in all copies or substantial portions of the Software.
17
18
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20
 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22
 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23
 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24
 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25
 OTHER DEALINGS IN THE SOFTWARE.
26
27
*/
28
namespace King23\Http;
29
30
use Psr\Container\ContainerInterface;
31
use Psr\Http\Message\ResponseInterface;
32
use Psr\Http\Message\ServerRequestInterface;
33
use Psr\Http\Server\RequestHandlerInterface;
34
use Psr\Log\LoggerInterface;
35
36
/**
37
 * King23_Router class, allowing the matching of URL -> classmethod
38
 */
39
class Router implements RouterInterface
40
{
41
    /**
42
     * Array for storing known routes
43
     *
44
     * @var array
45
     */
46
    protected $routes = [];
47
48
    /**
49
     * String containing the basis host of the application, if this is set
50
     * this parameter will be removed from the hostname before hostparameters are extracted,
51
     * so having a low parameter count won't falsify the parameters by using the basic host as parameters
52
     *
53
     * @var string
54
     */
55
    protected $baseHost = null;
56
57
    /**
58
     * @var LoggerInterface
59
     */
60
    protected $log;
61
62
    /**
63
     * @var ContainerInterface
64
     */
65
    protected $container;
66
67
    /**
68
     * @param LoggerInterface $log
69
     * @param ContainerInterface $container
70
     */
71
    public function __construct(LoggerInterface $log, ContainerInterface $container)
72
    {
73
        $this->log = $log;
74
        $this->container = $container;
75
    }
76
77
    /**
78
     * add route to list of known routes
79
     *
80
     * @param String $route beginning string of the route
81
     * @param String $class to be used for this route
82
     * @param String $action method to be called
83
     * @param string[] $parameters list of parameters that should be retrieved from url
84
     * @param array $hostparameters - allows to use subdomains as parameters
85
     * @return self
86
     */
87
    public function addRoute($route, $class, $action, $parameters = [], $hostparameters = [])
88
    {
89
        $this->log->debug('adding route : ' . $route . ' to class ' . $class . ' and action ' . $action);
90
91
        $this->routes[$route] = [
92
            "class" => $class,
93
            "action" => $action,
94
            "parameters" => $parameters,
95
            "hostparameters" => $hostparameters
96
        ];
97
        return $this;
98
    }
99
100
    /**
101
     * method to set the basicHost for hostparameters in routing
102
     *
103
     * @see King23_Router::$basicHost
104
     * @param String $baseHost
105
     * @return self
106
     */
107
    public function setBaseHost($baseHost = null)
108
    {
109
        $this->log->debug('Setting Router baseHost to ' . $baseHost);
110
        $this->baseHost = $baseHost;
111
        return $this;
112
    }
113
114
    /**
115
     * @param ServerRequestInterface $request
116
     * @param RequestHandlerInterface $next
117
     * @return ResponseInterface
118
     * @throws \King23\Controller\Exceptions\ActionDoesNotExistException
119
     */
120
    public function process(ServerRequestInterface $request, RequestHandlerInterface $next) : ResponseInterface {
121
        $this->log->debug('Dispatching request for ' . $request->getUri()->getPath());
122
123
        // sort routes
124
        uksort(
125
            $this->routes,
126
            function ($a, $b) {
127
                return strlen($a) < strlen($b);
128
            }
129
        );
130
        foreach ($this->routes as $route => $info) {
131
            // check if route is matched
132
            if (substr($request->getUri()->getPath(), 0, strlen($route)) == $route) {
133
                $this->log->debug('route ' . $route . ' matches ' . $request->getUri()->getPath());
134
                return $this->handleRoute($info, $request, $route);
135
            }
136
        }
137
        return $next->handle($request);
138
    }
139
140
    /**
141
     * Handle a regular route
142
     *
143
     * @param array $info
144
     * @param ServerRequestInterface $request
145
     * @param string $route
146
     * @return ResponseInterface
147
     * @throws \King23\Controller\Exceptions\ActionDoesNotExistException
148
     */
149
    private function handleRoute($info, ServerRequestInterface $request, $route) : ResponseInterface
150
    {
151
        // initialize router attributes for the request
152
        $attributes = [
153
            'params' => [
154
                'url' => [],
155
                'host' => []
156
            ]
157
        ];
158
159
        // prepare parameters
160
        if ($paramstr = substr($request->getUri()->getPath(), strlen($route))) {
161
            $attributes['params']['url'] = $this->filterParameters($info['parameters'], explode("/", $paramstr));
162
        }
163
164
        // check host parameters
165
        if (count($info["hostparameters"]) > 0) {
166
            $attributes['params']['host'] = $this->extractHostParameters($request, $info);
167
        }
168
169
        // put route parameters into king23.router.parameters attribute
170
        $request = $request->withAttribute('king23.router', $attributes);
171
172
        /** @var \King23\Controller\Controller $controller */
173
        $controller = $this->container->get($info["class"]);
174
175
        return $controller->dispatch($info["action"], $request);
176
    }
177
178
    /**
179
     * @param array $info
180
     * @param array $params
181
     * @return array
182
     */
183
    private function filterParameters($info, $params)
184
    {
185
        $parameters = [];
186
        foreach ($info as $key => $value) {
187
            if (isset($params[$key])) {
188
                $parameters[$value] = urldecode($params[$key]);
189
            } else {
190
                $parameters[$value] = null;
191
            }
192
        }
193
        return $parameters;
194
    }
195
196
    /**
197
     * extract parameters from hostname
198
     *
199
     * @param ServerRequestInterface $request
200
     * @param array $info
201
     * @return array
202
     */
203
    private function extractHostParameters($request, $info)
204
    {
205
        $hostname = $this->cleanHostName($request);
206
207
        if (empty($hostname)) {
208
            $params = [];
209
        } else {
210
            $params = array_reverse(explode(".", $hostname));
211
        }
212
213
        $parameters = $this->filterParameters($info['hostparameters'], $params);
214
        return $parameters;
215
    }
216
217
    /**
218
     * will get hostname, and clean basehost off it
219
     *
220
     * @param ServerRequestInterface $request
221
     * @return string
222
     */
223
    private function cleanHostName(ServerRequestInterface $request)
224
    {
225
226
        if (is_null($this->baseHost)) {
227
            $hostname = $request->getUri()->getHost();
228
        } else {
229
            $hostname = str_replace($this->baseHost, "", $request->getUri()->getHost());
230
        }
231
232
        if (substr($hostname, -1) == ".") {
233
            $hostname = substr($hostname, 0, -1);
234
        }
235
236
        return $hostname;
237
    }
238
}
239