关于重构自定义路由方案的建议(锂框架)

时间:2013-01-28 17:07:38

标签: php refactoring url-routing lithium

上一个问题的延续:Custom lithium routing scenario

注意:这是特定于Lithium Framework

问题

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

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

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

解决方案?

是否可以使用检查数据库以确定正确控制器的路由方案?

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

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

无论哪种方式,Router::connect()在其设计中并不意味着 动态。

2 个答案:

答案 0 :(得分:3)

很难非常具体,没有看到更多不同页面类型和其他示例网址的例子(我确实看过上一个问题,但我觉得这并不能说明整个情况),但与在上一个问题中,听起来答案将再次成为使用处理程序的自定义路由。

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调度。

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

答案 1 :(得分:-1)

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

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

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

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

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);
相关问题