PHP Application URL Routing - PullRequest
       15

PHP Application URL Routing

17 голосов
/ 24 сентября 2008

Итак, я пишу фреймворк, на котором я хочу основать несколько приложений, над которыми я работаю (фреймворк есть, поэтому у меня есть среда для работы и система, которая позволит мне, например, использовать единый вход)

Я хочу создать эту платформу, и приложения, которые она использует, используют ресурсно-ориентированную архитектуру.

Теперь я хочу создать класс маршрутизации URL-адресов, который может расширяться авторами приложений (и, возможно, также пользователями приложений CMS, но это WAYYYY впереди в будущем), и я пытаюсь найти лучший способ сделать это глядя на то, как это делают другие приложения.

Ответы [ 8 ]

13 голосов
/ 24 сентября 2008

Я предпочитаю использовать reg ex вместо создания своего собственного формата, так как это общеизвестно. Я написал небольшой класс, который я использую, который позволяет мне вложить эти таблицы маршрутизации ex 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",
    ));
}

Также вы можете определить любые значения по умолчанию для вашей строки маршрутизации справа. Только не забудьте документировать их, иначе вы запутаете людей. В настоящее время я вызываю index, если вы не указали имя функции справа. Здесь - мой текущий код. Возможно, вы захотите изменить его, чтобы обрабатывать ошибки так, как вам нравится, или действия по умолчанию.

2 голосов
/ 17 апреля 2009

Еще одна структура? - все равно ...

Хитрость в том, что с маршрутизацией нужно передать все это вашему контроллеру маршрутизации.

Возможно, вы захотите использовать что-то похожее на то, что я описал здесь:

http://www.hm2k.com/posts/friendly-urls

Второе решение позволяет использовать URL-адреса, аналогичные Zend Framework.

1 голос
/ 24 сентября 2008

Используйте список регулярных выражений, чтобы выбрать, какой объект я должен использовать

Например

^/users/[\w-]+/bookmarks/(.+)/$
^/users/[\w-]+/bookmarks/$
^/users/[\w-]+/$

Плюсы: приятно и просто, позволяет мне определять маршруты напрямую Минусы: придется заказывать, что не позволяет легко добавлять новые вещи (очень подвержено ошибкам) ​​

Это, афаик, как Джанго это делает

0 голосов
/ 28 января 2014

Вы должны проверить 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);
0 голосов
/ 01 июля 2012

Как и следовало ожидать, есть много способов сделать это.

Например, в 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 . '\'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(&|&amp;)Module=Login/?@' => 'Members/Login/'
    )
);

Вы также можете использовать более сложные комбинации, такие как:

$_FURLTEMPLATES['article']  =   array(
    'i' => array(
        'pattern' => '@CMS/Articles/([\d]+)/?@i',
        'matches' => array( 'Application' => "CMS",
            'Module' => 'Articles',
            'Sector' => 'showArticle',
            'ArticleID' => '$1' ),
    ),
    'o' => array(
     '@Application=CMS(&|&amp;)Module=Articles(&|&amp;)Sector=showArticle(&|&amp;)ArticleID=([\d]+)@' => 'CMS/Articles/$4'
    )
);

Суть, как я думаю, в том, что возможности безграничны, все зависит от того, насколько сложным вы хотите, чтобы ваша структура была, и что вы хотите с ней делать.

Если, например, это просто веб-служба или простая оболочка для веб-сайта - просто используйте стиль написания Slim Framework - очень простой и красивый код.

Однако, если вы хотите разрабатывать сложные сайты с использованием этого, я думаю, что регулярное выражение является решением.

Удачи! :)

0 голосов
/ 24 сентября 2008

Zend MVC фреймворк по умолчанию использует такую ​​структуру, как

/router/controller/action/key1/value1/key2/value2

, где router - это файл маршрутизатора (отображается через mod_rewrite, controller из обработчика действий контроллера, который определяется классом, производным от Zend_Controller_Action, и action ссылается на метод в контроллере, named actionAction. Пары ключ / значение могут идти в любом порядке и доступны методу действия в виде ассоциативного массива.

Я использовал нечто подобное в прошлом в своем собственном коде, и до сих пор это работало довольно хорошо.

0 голосов
/ 24 сентября 2008

Я думаю, что многие фреймворки используют комбинацию Apache mod_rewrite и фронт-контроллера. С помощью mod_rewrite вы можете превратить URL-адрес следующим образом: / people / get / 3 в следующий: index.php? контроллер = люди и метод = получить & ID = 3. Index.php реализует ваш фронт-контроллер, который направляет запрос страницы на основе заданных параметров.

0 голосов
/ 24 сентября 2008

Попробуйте взглянуть на MVC паттерн.
Zend Framework использует его, например, но также CakePHP, CodeIgniter, ...

Лично мне не нравится модель MVC, но большую часть времени она реализована как компонент "Просмотр для Интернета".

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

...