2013-04-13 87 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