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
|
|
|
} |
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
|
|
|
} |
119
|
|
|
} else { |
120
|
33 |
|
foreach ($verbs as $verb) { |
121
|
33 |
|
$collector->addRoute($verb, $pattern, $route); |
122
|
|
|
} |
123
|
|
|
} |
124
|
|
|
} |
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
|
|
|
} |
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
|
|
|
|