web-dev-qa-db-ja.com

PHPアプリケーションのURLルーティング

ですから、私は自分が取り組んでいるいくつかのアプリのベースにしたいフレームワークを書いています(フレームワークはそこにあるので、作業する環境があり、たとえば、単一のアプリを使用できるシステムがあります入社する)

このフレームワークと、それが持つアプリでリソース指向のアーキテクチャを使用したいと思います。

今、私はAPPライター(そしておそらくCMSアプリユ​​ーザーも)によって拡張可能なURLルーティングクラスを作成したいと思っていますが、それは将来的にはWAYYYYです)そして私はそれを行うための最良の方法を見てみようとしています他のアプリがそれを行う方法。

18
Mez

常識であるため、独自のフォーマットを作成するよりも正規表現を使用する方が好きです。これらの正規表現ルーティングテーブルをネストできるようにする、使用する小さなクラスを作成しました。以前は継承によって実装されたものと似たものを使用していましたが、継承は必要なかったので書き直しました。

キーに対して正規表現を実行し、自分の制御文字列にマップします。以下の例を見てください。 _/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",
));
_

エラーを抑え、単純さを高めるために、テーブルを細分化することができます。このようにして、ルーティングテーブルをそれが制御するクラスに配置できます。上記の例をとると、3つのスレッド呼び出しを1つに組み合わせることができます。

_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",
    ));
}
_

また、右側のルーティング文字列に必要なデフォルトを定義することもできます。それらを文書化することを忘れないでください。そうしないと、人々を混乱させることになります。右側に関数名が含まれていない場合は、現在インデックスを呼び出しています。 ここ は私の現在のコードです。エラーやデフォルトのアクションを処理するように変更することをお勧めします。

14
gradbot

Regexのリストを使用して、使用するオブジェクトと一致させます

例えば

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

長所:素晴らしくシンプルで、ルートを直接定義できます短所:注文する必要があり、新しいものを簡単に追加できない(エラーが発生しやすい)

これは、afaik、どのようにDjango

1
Mez

ご想像のとおり、それを行う方法はたくさんあります。

たとえば、 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など)、最初のパラメーターとしてルートを取得し、2番目のパラメーターとしてコールバックを取得します。

ルートはトークンを取得できます。これは、すべてのルーティングコントローラーと同様に、実行時に一部のデータ(メンバー名、記事ID、組織の場所名など)に基づいて変更される「変数」です。

個人的にはこの方法が好きですが、高度なフレームワークには十分な柔軟性がないと思います。

私は現在ZFとYiiで作業しているので、私が働いている会社のフレームワークの一部として作成したルーターの例があります。

ルートエンジンは正規表現(@gradbotのものと同様)に基づいていますが、双方向の会話があります。そのため、クライアントが(Apacheで)mod_rewriteを実行できない場合、またはサーバーに書き換えルールを追加できない場合は、クエリ文字列で従来の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'
    )
);

肝心なのは、私が思うに、可能性は無限であるということです。それは、フレームワークをどれだけ複雑にしたいのか、そしてそれを使って何をしたいのかによって異なります。

たとえば、Webサービスまたは単純なWebサイトラッパーを目的としている場合は、Slimフレームワークの記述スタイルに合わせてください。非常に簡単で見栄えの良いコードです。

ただし、それを使用して複雑なサイトを開発したい場合は、正規表現が解決策だと思います。

幸運を! :)

0
Gindi Bar Yahav

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
c9s

多くのフレームワークは、Apacheのmod_rewriteとフロントコントローラーの組み合わせを使用していると思います。 mod_rewriteを使用すると、次のようなURLを使用できます:/ people/get/3:index.php?controller = people&method = get&id = 3。 Index.phpは、指定されたパラメーターに基づいてページリクエストをルーティングするフロントコントローラーを実装します。

0
Unlabeled Meat