Ну, чтобы ответить на мой собственный вопрос с моим собственным предложением:
// split routePath and set base path
$routeParts = explode('/', $routePath);
$classPath = 'Flooid/Application';
do{
// append part to path and check if file exists
$classPath .= '/' . array_shift($routeParts);
if(is_file(FLOOID_PATH_BASE . '/' . $classPath . '.class.php')){
// transform to class name and check if method exists
$className = str_replace('/', '_', $classPath);
if(method_exists($className, $action = array_shift($routeParts))){
// build param key => value array
do{
$routeParams[current($routeParts)] = next($routeParts);
}while(next($routeParts));
// controller instance with params passed to __construct and break
$controller = new $className($routeParams);
break;
}
}
}while(!empty($routeParts));
// if controller exists call action else 404
if(isset($controller)){
$controller->{$action}();
}else{
throw new Flooid_System_ResponseException(404);
}
Мой автозагрузчик настолько же прост, как и выглядит:
function __autoload($className){
require_once FLOOID_PATH_BASE . '/' . str_replace('_', '/', $className) . '.class.php';
}
Это работает, на удивление хорошо. Я еще не выполнил некоторые проверки, такие как проверка того, что запрошенный контроллер фактически идет от моего Flooid_System_ControllerAbstract
, но на данный момент это то, с чем я работаю.
Несмотря на это, я чувствую, что этот подход мог бы выиграть от критики, если бы не полномасштабный капитальный ремонт.
С тех пор я пересмотрел этот подход, хотя в конечном итоге он выполняет те же функции. Вместо того, чтобы создавать экземпляр контроллера, он возвращает имя класса контроллера, имя метода и массив параметров. Все это в getVerifiedRouteData()
, verifyRouteParts()
и createParamArray()
. Я думаю, что хочу реорганизовать или обновить этот класс, хотя. Я ищу понимание того, где я могу оптимизировать удобочитаемость и удобство использования. :
class Flooid_Core_Router {
protected $_routeTable = array();
public function getRouteTable() {
return !empty($this->_routeTable)
? $this->_routeTable
: null;
}
public function setRouteTable(Array $routeTable, $mergeTables = true) {
$this->_routeTable = $mergeTables
? array_merge($this->_routeTable, $routeTable)
: $routeTable;
return $this;
}
public function getRouteRule($routeFrom) {
return isset($this->_routeTable[$routeFrom])
? $this->_routeTable[$routeFrom]
: null;
}
public function setRouteRule($routeFrom, $routeTo, Array $routeParams = null) {
$this->_routeTable[$routeFrom] = is_null($routeParams)
? $routeTo
: array($routeTo, $routeParams);
return $this;
}
public function unsetRouteRule($routeFrom) {
if(isset($this->_routeTable[$routeFrom])){
unset($this->_routeTable[$routeFrom]);
}
return $this;
}
public function getResolvedRoutePath($routePath, $strict = false) {
// iterate table
foreach($this->_routeTable as $routeFrom => $routeData){
// if advanced rule
if(is_array($routeData)){
// build rule
list($routeTo, $routeParams) = each($routeData);
foreach($routeParams as $paramName => $paramRule){
$routeFrom = str_replace("{{$paramName}}", "(?<{$paramName}>{$paramRule})", $routeFrom);
}
// if !advanced rule
}else{
// set rule
$routeTo = $routeData;
}
// if path matches rule
if(preg_match("#^{$routeFrom}$#Di", $routePath, $paramMatch)){
// check for and iterate rule param matches
if(is_array($paramMatch)){
foreach($paramMatch as $paramKey => $paramValue){
$routeTo = str_replace("{{$paramName}}", $paramValue, $routeTo);
}
}
// return resolved path
return $routeTo;
}
}
// if !strict return original path
return !$strict
? $routePath
: false;
}
public function createParamArray(Array $routeParts) {
$params = array();
if(!empty($routeParts)){
// iterate indexed array, use odd elements as keys
do{
$params[current($routeParts)] = next($routeParts);
}while(next($routeParts));
}
return $params;
}
public function verifyRouteParts($className, $methodName) {
if(!is_subclass_of($className, 'Flooid_Core_Controller_Abstract')){
return false;
}
if(!method_exists($className, $methodName)){
return false;
}
return true;
}
public function getVerfiedRouteData($routePath) {
$classParts = $routeParts = explode('/', $routePath);
// iterate class parts
do{
// get parts
$classPath = 'Flooid/Application/' . implode('/', $classParts);
$className = str_replace('/', '_', $classPath);
$methodName = isset($routeParts[count($classParts)]);
// if verified parts
if(is_file(FLOOID_PATH_BASE . '/' . $classPath . '.class.php') && $this->verifyRouteParts($className, $methodName)){
// return data array on verified
return array(
'className'
=> $className,
'methodName'
=> $methodName,
'params'
=> $this->createParamArray(array_slice($routeParts, count($classParts) + 1)),
);
}
// if !verified parts, slide back class/method/params
$classParts = array_slice($classParts, 0, count($classParts) - 1);
}while(!empty($classParts));
// return false on not verified
return false;
}
}