-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdispatcher.class.php
117 lines (105 loc) · 3.24 KB
/
dispatcher.class.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
<?php
/**
* Dispatcher, handles basic request dispatching based on mappings (singleton)
*/
class Dispatcher {
private static $instance;
private $mappings;
/**
* Construction function for Dispatcher - private to enforce singleton
*/
private function __construct() {
$this->mappings = array();
}
/**
* Get the active instance of the singleton
*/
public static function instance() {
if (empty(self::$instance)) {
self::$instance = new Dispatcher();
}
return self::$instance;
}
/**
* Add a mapping, see comment on constructor for format
* @param $mapping - a mapping of paths to handlers - for example:
* array(
* '/api/*.json' => array (
* 'prepare' => (callback) 'checkParameters', // An optional function to prepare the data prior to sending it to the handler (as a php callback)
* 'handler' => (callback) array('LoginController', 'saveUser') // A function to handle the request (as a php callback)
* )
* )
*/
public function addMapping($mapping = array()) {
$this->mappings = array_merge($this->mappings, $mapping);
}
/**
* This is the main function for Dispatcher, it takes a request, parses it, finds the best handler and calls it
*/
public function handle() {
//get the request
$request = empty($_GET['q']) ? '' : $_GET['q'];
//find the best handler
$handler = $this->getHandler($request);
if ($handler) {
$data = $_REQUEST;
// add the exploded path as a data item for convience
$data['path args'] = explode('/', $request);
//run the prepare function if it exists
if ($handler['prepare']) {
$data = static::run($handler['prepare'], $data);
}
//run the handler
$response = static::run($handler['handler'], $data);
} else {
//return a 404 if we couldn't find the handler
header("HTTP/1.0 404 Not Found");
$response = 'SadFace, we couldn\'t find <em>' . $request . '</em>. We\'ll keep looking, but you might want to hit the back button.';
}
echo $response;
}
/**
* Find the best (aka most specific) handler for a request
* @param $request - as string path - like /opt/dev or opt/dev
*/
protected function getHandler($request) {
$handler = FALSE;
$best = 0;
$request = explode('/', $request);
//remove any empty keys
$request = array_filter($request);
//loop through the handlers and find the ones that match
foreach ($this->mappings as $path => $mapping) {
//find the score for each handler that matches the mapping
$path = explode('/', $path);
//remove any empty keys
$path = array_filter($path);
$score = 0;
foreach ($request as $ind => $part) {
if ($part == $path[$ind]) {
$score++;
} else if ($path[$ind] == '*') {
continue;
} else {
$score = -1;
}
}
if ($score >= $best) {
$best = $score;
$handler = $mapping;
}
}
if ($best > 0) {
return $handler;
}
return FALSE;
}
/**
* Simple helper to call a user function
*/
private static function run ($callback, $data) {
if (is_callable($callback)) {
return call_user_func($callback, $data);
}
}
}