Last active
August 29, 2015 14:12
-
-
Save noodlehaus/3e7243dafd2e003b561c to your computer and use it in GitHub Desktop.
routing functions from dispatch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
# @author Jesus A. Domingo | |
# @license MIT <http://noodlehaus.mit-license.org> | |
namespace noodlehaus\pico; | |
# returns the value for an http request header | |
function request_header($name) { | |
$headers = &$GLOBALS['app/state']['request_headers']; | |
# first call, prime it | |
if (!count($headers)) { | |
# if we're not in CLI, use it | |
if (function_exists('getallheaders')) { | |
$headers = array_change_key_case(getallheaders()); | |
} else { | |
# manual header extraction (CLI + test) | |
$special = array('CONTENT_LENGTH', 'CONTENT_MD5', 'CONTENT_TYPE'); | |
# get the rest of the headers out | |
foreach ($_SERVER as $name => $data) { | |
if (0 === strpos($name, 'HTTP_')) { | |
$name = strtolower(str_replace('_', '-', substr($name, 5))); | |
$headers[$name] = $data; | |
} else if (in_array($name, $special)) { | |
$name = strtolower(str_replace('_', '-', $name)); | |
$headers[$name] = $data; | |
} | |
} | |
} | |
} | |
# normalize the input then try to fetch | |
$name = trim(strtolower($name)); | |
return isset($headers[$name]) ? $headers[$name] : null; | |
} | |
# function for mapping actions to routes | |
function map() { | |
$args = func_get_args(); | |
$data = &$GLOBALS['app/state']['routes']; | |
# try to figure out how we were called | |
switch (count($args)) { | |
# (method, path, handler) | |
case 3: | |
foreach ((array) $args[0] as $verb) { | |
$data['explicit'][strtoupper($verb)][] = array( | |
'/'.trim($args[1], '/'), | |
$args[2] | |
); | |
} | |
break; | |
# (path, handler) | |
case 2: | |
foreach ((array) $args[0] as $path) { | |
$data['any'][] = array('/'.trim($path, '/'), $args[1]); | |
} | |
break; | |
# any method and any path (just one for this, replace ref) | |
case 1: | |
$data['all'] = $args[0]; | |
break; | |
# everything else | |
default: | |
throw new BadFunctionCallException( | |
'Invalid number of arguments.', | |
500 | |
); | |
} | |
} | |
# hooks actions to route symbols | |
function hook($name, $func) { | |
$GLOBALS['app/state']['routes']['hooks'][$name] = $func; | |
} | |
# dispatches the current request against our handlers/actions | |
function run() { | |
$args = func_get_args(); | |
$data = &$GLOBALS['app/state']['routes']; | |
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); | |
$path = trim($path, '/'); | |
$path = trim($path, '/'); | |
$verb = strtoupper($_SERVER['REQUEST_METHOD']); | |
# for POST requests, check for method override header or _method | |
if ($verb == 'POST') { | |
if (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) { | |
$verb = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']); | |
} else { | |
$verb = isset($_POST['_method']) ? strtoupper($_POST['_method']) : $verb; | |
} | |
} | |
# set any mapping as base, then append exp_mapping if any | |
$maps = $data['any']; | |
if (isset($data['explicit'][$verb])) { | |
$maps = array_merge($data['explicit'][$verb], $maps); | |
} | |
$rexp = null; | |
$func = null; | |
$vals = null; | |
# try to see if we have any matching route | |
foreach ($maps as $temp) { | |
list($rexp, $call) = $temp; | |
$rexp = trim($rexp, '/'); | |
$rexp = preg_replace('@\{(\w+)\}@', '(?<\1>[^/]+)', $rexp); | |
if (!preg_match('@^'.$rexp.'$@', $path, $vals)) { | |
continue; | |
} | |
$func = $call; | |
break; | |
} | |
# valid handler, try to parse out route symbol values | |
if ($func && is_callable($func)) { | |
# remove top group from vals | |
array_shift($vals); | |
# extract route symbols and run the hook()s | |
if ($vals) { | |
# extract any route symbol values | |
$toks = array_filter(array_keys($vals), 'is_string'); | |
$vals = array_map('urldecode', array_intersect_key( | |
$vals, | |
array_flip($toks) | |
)); | |
# if we have symbol hooks, run them | |
if (count($data['hooks'])) { | |
foreach ($vals as $key => $val) { | |
if (!isset($data['hooks'][$key])) { | |
continue; | |
} | |
$hook = $data['hooks'][$key]; | |
$vals[$key] = call_user_func_array( | |
$hook, | |
array_merge((array) $val, $args) | |
); | |
} | |
} | |
# insert symbol values before dispatch() args | |
array_unshift($args, $vals); | |
} | |
} else { | |
# no matching handler, try to use 'all', or 404 | |
if (is_callable($data['all'])) { | |
$func = $data['all']; | |
} else { | |
$func = function () { | |
\header("{$_SERVER['SERVER_PROTOCOL']} 404 Not found", true, 404); | |
echo "Not found\n"; | |
exit; | |
}; | |
} | |
} | |
return call_user_func_array($func, $args); | |
} | |
# state (routes, handlers, etc) | |
$GLOBALS['app/state'] = array( | |
'stash' => array(), | |
'request_headers' => array(), | |
'routes' => array( | |
'all' => null, | |
'any' => array(), | |
'hooks' => array(), | |
'explicit' => array(), | |
'errors' => array() | |
) | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment