Completed
Push — master ( cc3500...7c787d )
by Taosikai
14:10
created

Matcher.php (1 issue)

Severity

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * slince routing library
4
 * @author Tao <[email protected]>
5
 */
6
namespace Slince\Routing;
7
8
use Psr\Http\Message\ServerRequestInterface;
9
use Slince\Routing\Exception\RouteNotFoundException;
10
use Slince\Routing\Exception\MethodNotAllowedException;
11
12
class Matcher
13
{
14
    /**
15
     * Routes collection
16
     * @var RouteCollection
17
     */
18
    protected $routes;
19
20
    public function __construct(RouteCollection $routes)
21
    {
22
        $this->routes = $routes;
23
    }
24
25
    /**
26
     * Find the route that match the given path from the routes
27
     * @param string $path
28
     * @return Route
29
     */
30
    public function match($path)
31
    {
32
        $path = '/' . ltrim($path, '/');
33
        return $this->doMatch($path);
34
    }
35
36
    /**
37
     * Find the route that match given request
38
     * @param ServerRequestInterface $request
39
     * @return Route
40
     */
41
    public function matchRequest(ServerRequestInterface $request)
42
    {
43
        return $this->doMatch($request);
44
    }
45
46
    /**
47
     * Do match
48
     * @param string|ServerRequestInterface $pathOrRequest
49
     * @return Route
50
     */
51
    protected function doMatch($pathOrRequest)
52
    {
53
        $route = $pathOrRequest instanceof ServerRequestInterface
54
            ? $this->findRouteFromRequest($pathOrRequest)
55
            : $this->findRoute($pathOrRequest);
56
        $computedParameters = $this->computeRouteParameters($route);
57
        $route->setComputedParameters($computedParameters);
58
        return $route;
59
    }
60
61
    /**
62
     * @param ServerRequestInterface $request
63
     * @throws MethodNotAllowedException
64
     * @throws RouteNotFoundException
65
     * @return Route
66
     */
67
    protected function findRouteFromRequest(ServerRequestInterface $request)
68
    {
69
        $requiredMethods = [];
70
        foreach ($this->routes as $route) {
71
            if (static::matchSchema($route, $request)
72
                && static::matchHost($route, $request)
73
                && static::matchPath($request->getUri()->getPath(), $route)
74
            ) {
75
                if (static::matchMethod($route, $request)) {
76
                    return $route;
77
                } else {
78
                    $requiredMethods = array_merge($requiredMethods, $route->getMethods());
79
                }
80
            }
81
        }
82
        if (!empty($requiredMethods)) {
83
            throw new MethodNotAllowedException($requiredMethods);
84
        }
85
        throw new RouteNotFoundException();
86
    }
87
88
    /**
89
     * @param string $path
90
     * @throws RouteNotFoundException
91
     * @return Route
92
     */
93
    protected function findRoute($path)
94
    {
95
        foreach ($this->routes as $route) {
96
            if (static::matchPath($path, $route)) {
97
                return $route;
98
            }
99
        }
100
        throw new RouteNotFoundException();
101
    }
102
103
    /**
104
     * Checks whether the route matches the current request host
105
     * @param Route $route
106
     * @param ServerRequestInterface $request
107
     * @return boolean
108
     */
109
    protected static function matchHost(Route $route, $request)
110
    {
111
        if (empty($route->getHost())) {
112
            return true;
113
        }
114
        if (preg_match($route->compile()->getHostRegex(), $request->getUri()->getHost(), $matches)) {
115
            $routeParameters = array_filter($matches, function($value, $key){
116
                return !is_int($key) && $value;
117
            }, ARRAY_FILTER_USE_BOTH);
118
            $route->setParameter('_hostMatches', $routeParameters);
119
            return true;
120
        }
121
        return false;
122
    }
123
124
    /**
125
     * Checks whether the route matches the current request method
126
     * @param Route $route
127
     * @param ServerRequestInterface $request
128
     * @return boolean
129
     */
130
    protected static function matchMethod(Route $route, $request)
131
    {
132
        if (!$route->getMethods()) {
133
            return true;
134
        }
135
        return in_array(strtoupper($request->getMethod()), $route->getMethods());
136
    }
137
138
    /**
139
     * Checks whether the route matches the scheme
140
     * @param Route $route
141
     * @param ServerRequestInterface $request
142
     * @return boolean
143
     */
144
    protected static function matchSchema(Route $route, $request)
145
    {
146
        if (!$route->getSchemes()) {
147
            return true;
148
        }
149
        return in_array($request->getUri()->getScheme(), $route->getSchemes());
150
    }
151
152
    /**
153
     * Checks whether the route matches the given path
154
     * @param string $path
155
     * @param Route $route
156
     * @return boolean
157
     */
158
    protected static function matchPath($path, Route $route)
159
    {
160
        if (preg_match($route->compile()->getPathRegex(), rawurldecode($path), $matches)) {
161
            $routeParameters = array_filter($matches, function($value, $key){
162
                return !is_int($key) && $value;
163
            }, ARRAY_FILTER_USE_BOTH);
164
            $route->setParameter('_pathMatches', $routeParameters);
165
            return true;
166
        }
167
        return false;
168
    }
169
170
    /**
171
     * 处理路由参数
172
     * @param Route $route
173
     * @return array
174
     */
175
    protected static function computeRouteParameters(Route $route)
176
    {
177
        return array_replace($route->getDefaults(),
178
            $route->getParameter('_hostMatches') ?: [],
179
            $route->getParameter('_pathMatches', []) ?: []
0 ignored issues
show
The call to Route::getParameter() has too many arguments starting with array().

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
180
        );
181
    }
182
}