2013-04-13 131 views
1

在PHP中,klein路由將匹配儘可能多的路由。 我建立的2條路線有衝突。它們是:正則表達式匹配url

$route1: '/websites/[i:websiteId]/users/[i:id]?' 

$route2: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]?' 

這是我想匹配的URL,這是我認爲應該匹配第一個而不是第二,就是:

/api/v1-test/websites/100/users/4 

這兩個產生的正則表達式是:

$regex1: `^/api(?:/(v1|v1-test))/websites(?:/(?P<websiteId>[0-9]++))/users(?:/(?P<id>[0-9]++))?$` 

$regex2: `^/api(?:/(v1|v1-test))/websites(?:/(?P<websiteId>[0-9]++))/users(?:/(?P<filename>[0-9A-Za-z]++))(?:\.(?P<extension>json|csv))?$` 

我的意思是它不匹配,如果沒有'.csv'或'.json'。問題是它匹配兩條路線。對於第二個,結果文件名是'4',擴展名是空白的。

正在發送/api/v1-test/websites/100/users/users.csv,它只能匹配第二條路由。

我只能控制路線,而不是正則表達式或匹配。 謝謝。

回答

0

這裏

(?:\.(?P<extension>json|csv))? 

這一點在你的第二個正則表達式的結束使得它是否匹配有一個文件名,由於?在最後。問號意味着0 or 1 of the previous expression。擺脫這一點,至少,字符串將只有匹配這個正則表達式時,他們有擴展名。

爲了使這一變化,只是從你的第二條路線中刪除問號,像這樣:

$route2: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]' 
+0

我不太喜歡這個當我第一次閱讀時回答。我天真的理解是,說這之後的任何事情都是作爲參數。 –

+0

你說得對嗎?可以用來[標籤子模式](http://www.php.net/manual/en/regexp.reference.subpatterns.php)。但碰巧在PHP正則表達式語法中(Klein路由系統使用的),問號有多種用法。最後 ?在你的路線被解釋爲'0或1'[元字符](http://www.php.net/manual/en/regexp.reference.meta.php)。 – jmeas

+0

事實上,[Klein自述文件](https://github.com/chriso/klein.php#routing)中的最後一個路由示例與您所描述的路徑有非常相似的路由,明確地說它會導致選項文件擴展名。如果你想讓route2需要擴展名,你應該刪除尾部的'?'。 – jmeas

0

的問題是,match_type真的定義...古怪:

$match_types = array(
      'i' => '[0-9]++', 
      'a' => '[0-9A-Za-z]++', 
[...] 

因此,您無法真正捕獲僅對應於[a-zA-Z]的序列...我唯一的選擇是使用3條路線:

$route1: '/websites/[i:websiteId]/users/[i:id]?' 
$route2: '/websites/[i:websiteId]/users/[a:filename]' 
$route3: '/websites/[i:websiteId]/users/[a:filename].[json|csv:extension]' 

並指定了路線2和3相同的動作,那麼你會擁有這樣的:

  • /api/v1-test/websites/100/users/由1
  • /api/v1-test/websites/100/users/4匹配由1
  • /api/v1-test/websites/100/users/test匹配由2
  • 匹配
  • /api/v1-test/websites/100/users/test.csv匹配3

這看起來像你想要的行爲。

Abother(容易)的解決辦法是採取此位的文檔的優勢:

Routes automatically match the entire request URI. 
If you need to match only a part of the request URI 
or use a custom regular expression, use the @ operator.

然後,您可以這樣定義你的路由:

$route1: '@/websites/[0-9]+/users/[0-9]*$' 
$route1: '@/websites/[0-9]+/users/[a-zA-Z]+(\.[a-zA-Z]+)?$' 
+0

哲學上,我更喜歡這個答案。我認爲使用多條路線有潛力。但我仍然需要?因爲所有的參數都來了。所以我不清楚你的改變如何阻止用戶/ 4匹配路由3. –

+0

所以我錯了。 PHP瞭解?在URL中沒有我將它添加到路由中。 –

+0

@BradWhite:實際上,當我再次閱讀我的答案時,我認爲第一種解決方案在所有...用戶/ 4不匹配路由3後,因爲它需要在文件名後面有一個擴展名。然而,用戶/ 4仍然會匹配路線1和2,我想。不過,我很確定第二種解決方案正是您所需要的。 – m4573r