Completed
Push — master ( e32a6c...5f3630 )
by Taosikai
15:51 queued 54s
created

Matcher.php (3 issues)

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 Route[]
17
     */
18
    protected $routes;
19
20
    public function __construct(RouteCollection $routes)
21
    {
22
        $this->routes = $routes;
0 ignored issues
show
Documentation Bug introduced by
It seems like $routes of type object<Slince\Routing\RouteCollection> is incompatible with the declared type array<integer,object<Slince\Routing\Route>> of property $routes.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
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', []),
0 ignored issues
show
array() is of type array, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
179
            $route->getParameter('_pathMatches', [])
0 ignored issues
show
array() is of type array, but the function expects a string|null.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
180
        );
181
    }
182
}