Маршрутизация 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".

решение в значительной степени зависит от предпочтений...