Маршрутизация URL-адресов PHP-приложений
Итак, я пишу фреймворк, на котором я хочу основать несколько приложений, над которыми я работаю (инфраструктура там, поэтому у меня есть среда для работы, и система, которая позволит мне, например, используйте единый вход)
Я хочу создать эту фреймворк и приложения, в которых она использует ресурсо-ориентированную архитектуру.
Теперь я хочу создать класс маршрутизации URL-адресов, который может быть расшифрован авторами APP (и, возможно, также пользователями CMS App, но этот WAYYYY впереди в будущем), и я пытаюсь найти лучший способ сделать это посмотрев, как это делают другие приложения.
Ответы
Ответ 1
Я предпочитаю использовать reg ex для создания своего собственного формата, поскольку это общеизвестно. Я написал небольшой класс, который я использую, что позволяет мне вставлять эти таблицы reg ex routing. Я использую нечто похожее, которое было реализовано наследованием, но оно не нуждалось в наследовании, поэтому я переписал его.
Я делаю reg ex на ключе и сопоставляю свою собственную контрольную строку. Возьмите приведенный ниже пример. Я посещаю /api/related/joe
, и мой класс маршрутизатора создает новый объект ApiController
и вызывает его метод relatedDocuments(array('tags' => 'joe'));
// the 12 strips the subdirectory my app is running in
$index = urldecode(substr($_SERVER["REQUEST_URI"], 12));
Route::process($index, array(
"#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags",
"#^thread/(.*)/post$#Di" => "ThreadController/post/title",
"#^thread/(.*)/reply$#Di" => "ThreadController/reply/title",
"#^thread/(.*)$#Di" => "ThreadController/thread/title",
"#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags",
"#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id",
"#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id",
"#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle",
"#^$#Di" => "HomeController",
));
Чтобы сохранить ошибки и простоту, вы можете разделить таблицу. Таким образом вы можете поместить таблицу маршрутизации в класс, который он контролирует. Взяв приведенный выше пример, вы можете объединить три потока вызовов в один.
Route::process($index, array(
"#^api/related/(.*)$#Di" => "ApiController/relatedDocuments/tags",
"#^thread/(.*)$#Di" => "ThreadController/route/uri",
"#^ajax/tag/(.*)/(.*)$#Di" => "TagController/add/id/tags",
"#^ajax/reply/(.*)/post$#Di"=> "ThreadController/ajaxPost/id",
"#^ajax/reply/(.*)$#Di" => "ArticleController/newReply/id",
"#^ajax/toggle/(.*)$#Di" => "ApiController/toggle/toggle",
"#^$#Di" => "HomeController",
));
Затем вы определяете ThreadController:: route таким образом.
function route($args) {
Route::process($args['uri'], array(
"#^(.*)/post$#Di" => "ThreadController/post/title",
"#^(.*)/reply$#Di" => "ThreadController/reply/title",
"#^(.*)$#Di" => "ThreadController/thread/title",
));
}
Также вы можете определить, какие значения по умолчанию вы хотите для строки маршрутизации справа. Просто не забудьте документировать их или вы будете путать людей. В настоящее время я вызываю индекс, если вы не включаете имя функции справа. Здесь мой текущий код. Вы можете изменить его, чтобы обрабатывать ошибки, как вам нравится, и/или действия по умолчанию.
Ответ 2
Еще одна структура? - в любом случае...
Трюк с маршрутизацией - передать все его контроллеру маршрутизации.
Возможно, вы захотите использовать что-то похожее на то, что я документировал здесь:
http://www.hm2k.com/posts/friendly-urls
Второе решение позволяет использовать URL-адреса, похожие на Zend Framework.
Ответ 3
Используйте список регулярных выражений для соответствия тому, с каким объектом я должен пользоваться
Например
^/users/[\w-]+/bookmarks/(.+)/$
^/users/[\w-]+/bookmarks/$
^/users/[\w-]+/$
Плюсы: красиво и просто, позволяет мне определять маршруты напрямую
Минусы: нужно было бы заказать, не позволяя легко добавлять новые вещи (очень подверженные ошибкам)
Это, afaik, как Django делает это
Ответ 4
Я думаю, что многие фреймворки используют комбинацию Apache mod_rewrite и фронтального контроллера. С mod_rewrite вы можете повернуть URL-адрес следующим образом:/people/get/3:
Index.php? = Контроллер люди & метод = получить & ID = 3. Index.php реализует ваш фронт-контроллер, который направляет запрос страницы на основании заданных параметров.
Ответ 5
Как и следовало ожидать, есть много способов сделать это.
Например, в Slim Framework пример механизма маршрутизации может быть следующим (на основе шаблона ${OBJECT}->${REQUEST METHOD}(${PATTERM}, ${CALLBACK})
):
$app->get("/Home", function() {
print('Welcome to the home page');
}
$app->get('/Profile/:memberName', function($memberName) {
print( 'I\'m viewing ' . $memberName . '\ profile.' );
}
$app->post('/ContactUs', function() {
print( 'This action will be fired only if a POST request will occure');
}
Итак, инициализированный экземпляр ($app
) получает метод для метода запроса (например, get, post, put, delete и т.д.) и получает маршрут в качестве первого параметра и обратного вызова как второго.
Маршрут может получить токены, которые являются "переменными", которые будут меняться во время выполнения на основе некоторых данных (таких как имя участника, идентификатор статьи, название местоположения организации или что-то еще - вы знаете, как и в каждом контроллере маршрутизации).
Лично мне нравится этот способ, но я не думаю, что он будет достаточно гибким для расширенной структуры.
Поскольку я работаю в настоящее время с ZF и Yii, у меня есть пример маршрутизатора, который я создал как часть структуры для компании, над которой я работаю:
Механизм маршрутизации основан на регулярном выражении (аналогично @gradbot one), но получил двухсторонний разговор, поэтому, если ваш клиент не может запустить mod_rewrite (в Apache) или добавить правила перезаписи на свой сервер, он или она все еще может использовать традиционные URL-адреса с строкой запроса.
Файл содержит массив, каждый из которых, каждый элемент аналогичен этому примеру:
$_FURLTEMPLATES['login'] = array(
'i' => array( // Input - how the router parse an incomming path into query string params
'pattern' => '@Members/Login/[email protected]',
'matches' => array( 'Application' => 'Members', 'Module' => 'Login' ),
),
'o' => array( // Output - how the router parse a query string into a route
'@Application=Members(&|&)Module=Login/[email protected]' => 'Members/Login/'
)
);
Вы также можете использовать более сложные комбинации, такие как:
$_FURLTEMPLATES['article'] = array(
'i' => array(
'pattern' => '@CMS/Articles/([\d]+)/[email protected]',
'matches' => array( 'Application' => "CMS",
'Module' => 'Articles',
'Sector' => 'showArticle',
'ArticleID' => '$1' ),
),
'o' => array(
'@Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)@' => 'CMS/Articles/$4'
)
);
Суть, как я думаю, в том, что возможности бесконечны, это зависит от того, насколько сложна ваша структура и что вы хотите с ней делать.
Если это, например, просто предназначено для веб-службы или простой веб-обложки - просто перейдите в Slim framework для написания - очень простой и красивый код.
Однако, если вы хотите разработать сложные сайты, используя его, я думаю, что регулярное выражение является решением.
Удачи!:)
Ответ 6
Вы должны проверить Pux https://github.com/c9s/Pux
Вот краткое описание
<?php
require 'vendor/autoload.php'; // use PCRE patterns you need Pux\PatternCompiler class.
use Pux\Executor;
class ProductController {
public function listAction() {
return 'product list';
}
public function itemAction($id) {
return "product $id";
}
}
$mux = new Pux\Mux;
$mux->any('/product', ['ProductController','listAction']);
$mux->get('/product/:id', ['ProductController','itemAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$mux->post('/product/:id', ['ProductController','updateAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$mux->delete('/product/:id', ['ProductController','deleteAction'] , [
'require' => [ 'id' => '\d+', ],
'default' => [ 'id' => '1', ]
]);
$route = $mux->dispatch('/product/1');
Executor::execute($route);
Ответ 7
Структура Zend MVC по умолчанию использует структуру типа
/router/controller/action/key1/value1/key2/value2
где router
- это файл маршрутизатора (отображается через mod_rewrite
, controller
) из обработчика действий контроллера, который определяется классом, который происходит от Zend_Controller_Action
и action
, ссылается на метод в контроллере, named actionAction
. Пара ключей/значений может идти в любом порядке и доступна для действия в качестве ассоциативного массива.
В прошлом я использовал что-то подобное в своем собственном коде, и до сих пор он работал достаточно хорошо.
Ответ 8
Попробуйте взглянуть на шаблон MVC.
Zend Framework использует его, например, но также CakePHP, CodeIgniter,...
Мне лично не нравится модель MVC, но она большую часть времени реализована как компонент "Просмотр для Интернета".
Решение в значительной степени зависит от предпочтения...