1

我当前的路由器 / 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');
        }
    }
}
4

4 回答 4

3

根据您的代码片段,我会这样做(伪 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;
}

所以基本上如果没有控制器来处理某个位置,您检查是否有任何控制器配置为将给定路径作为别名处理,如果是,则返回该控制器及其映射到的方法。

于 2013-01-22T20:47:53.553 回答
3

您可以通过以下两种方法之一使用您的 URL:

按照路由定义控制器的方式建立控制器

example.com/contact => 有一个带有默认或索引操作的“联系人”控制器

example.com/about/portfolio => 有一个带有“portfolio”操作的“about”控制器

因为您当前可用的路由表明您的 URL 被视为“/controller/method”,所以没有其他方法。

建立动态路由以允许单个控制器处理多个 URL

显然,这需要一些配置,因为无法知道哪些 URL 是有效的,哪些应该重定向到通用控制器,哪些不应该。这在某种程度上可以替代任何重写或重定向解决方案,但由于它是在 PHP 级别处理的,因此更改可能更容易处理(由于性能原因,某些 Web 服务器配置不提供 .htaccess,而且通常需要更多的努力创建这些)。

您的配置输入是:

  1. 您要处理的 URL 和
  2. 您希望将 URL 传递到的控制器,以及它的操作。

你最终会得到一个这样的数组结构:

$specialRoutes = array(
    "/contact" => "IndexController::indexAction",
    "/about/portfolio" => "IndexController::indexAction"
);

缺少的是此操作应将当前 URL 作为参数传递,或者路径部分成为 URL 架构中的指定参数。

总而言之,这种方法编码起来要困难得多。要了解一个想法,请尝试查看常见 MVC 框架的路由,例如 Symfony 和 Zend Framework。它们提供高度可配置的路由,因此,路由发生在多个类中。如果检测到匹配,主路由器只读取配置,然后将任何 URL 的路由传递给配置的路由器。

于 2013-01-22T21:34:36.127 回答
1

您可以在您的网络服务器中为这些异常创建重写。例如:

RewriteRule ^contact$ /index/contact
RewriteRule ^about/portfolio$ /about/portfolio

这将允许您拥有映射到常规结构的简化 URL。

如果您能够精确定义应该重写到 /index 的内容,则可以有一个动态规则。例如:

RewriteRule ^([a-z]+)$ /index/$1
于 2013-01-22T20:31:53.587 回答
1

试试这个动态 htaccess 重写规则:

RewriteRule ^(.+)/?$ /index/$1 [QSA]

QSA如果需要,上述规则中的标志还允许您在末尾添加查询字符串,如下所示:

http://localhost/contact?arg1=1&arg2=2

编辑:此规则还将处理以下情况/about/portfolio

RewriteRule ^(.+)/?(.+)?$ /index/$1 [QSA]
于 2013-01-22T20:36:52.473 回答