假设我有这个动作:
public function index_by_date($year = NULL, $month = NULL, $day = NULL) {
if($year && $month && $day) {
//Posts of day
}
elseif($year && $month) {
//Posts of month
}
elseif($year) {
//Posts of year
}
else {
//Exception...
}
}
这显示了一天的帖子(06/11/2016的所有帖子):
mysite.com/posts/2016/06/11
这显示整个月的帖子(2016年6月的所有帖子):
mysite.com/posts/2016/06
这显示了一整年的帖子(2016年的所有帖子):
mysite.com/posts/2016
我认为这很清楚。
现在我想为所有这些案例写一条路线。然后,第二个和第三个参数应该是可选的。
我尝试过类似的东西,但这不起作用:
$routes->connect('/posts/:year/:month/:day',
['controller' => 'Posts', 'action' => 'index_by_date'],
[
'year' => '[12][0-9]{3}',
'month' => '(0[1-9]|1[012])?',
'day' => '(0[1-9]|[12][0-9]|3[01])?',
'pass' => ['year', 'month', 'day']
]
);
怎么办?
修改 现在,这是我能做的最好的事情:
路线:
$routes->connect('/posts/:date',
['controller' => 'Posts', 'action' => 'index_by_date'],
[
'date' => '\d{4}(\/\d{2}(\/\d{2})?)?',
'pass' => ['date']
]
);
动作:
public function index_by_date($date = NULL) {
list($year, $month, $day) = array_merge(explode('/', $date), [NULL, NULL, NULL]);
if($year && $month && $day) {
//Posts of day
}
elseif($year && $month) {
//Posts of month
}
elseif($year) {
//Posts of year
}
else {
//Exception...
}
}
有更好的方法吗?
答案 0 :(得分:1)
在CakePHP 3中,您可以将'_name'选项添加到$ routes-> connect()并分隔三个不同的路由。
完整日期,routes.php:
$routes->connect('/posts/:year/:month/:day',
['controller' => 'Posts', 'action' => 'index_by_date'],
[
'year' => '[12][0-9]{3}',
'month' => '(0[1-9]|1[012])?',
'day' => '(0[1-9]|[12][0-9]|3[01])?',
'pass' => ['year', 'month', 'day'],
'_name' => 'postsFull'
]
);
用法(通话中):
['_name' => 'postsFull', 'year' => '2016', 'month' => '06', 'day' => '11']
每年的月份,routes.php:
$routes->connect('/posts/:year/:month',
['controller' => 'Posts', 'action' => 'index_by_date'],
[
'year' => '[12][0-9]{3}',
'month' => '(0[1-9]|1[012])?',
'pass' => ['year', 'month'],
'_name' => 'postsYearMonth'
]
);
用法(通话中):
['_name' => 'postsYearMonth', 'year' => '2016', 'month' => '06']
仅一年,routes.php:
$routes->connect('/posts/:year',
['controller' => 'Posts', 'action' => 'index_by_date'],
[
'year' => '[12][0-9]{3}',
'pass' => ['year'],
'_name' => 'postsYear'
]
);
用法(通话中):
['_name' => 'postsYear', 'year' => '2016']
希望对您有帮助。
答案 1 :(得分:0)
最好放弃将这个定义为具有单独路由元素的单一路由的想法,路由编译器/匹配器既不支持也不支持,也不支持反向路由。
虽然您可以创建支持此功能的自定义路由类,但您必须完全重新实现路由编译,并且实现反向路由支持可能同样有趣 - 我个人认为这不值得麻烦。< / p>
所以要么写多个路由,这是我最有可能做的,要么像你在这里一样使用参数解析解决方案。
当选择后者时,最好在自定义路线类中完成,以使事情更加干燥。但是,在构建URL时,您仍需要将日期部分作为单个字符串传递,除非您还实现了一些自定义匹配,例如检查year
,month
,day
个密钥存在,并构建一个新的URL数组以匹配。
我现在有一点空闲时间,这样的解析/匹配通常很有趣,所以这里有一个快速的&amp;肮脏的例子:
<?php
namespace App\Routing\Route;
use Cake\Routing\Route\Route;
class CompactDateRoute extends Route
{
public function parse($url)
{
$params = parent::parse($url);
if (!$params) {
return false;
}
$params['pass'] = explode('/', $params['pass'][0]) + [null, null, null];
return $params;
}
public function match(array $url, array $context = [])
{
$dateParts = [];
foreach (['year', 'month', 'day'] as $key) {
if (!isset($url[$key])) {
break;
}
$dateParts[] = $url[$key];
unset($url[$key]);
}
if ($dateParts) {
$date = implode('/', $dateParts);
return parent::match($url + compact('date'), $context);
}
return false;
}
}
解析部分应该是非常自我解释的,它只是将单个日期字符串解析为单独的参数,然后将其作为单独的参数传递给您的控制器操作。请注意+
而不是array_merge()
的使用,后者会追加 null
值!
匹配部分也不过分复杂,它只是检查URL数组中的日期部分键,从中构建一个紧凑的日期值(year/month?/day?
),它可以匹配您的路线,并与之匹配,即从像
[
'controller' => 'Posts',
'action' => 'index_by_date',
'year' => '2014',
'month' => '12',
'day' => '04'
]
基本上与
相等[
'controller' => 'Posts',
'action' => 'index_by_date',
'date' => '2014/12/04'
]
然而,所有这一切,只是因为能够用一条路线来定义它?再说一次,我不确定这是值得的麻烦。