Getting a string from a Regex?
Is there a way to get the opposite of a Regex? To put this simply it's for a routing engine... It's all set up fine, but I'm writing a function to build URLs for links. Here's a routes.php file:
class Router {
/*
* @var urls Contains info about routes
* @format '{^REGEX(?<url_paramaters>$}' => array('ControllerClassName', 'ActionName', array/string('method(s)'))
*/
var $urls = array(
array('{^$}' => array('PagesController', 'index')),
array('{^contact$}' => array('PagesController', 'contact', 'get')),
array('{^about$}' => array('PagesController', 'about', 'get')),
array('{^users/(?<user_id>\d+)$}' => array('UsersController', 'show')),
);
}
Right. SO that's all working fine. The dispatcher matches the URL against the regex, then dispatches it using the array following the Regex. Here's my URL builder function... currently:
function build(array $resource = null) {
$routes = new Router;
$controller = ucwords((isset($resource['controller'])) ? $resource['controller'] : $GLOBALS['controller']) . "Controller";
$action = (isset($resource['action'])) ? $resource['action'] : 'index';
// Loop through the routes to find the right Regex using the callback
foreach($routes->urls as $route) {
$reg开发者_如何转开发ex = array_keys($route);
$regex = $regex[0]; //Eg/ ^users/(?<user_id>\d+)$
$callback = $route[$regex];
// ?? Something in here.
}
}
Imagine the $resource could contain stuff like "user_id" => 123. How could I go through the regex setting the capture groups to the right value? I hope I worded this well enough! Thanks in advance, Brad
Maybe this can help
preg_match('@/users/(?P<userId>\d+)/@Uis', $_SERVER['REQUEST_URL'], $matches);
// url: /users/1/
// $matches['userId'] = 1
You should use ordinary string concatenation and prepare an ordinary php map (instead of attempting to convert the regexpressions into one). For example:
// if $resource contains the capture groups
$keys = implode(",", array_keys($r = $resource));
// you would need an if-tree or switch to avoid notices here
$map = array(
"user_id" => "users/$r[user_id]",
"PagesController,contact,get" => "contact",
"" => "",
}
return $map[$keys];
You see that the regex URL mapping is not reversible alone with the capture groups. You need other clues for "contact" and "about" pages. I've used the routing parmeters here as example. You could however simply create an unused capture group in your original regex:
array('{^(?<contact>contact)$}' => ...
Think I've got it. It's probably a pretty bad solution but here it is anyway. PS. Please optimize it if you can! Ta.
function build(array $resource = null) {
$routes = new Router;
$controller = ucwords((isset($resource['controller'])) ? $resource['controller'] : $GLOBALS['controller']) . "Controller";
$action = isset($resource['action']) ? $resource['action'] : 'index';
// Loop through the routes to find the right Regex using the callback
foreach($routes->urls as $route) {
$regex = array_keys($route);
$regex = $regex[0]; // ^users/(?<user_id>\d+)$
$callback = $route[$regex];
if($controller == $callback[0] && $action == $callback[1]) {
$url = substr($regex, 2, -2);
foreach($resource as $key => $value) {
$url = preg_replace("/\??\(\?<".$key.">[^\)]+\)\??/", $value, $url);
$url = preg_replace("/\)?\(?\??/", "", $url);
}
break;
}
}
return "/".$url."/";
}
精彩评论