Отображение нескольких маршрутов (контроллера) с использованием маршрутизатора

Я смотрю на библиотеку маршрутизатора danny vankooten здесь. Это выглядит хорошо (хотя не уверен, как он будет обрабатывать проект от среднего до большого, например, сайт электронной коммерции). Теперь, перейдя к примеру, это отображение

$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 для всех, кто хочет ответить, как использовать указанный маршрутизатор, используя подстановочный знак для соответствия контроллеру/методу.

Ответ 1

Что вы можете сделать, чтобы облегчить ваш файл маршрутизатора, это переместить определение маршрута в файл 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();

Дэнни Ван Кутен также сделал PHP-Router, который имеет встроенную поддержку файлов YAML. (Если вы посмотрите на исходный код, вы увидите, что он использует синтаксический анализатор Symfony, поэтому оба метода очень похожи)

Из документа

Определение маршрута 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();

Ответ 2

в библиотеке нет функции, которая делает что-то вроде того, что вам нужно, но есть альтернативный способ сделать это, - это сохранить эту страницу в базе данных, чтобы у вас было что-то вроде этого ниже

//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));
  }
}

Я надеюсь, что это поможет

Ответ 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');

Ответ 4

Как часть фазы начальной загрузки скажите своим контроллерам отобразить себя на маршрутизаторе:

// bootstrap
$router = new AltoRouter();

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

Каждому контроллеру разрешено создавать все необходимые маршруты.