我当前的路由器/ FrontController设置为以以下格式剖析URL:
http://localhost/controller/method/arg1/arg2/etc...
但是,我不确定如何获取默认的IndexController的某些请求,以便我可以输入:
http://localhost/contact
or
http://localhost/about/portfolio
而不是:
http://localhost/index/contact
or
http://localhost/index/about/portfolio
这是如何完成的?
<?php
namespace framework;
class FrontController {
const DEFAULT_CONTROLLER = 'framework\controllers\IndexController';
const DEFAULT_METHOD = 'index';
public $controller = self::DEFAULT_CONTROLLER;
public $method = self::DEFAULT_METHOD;
public $params = array();
public $model;
public $view;
function __construct() {
$this->model = new ModelFactory();
$this->view = new View();
}
// route request to the appropriate controller
public function route() {
// get request path
$basePath = trim(substr(PUBLIC_PATH, strlen($_SERVER['DOCUMENT_ROOT'])), '/') . '/';
$path = trim(parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH), '/');
if($basePath != '/' && strpos($path, $basePath) === 0) {
$path = substr($path, strlen($basePath));
}
// determine what action to take
@list($controller, $method, $params) = explode('/', $path, 3);
if(isset($controller, $method)) {
$obj = __NAMESPACE__ . '\\controllers\\' . ucfirst(strtolower($controller)) . 'Controller';
$interface = __NAMESPACE__ . '\\controllers\\' . 'InterfaceController';
// make sure a properly implemented controller and corresponding method exists
if(class_exists($obj) && method_exists($obj, $method) && in_array($interface, class_implements($obj))) {
$this->controller = $obj;
$this->method = $method;
if(isset($params)) {
$this->params = explode('/', $params);
}
}
}
// make sure we have the appropriate number of arguments
$args = new \ReflectionMethod($this->controller, $this->method);
$totalArgs = count($this->params);
if($totalArgs >= $args->getNumberOfRequiredParameters() && $totalArgs <= $args->getNumberOfParameters()) {
call_user_func_array(array(new $this->controller, $this->method), $this->params);
} else {
$this->view->load('404');
}
}
}
答案 0 :(得分:2)
基于你的代码片段我会这样做(伪php代码):
$handler = get_controller($controller);
if(!$handler && ($alias = lookup_alias($path))) {
list($handler, $method) = $alias;
}
if(!$handler) error_404();
function lookup_alias($path) {
foreach(ALL_CONTROLLERS as $controller) {
if(($alias = $controller->get_alias($path))) {
return $alias;
}
}
return null;
}
所以基本上如果没有控制器来处理某个位置,你检查是否有任何控制器配置为处理作为别名的给定路径,如果是,则返回该控制器及其映射到的方法。
答案 1 :(得分:2)
您可以通过以下两种方法之一使用您的网址:
以路由定义控制器的方式建立控制器
example.com/contact =&gt;拥有一个带有默认或索引操作的“联系”控制器
example.com/about/portfolio =&gt;拥有一个带有“投资组合”行动的“约”控制器
由于您当前可用的路由表明您的网址被视为“/ controller / method”,因此没有别的办法。
建立动态路由以允许单个控制器处理多个URL
显然,这需要一些配置,因为无法知道哪些URL有效,哪些URL应重定向到通用控制器,哪些不应该。这在某种程度上是对任何重写或重定向解决方案的替代,但由于它是在PHP级别上处理的,因此更改可能更容易处理(由于性能原因,某些Web服务器配置不提供.htaccess,并且通常更省力创造这些)。
您的配置输入是:
你最终会有这样的数组结构:
$specialRoutes = array(
"/contact" => "IndexController::indexAction",
"/about/portfolio" => "IndexController::indexAction"
);
缺少的是此操作应将当前URL作为参数传递,或者路径部分成为URL架构中的指定参数。
总而言之,这种方法很难编码。要了解一下,请尝试查看常见MVC框架的路由,例如Symfony和Zend Framework。它们提供高度可配置的路由,因此,路由在多个类中进行。主路由器仅读取配置,然后在检测到匹配时将任何URL的路由传递给配置的路由器。
答案 2 :(得分:1)
您可以在网络服务器中为这些例外创建重写。例如:
RewriteRule ^contact$ /index/contact
RewriteRule ^about/portfolio$ /about/portfolio
这将允许您拥有映射到常规结构的简化网址。
如果能够精确定义应重写为/ index的内容,则可以使用动态规则。例如:
RewriteRule ^([a-z]+)$ /index/$1
答案 3 :(得分:1)
试试这个动态的htaccess重写规则:
RewriteRule ^(.+)/?$ /index/$1 [QSA]
上述规则中的QSA
标志允许您根据需要在末尾添加查询字符串,如下所示:
http://localhost/contact?arg1=1&arg2=2
编辑:此规则还会处理/about/portfolio
等案例:
RewriteRule ^(.+)/?(.+)?$ /index/$1 [QSA]