2

上一个问题的延续:自定义锂路由方案

注意:这是特定于锂框架的

问题

我继承了一个 URL 方案,它实际上没有任何约定来区分页面、项目和类别。所以,我有一个非常通用的路由器,它传递给一个包罗万象的控制器。

这个包罗万象的控制器 (PagesController) 使用 url 作为键从数据库中检索页面类型。然后 PagesController 运行方法并根据页面类型选择模板。我将这些信息无限期地存储在 Memcached 中,因此查找速度非常快。

然而,随着越来越多的页面类型开始发挥作用,我可以看到这个控制器变得过于臃肿和不灵活。理想情况下,我想将不同的页面类型分解为它们自己的控制器。

解决方案?

是否有可能有一个路由方案来检查数据库以确定正确的控制器?

我的第一个想法是在and中继承lithium\net\http\Router和使用自定义逻辑。Router::connect()Router::_parseController()

如果可以在 bootstrap\routes.php 中查询数据库并lithium\net\http\Route根据结果创建一个新对象,那就太好了。然后,只需将其传递给Router::connect(). 这似乎是一个可怕的黑客攻击。

无论哪种方式,Router::connect()它的设计并不意味着是动态的。

4

2 回答 2

3

很难非常具体,没有看到更多不同页面类型的示例和其他示例 URL(我确实看过上一个问题,但我觉得这并没有给出全貌),但与上一个问题一样,听起来答案将再次是使用处理程序的自定义路由。

Router::connect('/{:pageType}/{:pageKey}', ['pageKey' => null], function($req) {
    $types = ['list', 'of', 'page', 'types'];
    $controller = 'pages';
    $action = 'view';

    if (in_array($req->pageType, $types)) {
        // It's a proper type, do a database lookup and set
        // `$controller` accordingly

        // Here I'm assuming category vs. item view for the action:
        $action = $req->pageKey ? 'view' : 'index';
    } elseif (!$req->pageKey) {
        // It's a `/custom` URL, figure out what to do with it
    }

    // This lets you return custom, arbitrary parameters that Lithium
    // will use for dispatch
    return compact('controller', 'action') + $req->params;
});

如您所见,使用处理程序,您几乎可以做任何您想做的事情。解析参数,运行你的数据库调用,并传回一组完全任意的路由参数供 Lithium 调度。

如果您的规则开始变得复杂,您可能要添加到上面的唯一其他内容是一个单独的类,它可以管理页面类型/自定义页面和路由参数之间的配对。

于 2013-01-29T16:44:38.320 回答
-1

您可以构建一个像一堆过滤器一样工作的路由器。

您从列表的顶部开始并询问每个过滤器是否与给定的 URL 匹配。如果不匹配,它将继续到下一个过滤器等。一直到堆栈。

堆栈顶部的过滤器具有更高的优先级。优先级可能是因为匹配规则或仅仅是性能。IE。数据库查找速度很慢,因此请添加一个预过滤器,以尽快拒绝不匹配的 URL。

您可以构建一个非常通用的路由器类,您可以在其中添加过滤器。路由器只是(堆栈)过滤器的容器,具有使用给定输入数据集开始运行的方法。

class Router {
    public function addFilter(Filter $filter) {}
    public function run($input) {}  // returns a route
}

interface Filter {
    public function findRoute($input) {} // returns false or a route
}

这允许非常模块化的结构。您可以在加载模块时动态添加过滤器。

一个示例过滤器可能是:

class NewsFilter implements Filter {
    public function findRoute($input) {
        if (preg_match(":^/news/item/([0-9]+)$:", $input["url"], $matches)) {
            $item = $this->news->findItem($matches[1]);
            if (false === $item) {
                return false;
            } else {
                return new NewsRoute($item);
            }
        }
        return false;
    }
}

$router = new Router();
$newsfilter = new NewsFilter();
$router->addFilter($newsfilter);
...
$router->run($input);
于 2013-01-28T17:17:03.147 回答