使用路由器映射多个路由(控制器)

时间:2017-01-24 07:46:56

标签: php design-patterns model-view-controller routing routes

我正在查看danny vankooten路由器库here。这看起来不错(虽然不确定它将如何处理从中到大的项目,例如电子商务网站)。现在,通过示例,这是映射

$router->map('GET','/', 'home.php', 'home');
$router->map('GET','/home/', 'home.php', 'home-home');
$router->map('GET','/plans/', 'plans.php', 'plans');
$router->map('GET','/about/', 'about.php', 'about');
$router->map('GET','/contact/', 'contact.php', 'contact');
$router->map('GET','/tos/', 'tos.html', 'tos');

假设我有一个场景,我的网站有20-30个静态页面或大约50个控制器,每个2-3个动作/方法。

如何映射它们。如果我使用上面的映射方法,我可能最终会有超过100行映射,这看起来不对。

我认为应该有一种方法或快捷方式/通配符,如检查是否有可用的页面或控制器,然后加载它或者抛出404。

如何以正确的方式映射所有路线?。

PS。向任何愿意回答如何使用通配符来匹配控制器/方法的上述路由器的人发放50的赏金。

4 个答案:

答案 0 :(得分:6)

如何减轻路由器文件的负担是在YAML文件中移动路径定义。你的YAML中仍然会有很多行,但它会更具可读性。

router.php文件中,使用以下代码:

不要忘记将symfony YAML解析器添加到composer.json

use Symfony\Component\Yaml\Yaml;
$yaml_file = 'routes.yaml';
$routes = Yaml::parse(file_get_contents($yaml_file));
foreach ($routes as $route_name => $params) {
    $router->map($params[0],$params[1], $params[2].'#'.$params[3], $route_name);
} 

// match current request
$match = $router->match();

您的文件routes.yaml将如下所示

index:      ["GET", "/", "home_controller", "display_item"]
content:    ["GET", "/content/[:parent]/?[:child]?", "content_controller", "display_item"]
article:    ["GET", "/article/[:page]", "article_controller", "display_item"]

要获得更小的文件,您可以做的另一件事是在许多小的YAML文件中分离您的路由定义。例如,一个用于静态文件,一个用于管理区域,一个用于前端...

要执行此类操作,您必须将router.php代码更改为以下内容:

use Symfony\Component\Yaml\Yaml;
$yaml_files = ['front.yaml', 'static.yaml', 'admin.yaml'];
foreach ($yaml_files as $yaml_file) {
    $routes = Yaml::parse(file_get_contents($yaml_file));
    foreach ($routes as $route_name => $params) {
        $router->map($params[0],$params[1], $params[2].'#'.$params[3], $route_name);
    } 
}

// match current request
$match = $router->match();

Danny Van Kooten也提出了PHP-Router,它内置了对YAML文件的支持。 (如果查看源代码,您将看到他使用Symfony解析器,因此两种方法非常相似)

From the doc

YAML路线定义

base_path: /blog

routes:
  index: [/index, someClass.indexAction, GET]
  contact: [/contact, someClass.contactAction, GET]
  about: [/about, someClass.aboutAction, GET]

Router.php

require __DIR__.'/vendor/autoload.php';

use PHPRouter\RouteCollection;
use PHPRouter\Config;
use PHPRouter\Router;
use PHPRouter\Route;

$config = Config::loadFromFile(__DIR__.'/router.yaml');
$router = Router::parseConfig($config);
$router->matchCurrentRequest();

答案 1 :(得分:3)

在库中没有任何功能可以执行您想要的操作,但是有另一种方法可以执行此操作,就是将这些页面存储在数据库中,您将在下面找到类似的内容

//your query
// "SELECT `method`, `route`, `page`, `name` FROM `static_pages`
$pages = (query); //your executed query
if(count($pages) > 0){
  foreach($pages as $page){
    $router->map($page['method'],$page['route'], $page['target'], (($page['name'] !== null || !empty($page['name']) ) ? $page['name'] : null));
  }
}

我希望这会有所帮助

答案 2 :(得分:3)

如果您使用预先构建的路由器,例如Silex,您可以执行以下操作:

$app->get('{route}', function($route) {
    $dir = "/path/to/my/static/files/";
    $file = $dir . $route . '.php';
    if (file_exists($file)) {
        require $file;
    } else {
        require '/path/to/custom/404.php';
    }
});

请注意,Silex和许多类似的路由器要求路由按优先顺序排列。当我需要使用这样的路由器时,我把它放在底部,这样它就不会意外地捕获其他任何东西。

请注意,如果你想构建像这个自定义的东西,你可以这样做 - 记住我不知道你的代码目前是什么样的或你需要什么逻辑 - 通过替换你的正则表达式(在Silex的例如,它使用大括号)并根据您制定的正则表达式检查$_SERVER['REQUEST_URI']

如果这是一个自定义应用程序,您可能不需要对此进行过度设计。

// routing class
foreach ($routes as $route) {
    if ($route != self::DEFAULT_ROUTE) {
        // do your normal routing logic
    } else {
        // check if file exists (as with code above), else send to error 404
    }
}

然后拨打电话:

$router->map('GET',Router::DEFAULT_ROUTE, 'legacyRouter.php', 'legacy');

答案 3 :(得分:2)

作为引导阶段的一部分,告诉您的控制器将自己映射到路由器上:

// bootstrap
$router = new AltoRouter();

FooController::mapRoutes($router);
BarController::mapRoutes($router);
// etc.

每个控制器都可以生成所需的路径。