2008-09-24 81 views
15

因此,我正在編寫一個框架,我要基於我正在開發的幾個應用程序(該框架在那裏,因此我有一個可以使用的環境,以及一個可讓我,例如,使用單一登錄)PHP應用程序URL路由

我想製作這個框架,它的應用程序使用面向資源的架構。

現在,我想創建一個可由APP編寫器擴展的URL路由類(也可能由CMS應用程序用戶進行擴展,但未來將提前推出),並試圖找出最佳做法它通過查看其他應用程序如何執行它。

回答

12

我更喜歡使用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", 
    )); 
} 

此外,您可以在右側爲您的路由字符串定義任何默認值。只是不要忘記記錄它們,否則你會迷惑人。如果您沒有在右側包含函數名,我現在正在調用索引。 Here是我當前的代碼。您可能需要將其更改爲處理錯誤的方式和/或默認操作。

+0

第二個例子非常符合Ive實際上正在考慮的事情......(RoR風格) - 我將通過你的代碼來看看。 – Mez 2008-09-25 07:08:06

1

使用Regexs列表匹配,我應該使用

例如

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

哪個對象優點:尼斯和簡單,讓我直接定義路線 缺點:必須是有序的,不使其易於在(非常容易出錯)添加新的東西

這一點,據我所知,Django是如何做它

-4

嘗試採取看看MVC模式。
Zend Framework使用它,但也CakePHP,CodeIgniter,...

我個人不喜歡MVC模型,但它的大部分時間實現爲「視圖爲web」組件。

的決定非常依賴於偏好...

+0

我使用的是MVC的東西。我正在談論技術方面或URL路由。這不是我的問題的答案 – Mez 2008-09-24 15:34:29

0

我想了很多框架使用Apache的mod_rewrite和前端控制器的組合。使用mod_rewrite,您可以將如下所示的URL變爲:/ people/get/3: index.php?controller = people & method = get & id = 3。 Index.php將實現您的前端控制器,它根據給定的參數來路由頁面請求。

+0

因此,顯然忽略你的非ROA網址,它與我上面的答案一樣,但使用mod_rewrite與特定的規則,並通過特定的paraameters,而不是通過代碼「路由」? – Mez 2008-09-24 15:40:18

-1

默認Zend的MVC框架使用像

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

其中router是路由器文件(通過mod_rewrite映射的結構,controller是從由從Zend_Controller_Actionaction派生的類中定義的控制器的動作的處理程序引用了控制器中的一個方法,名爲actionAction。鍵/值對可以按任何順序排列,並可作爲關聯數組的行爲方法使用。 t在我自己的代碼中,到目前爲止它的工作還算不錯。

+0

操作不適用於ROA系統,僅適用於RPC式系統 – Mez 2008-09-24 15:36:28

+0

您是完全正確的......我誤解了這個問題。那和ROA把我扔了。我一直稱它爲REST。 – 2008-09-24 20:16:08

+0

雖然這不是RESTFul。只是爲了記錄。 – DanMan 2012-06-25 09:57:59

2

又一個框架? - 無論如何...

路由的訣竅是把它傳遞給你的路由控制器。

你可能想使用類似的東西,我在這裏記載:

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

第二個解決方案,您可以使用類似Zend框架的URL。

0

正如您所料,有很多方法可以做到這一點。

例如,在Slim Framework,路由引擎的一個實例可以是folllowing(基於圖案${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)獲取每個請求方法的方法(例如獲取,發佈,放置,刪除等),並獲取一個路由作爲第一個參數,並將回調作爲第二個參數。

路由可以獲取令牌 - 這是「變量」,它將在運行時基於某些數據(例如成員名稱,文章ID,組織位置名稱或其他 - 就像在每個路由控制器中一樣)發生更改。

就我個人而言,我喜歡這種方式,但我認爲它對於高級框架來說不夠靈活。

由於我與ZF和目前的Yii工作,我有我作爲一個企業的框架的一部分,創造了一個路由器,我工作的一個例子:

路由引擎是基於在正則表達式(類似於@ gradbot的一個),但得到了雙向對話,所以如果你的客戶端不能運行mod_rewrite(在Apache中)或在他或她的服務器上添加重寫規則,他或她仍然可以使用傳統包含查詢字符串的網址。

該文件包含一個陣列,每個的話,每個項目類似於該實施例中:

$_FURLTEMPLATES['login'] = array(
    'i' => array(// Input - how the router parse an incomming path into query string params 
     'pattern' => '@Members/Login/[email protected]', 
     'matches' => array('Application' => 'Members', 'Module' => 'Login'), 
    ), 
    'o' => array(// Output - how the router parse a query string into a route 
     '@Application=Members(&|&)Module=Login/[email protected]' => 'Members/Login/' 
    ) 
); 

也可以使用更復雜的組合,諸如:

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

底線,正如我認爲的那樣,可能性是無止境的,它只取決於你希望你的框架有多複雜,以及你希望如何使用它。

如果是,例如,只是打算成爲一個Web服務或簡單的網站包裝 - 只需與Slim框架的寫作風格 - 非常簡單和漂亮的代碼。

但是,如果你想開發複雜的網站使用它,我認爲正則表達式是解決方案。

祝你好運! :)

0

你應該看看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);