Вопрос

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

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

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

Это было полезно?

Решение

Я предпочитаю использовать 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",
    ));
}

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

Другие советы

Еще один фреймворк?-- в любом случае...

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

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

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

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

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

Например

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

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

Вот, afaik, как Django это делает

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

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

Например, в Тонкий Каркас , примером механизма маршрутизации может быть following (основанный на шаблоне ${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' => '$1' ),
    ),
    'o' => array(
     '@Application=CMS(&|&)Module=Articles(&|&)Sector=showArticle(&|&)ArticleID=([\d]+)@' => 'CMS/Articles/$4'
    )
);

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

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

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

Удачи вам!:)

Тебе стоит проверить 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);

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top