|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace Vectorface\SnappyRouter\Handler; |
|
4
|
|
|
|
|
5
|
|
|
use FastRoute\Dispatcher; |
|
6
|
|
|
use FastRoute\RouteCollector; |
|
7
|
|
|
|
|
8
|
|
|
/** |
|
9
|
|
|
* A handler for matching route patterns and mapping to a method. |
|
10
|
|
|
* Internally the class uses FastRoute to do the pattern matching. |
|
11
|
|
|
* @copyright Copyright (c) 2014, VectorFace, Inc. |
|
12
|
|
|
* @author Dan Bruce <[email protected]> |
|
13
|
|
|
*/ |
|
14
|
|
|
class PatternMatchHandler extends AbstractRequestHandler |
|
15
|
|
|
{ |
|
16
|
|
|
/** the config key for the list of routes */ |
|
17
|
|
|
const KEY_ROUTES = 'routes'; |
|
18
|
|
|
|
|
19
|
|
|
/** the config key for the route cache */ |
|
20
|
|
|
const KEY_CACHE = 'routeCache'; |
|
21
|
|
|
|
|
22
|
|
|
// the currently active callback |
|
23
|
|
|
private $callback; |
|
24
|
|
|
// the currently active route parameters |
|
25
|
|
|
private $routeParams; |
|
26
|
|
|
|
|
27
|
|
|
/** All supported HTTP verbs */ |
|
28
|
|
|
private static $allHttpVerbs = array( |
|
29
|
|
|
'GET', |
|
30
|
|
|
'POST', |
|
31
|
|
|
'PUT', |
|
32
|
|
|
'DELETE', |
|
33
|
|
|
'OPTIONS' |
|
34
|
|
|
); |
|
35
|
|
|
|
|
36
|
|
|
/** The route information from FastRoute */ |
|
37
|
|
|
private $routeInfo; |
|
38
|
|
|
|
|
39
|
|
|
/** |
|
40
|
|
|
* Returns true if the handler determines it should handle this request and false otherwise. |
|
41
|
|
|
* @param string $path The URL path for the request. |
|
42
|
|
|
* @param array $query The query parameters. |
|
43
|
|
|
* @param array $post The post data. |
|
44
|
|
|
* @param string $verb The HTTP verb used in the request. |
|
45
|
|
|
* @return boolean Returns true if this handler will handle the request and false otherwise. |
|
46
|
|
|
*/ |
|
47
|
4 |
|
public function isAppropriate($path, $query, $post, $verb) |
|
48
|
|
|
{ |
|
49
|
4 |
|
$routeInfo = $this->getRouteInfo($verb, $path); |
|
50
|
4 |
|
if (Dispatcher::FOUND !== $routeInfo[0]) { |
|
51
|
1 |
|
return false; |
|
52
|
|
|
} |
|
53
|
4 |
|
$this->callback = $routeInfo[1]; |
|
54
|
4 |
|
$this->routeParams = isset($routeInfo[2]) ? $routeInfo[2] : array(); |
|
55
|
4 |
|
return true; |
|
56
|
|
|
} |
|
57
|
|
|
|
|
58
|
|
|
/** |
|
59
|
|
|
* Returns the array of route info from the routing library. |
|
60
|
|
|
* @param string $verb The HTTP verb used in the request. |
|
61
|
|
|
* @param string $path The path to match against the patterns. |
|
62
|
|
|
* @param boolean $useCache (optional) An optional flag whether to use the |
|
63
|
|
|
* cached route info or not. Defaults to false. |
|
64
|
|
|
* @return array Returns the route info as an array. |
|
65
|
|
|
*/ |
|
66
|
33 |
|
protected function getRouteInfo($verb, $path, $useCache = false) |
|
67
|
|
|
{ |
|
68
|
33 |
|
if (!$useCache || !isset($this->routeInfo)) { |
|
69
|
33 |
|
$dispatcher = $this->getDispatcher($this->getRoutes()); |
|
70
|
33 |
|
$this->routeInfo = $dispatcher->dispatch(strtoupper($verb), $path); |
|
71
|
33 |
|
} |
|
72
|
33 |
|
return $this->routeInfo; |
|
73
|
|
|
} |
|
74
|
|
|
|
|
75
|
|
|
/** |
|
76
|
|
|
* Returns the array of routes. |
|
77
|
|
|
* @return array The array of routes. |
|
78
|
|
|
*/ |
|
79
|
4 |
|
protected function getRoutes() |
|
80
|
|
|
{ |
|
81
|
4 |
|
$options = $this->getOptions(); |
|
82
|
4 |
|
return isset($options[self::KEY_ROUTES]) ? $options[self::KEY_ROUTES] : array(); |
|
83
|
|
|
} |
|
84
|
|
|
|
|
85
|
|
|
/** |
|
86
|
|
|
* Performs the actual routing. |
|
87
|
|
|
* @return mixed Returns the result of the route. |
|
88
|
|
|
*/ |
|
89
|
1 |
|
public function performRoute() |
|
90
|
|
|
{ |
|
91
|
1 |
|
return call_user_func($this->callback, $this->routeParams); |
|
92
|
|
|
} |
|
93
|
|
|
|
|
94
|
|
|
/** |
|
95
|
|
|
* Returns a request object extracted from the request details (path, query, etc). The method |
|
96
|
|
|
* isAppropriate() must have returned true, otherwise this method should return null. |
|
97
|
|
|
* @return \Vectorface\SnappyRouter\Request\HttpRequest|null Returns a |
|
98
|
|
|
* Request object or null if this handler is not appropriate. |
|
99
|
|
|
*/ |
|
100
|
2 |
|
public function getRequest() |
|
101
|
|
|
{ |
|
102
|
2 |
|
return null; |
|
103
|
|
|
} |
|
104
|
|
|
|
|
105
|
|
|
/** |
|
106
|
|
|
* Returns an instance of the FastRoute dispatcher. |
|
107
|
|
|
* @param array $routes The array of specified routes. |
|
108
|
|
|
* @return FastRoute\Dispatcher The dispatcher to use. |
|
109
|
|
|
*/ |
|
110
|
33 |
|
private function getDispatcher($routes) |
|
111
|
|
|
{ |
|
112
|
33 |
|
$verbs = self::$allHttpVerbs; |
|
113
|
33 |
|
$f = function (RouteCollector $collector) use ($routes, $verbs) { |
|
114
|
33 |
|
foreach ($routes as $pattern => $route) { |
|
115
|
33 |
|
if (is_array($route)) { |
|
116
|
2 |
|
foreach ($route as $verb => $callback) { |
|
117
|
2 |
|
$collector->addRoute(strtoupper($verb), $pattern, $callback); |
|
118
|
2 |
|
} |
|
119
|
2 |
|
} else { |
|
120
|
33 |
|
foreach ($verbs as $verb) { |
|
121
|
33 |
|
$collector->addRoute($verb, $pattern, $route); |
|
122
|
33 |
|
} |
|
123
|
|
|
} |
|
124
|
33 |
|
} |
|
125
|
33 |
|
}; |
|
126
|
|
|
|
|
127
|
33 |
|
$options = $this->getOptions(); |
|
128
|
33 |
|
$cacheData = array(); |
|
129
|
33 |
|
if (isset($options[self::KEY_CACHE])) { |
|
130
|
1 |
|
$cacheData = (array)$options[self::KEY_CACHE]; |
|
131
|
1 |
|
} |
|
132
|
|
|
|
|
133
|
33 |
|
if (empty($cacheData)) { |
|
134
|
32 |
|
return \FastRoute\simpleDispatcher($f); |
|
135
|
|
|
} else { |
|
136
|
1 |
|
return \FastRoute\cachedDispatcher($f, $cacheData); |
|
137
|
|
|
} |
|
138
|
|
|
} |
|
139
|
|
|
} |
|
140
|
|
|
|