Маршрутизация URL приложения PHP
поэтому я пишу фреймворк, на котором я хочу основать несколько приложений, над которыми я работаю (фреймворк есть, поэтому у меня есть среда для работы, и система, которая позволит мне, например, использовать единый вход)
Я хочу сделать эту структуру, и приложения, которые она имеет, используют архитектуру, ориентированную на ресурсы.
теперь я хочу создать класс маршрутизации URL, который расширяется авторами приложений (и, возможно, также пользователями приложений CMS, но это WAYYYY впереди в будущем) и я пытаюсь найти лучший способ сделать это, глядя на то, как это делают другие приложения.
8 ответов
Я предпочитаю использовать reg ex вместо создания собственного формата, так как это общеизвестно. Я написал небольшой класс, который я использую, который позволяет мне вложить эти таблицы маршрутизации reg ex. Я использую что-то подобное, что было реализовано по наследованию, но оно не нуждалось в наследовании, поэтому я переписал его.
Я делаю 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",
));
}
также вы можете определить любые значения по умолчанию для строки маршрутизации справа. Просто не забудьте документировать они или вы собьете людей с толку. В настоящее время я вызываю индекс, Если вы не включаете имя функции справа. здесь мой текущий код. Вы можете изменить его, чтобы обрабатывать ошибки, как вам нравится, и или действия по умолчанию.
еще одна структура? -- в любом случае...
трюк с маршрутизацией заключается в том, чтобы передать все это вашему контроллеру маршрутизации.
вы, вероятно, захотите использовать что-то похожее на то, что я уже описывал здесь:
http://www.hm2k.com/posts/friendly-urls
второе решение позволяет использовать URL-адреса, похожие на Zend Framework.
использовать список Regexs, чтобы соответствовать, какой объект я должен использовать
^/users/[\w-]+/bookmarks/(.+)/$
^/users/[\w-]+/bookmarks/$
^/users/[\w-]+/$
плюсы: приятно и просто, позволяет мне определить маршруты напрямую Минусы: придется заказывать, а не добавлять новые вещи (очень подвержены ошибкам)
вот, афаик, как это делает Джанго
Я думаю, что многие фреймворки используют комбинацию mod_rewrite Apache и фронтального контроллера. С помощью mod_rewrite вы можете превратить URL-адрес следующим образом: / people / get / 3 в это: индекс.РНР?контроллер=люди & метод=get & id=3. Индекс.php будет реализовывать ваш передний контроллер, который направляет запрос страницы на основе заданных параметров.
как и следовало ожидать, есть много способов сделать это.
например,Тонкие Рамки пример маршрутизации может быть следующее (на основе шаблона ${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 . '\'s 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), но получил двусторонний разговор, поэтому, если ваш клиент не может запустить mod_rewrite (в Apache) или добавить правила перезаписи на своем сервере, он или она все еще может использовать традиционные URL-адреса со строкой запроса.
файл содержит массив, каждый из них, каждый элемент похож на этот пример:
$_FURLTEMPLATES['login'] = array(
'i' => array( // Input - how the router parse an incomming path into query string params
'pattern' => '@Members/Login/?@i',
'matches' => array( 'Application' => 'Members', 'Module' => 'Login' ),
),
'o' => array( // Output - how the router parse a query string into a route
'@Application=Members(&|&)Module=Login/?@' => 'Members/Login/'
)
);
вы также можете использовать более сложные комбинации, такие как:
$_FURLTEMPLATES['article'] = array(
'i' => array(
'pattern' => '@CMS/Articles/([\d]+)/?@i',
'matches' => array( 'Application' => "CMS",
'Module' => 'Articles',
'Sector' => 'showArticle',
'ArticleID' => '' ),
),
'o' => array(
'@Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)@' => 'CMS/Articles/'
)
);
суть, как я думаю, в том, что возможности бесконечны, это просто зависите от того, насколько сложной вы хотите, чтобы ваша структура была и что вы хотите с ней делать.
если это, например, просто предназначен для веб-службы или простой веб - сайт обертка - просто пойти со стилем Slim framework в письменной форме-очень простой и красивый код.
однако, если вы хотите разрабатывать сложные сайты, используя его, я думаю, что regex-это решение.
удачи! :)
вы должны проверить 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);
в Zend в MVC по умолчанию использует структуру типа
/router/controller/action/key1/value1/key2/value2
здесь router
файл роутер (подключенный через mod_rewrite
, controller
от обработчика действия контроллера, который определяется классом, производным от Zend_Controller_Action
и action
ссылается на метод в контроллере с именем actionAction
. Пары ключ/значение могут идти в любом порядке и доступны в метод действия в виде ассоциативного массива.
я использовал что-то подобное в прошлом в своем собственном коде, и поэтому до сих пор это работало довольно хорошо.
попробуйте взглянуть на MVC узор.
Zend Framework использует его, например, но также CakePHP, CodeIgniter,...
Мне лично не нравится модель MVC, но в большинстве случаев она реализована как компонент "View for web".
решение в значительной степени зависит от предпочтений...