11.09.2020
Простой и быстрый роутинг
Все мы (веб-разработчики) иногда пишем какие-то инструменты или да же мини-CMS для мелких нужд. Роутинг в них, не то что головная боль — скорее рутина, на которую при этом не хочется тратить много времени. Открыл для себя интересную библиотеку, создающую простые функции, определения роутов и действий с ними. Создал на ней уже пару проектов, в том числе не только для себя — готов теперь поделиться и с вами.
Скачать (ссылка на офиц. GitHub) в конце статьи будет, а сейчас сразу переходим к настройке
1 2 3 |
RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteRule . index.php [L] |
1 |
try_files $uri /index.php; |
1 2 3 4 5 |
require 'AltoRouter.php'; $router = new AltoRouter(); #Если наше приложение находится в какой-то папке, относительно корня сайта $router->setBasePath('/path/'); |
Отлично, после манипуляций с настройкой веб-сервера, подключением библиотеки, мы готовы начинать. Следите за действиями, двигаемся быстро!
Создаем маршруты:
1 |
$router->map($method,$route,$target,$name); |
- $method — метод, или список методов этого запроса. Поддерживаются GET|POST|PATCH|PUT|DELETE
- $route — шаблон маршрута для сопоставления.
Это может быть обычная строка, один из предопределенных фильтров регулярных выражений или настраиваемое регулярное выражение. Пользовательские регулярные выражения должны начинаться с @. - $target — это может быть что угодно, анонимная функция, или функция из класса.
- $name — для обратной маршрутизации, укажите параметр имени, чтобы вы могли сгенерировать URL-адреса, используя этот маршрут.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// Вызов главной страницы через анонимную функцию $router->map( 'GET', '/', function() { require __DIR__ . '/views/home.php'; }); // Вызов контроллера пользователей (класс UserController, функция showDetails), //с передачей ID из адреса //Учтите, файл с классом должен быть уже подключен, класс должен успешно создаваться $router->map( 'GET', '/users/[i:id]/', 'UserController#showDetails' ); // Вызов функции по имени функции $router->map( 'POST', '/contact/', 'handleContactForm' ); //Массовое добавление роутов $router->addRoutes(array( array('PATCH','/users/[i:id]', 'users#update', 'update_user'), array('DELETE','/users/[i:id]', 'users#delete', 'delete_user') )); |
Но что, eсли нам надо проверить какие-то кастомные данные, например сделать роутинг по датам, /store/22.05.2020/ и /store/23.05.2020/ и т.д. ?! Создадим новый тип проверки валидации, и сделаем роутинг к нему!
1 2 3 4 5 |
//Создает новый тип данных в строке запроса \d{2}\.\d{2}\.\d{4} $router->addMatchTypes(array('DATE' => '\d{2}\.\d{2}\.\d{4}')); //Выполняет роутинг по созданному правилу, получая как параметр данные $router->map('GET', '/fm/[DATE:uid]', "FileManager@getFileForDate", 'fmget'); |
Все это хорошо. Мы создаем роуты, быстро и просто, да же с своими снипетами регулярных выражений. Но когда и как они начнут обрабатываться? Прямо сейчас!
1 |
$match = $router->match(); |
Если нам вернут массив из 3 элементов, то все хорошо, маршрут найден. Если нет — пора отдать 404, запрошенного адреса не существует! В классе нет как таковой обработки запросов. Сейчас он просто определил маршрут и подготовил данные для дальнейшего использования. На выходе, в $match, мы получили:
- target — объект который был указан в $target роута. Если это был класс с функцией — вернет экземпляр класса, если анонимная функция — результат ее выполнения (если он был), в других случаях просто вернет то что там было указано
- params — список параметров найденных по регулярным выражениям и снипетам.
- name — указанное имя роута, если оно было.
Дальше мы вольны делать с всем этим что угодно. Покажу для примера свою, вроде как универсальную обработку (для себя так решил). Сразу оговорюсь, я не хочу подключать все классы контроллеров, что бы он сам создавал и вызывал классы. И все контроллеры храню в одной папке. А в качестве $target указываю array(‘ControllerName’,’functionName’).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
$router->map('GET', '/users', array("User", "userLists"), 'userLists'); $router->map('GET|POST', '/users/edit/[i:id]', array("User", "userEdit"), 'userEdit'); $router->map('POST', '/users/add', array("User", "userAdd"), 'userAdd'); $router->map('POST', '/users/remove/[i:id]', array("User", "userRemove"), 'userRemove'); $router->map('POST', '/users/checklogin/[a:login]', array("User", "loginCheck"), 'userchecklogin'); $match = $router->match();//вызываем просчет роутинга if (is_array($match)) {//проверяем, существует роут или нет /* Вот тут отличное место, что бы вписать например авторизацию, Если она нужна для части страниц, или например части модулей */ if (is_callable($match['target'])) //Если это имя функции - выполняем с параметрами ее call_user_func_array($match['target'], $match['params']); else if (is_array($match['target']) && file_exists($adminDir."/Controllers/".$match['target'][0].'.php')) { //Если это массив из 2 элементов, и есть файл контроллера с именем 0 элемента require_once $adminDir . "/Controllers/" . $match['target'][0] . '.php'; $nameCl = $match['target'][0]; $nameFunc = $match['target'][1]; $controller = new $nameCl(); $controller->$nameFunc($match['params']); } } else { //показываем 404 если ничего не нашли header($_SERVER["SERVER_PROTOCOL"] . ' 404 Not Found'); } |
Вы можете взять мой метод, или создать свою логику, библиотека предоставляет лишь инструмент, а не занимается стандартизацией логики работы, наоборот давая максимальную гибкость.
Теперь осталась мелочь — вывод в интерфейс адресов по именам роутов (помните в начале обещали), и отладка.
1 2 |
$route->getRoutes(); //Вернет массив всех существующих роутов $route->generate('getPage', ['id'=>55]); //вернет полный URL для роута, с параметром ID |
Вот и все, роуты перестают занимать голову, вся маршрутизация делается без отвлекания от логики самого приложения, задача библиотеки выполнена на 146%.
- Размер: 10,3 KB
- Скачиваний: 3