多个路由到同一个 Laravel 资源控制器操作
Posted
技术标签:
【中文标题】多个路由到同一个 Laravel 资源控制器操作【英文标题】:Multiple routes to same Laravel resource controller action 【发布时间】:2014-08-07 12:40:14 【问题描述】:我喜欢在 Laravel 中使用资源控制器,因为它让我想到了数据建模。到目前为止,我已经过关了,但我现在正在开发一个具有公共前端和受保护后端(管理区域)的网站。
我创建了一个添加“admin”前缀的路由组,如下所示:
Route::group(array('before' => 'auth', 'prefix' => 'admin'), function()
Route::resource('article', 'ArticleController');
Route::resource('event', 'EventController');
Route::resource('user', 'UserController');
);
我可以使用默认的 URL 结构访问方法,即 http://example.com/admin/article/1/edit。
但是,我希望在前端使用一个不同的 URL 结构,这不符合资源控制器的期望。
例如,要访问一篇文章,我想使用如下 URL:http://example.com/news/2014/06/17/some-article-slug。如果这篇文章的 ID 为 1,它应该(在后台)转到 /article/1/show。
如何在 Laravel 中实现这一点?在那里,我可以对路线进行某种预处理,以将日期和 slug 与文章 ID 匹配,然后然后将其作为参数传递给我的资源控制器的 show()
方法?
【问题讨论】:
你想出答案了吗?另外,你考虑过路由过滤器吗?? @brianlmerritt 不要以为我解决了我在问题中谈到的 Laravel 4 应用程序,但对于 Laravel 5 应用程序,我已经开始使用路由参数(可能包含斜杠),然后在此基础上找到一个模型,因此“2014/06/17/some-article-slug”可以传递给我的Article
模型中的静态findBySlug()
方法,然后在斜线处拆分它,并找到一个根据日期和 slug 匹配记录。
【参考方案1】:
重新访问这个,我通过使用路由模型绑定和模式解决了它:
$year = '[12][0-9]3';
$month = '0[1-9]|1[012]';
$day = '0[1-9]|[12][0-9]|3[01]';
$slug = '[a-z0-9\-]+';
// Pattern to match date and slug, including spaces
$date_slug = sprintf('(%04d)\/(%02d)\/(%02d)\/(%s)', $year, $month, $day, $slug);
Route::pattern('article_slug', $date_slug);
// Perform the route–model binding
Route::bind('article_slug', function ($slug)
return Article::findByDateAndSlug($date_slug);
);
// The actual route
Route::get('news/article_slug', 'ArticleController@show');
然后根据需要将Article
模型实例注入到我的控制器操作中。
【讨论】:
【参考方案2】:如果 Laravel 4 在路由中支持 (:all)
似乎可以轻松做到,但不幸的是 (:all)
is not supported in Laravel 4。
不过,Laravel 4 允许通过正则表达式检测路由,所以我们可以使用->where('slug', '.*')
。
routes.php:(文件底部)
Route::get('slug', 'ArticleController@showBySlug')->where('slug', '.*');
由于 Laravel 会首先尝试匹配 routes.php 中最顶层的路由,所以我们可以安全地将通配符路由放在 routes.php 的底部,以便只有在所有其他条件都已经评估后才检查它。
ArticleController.php:
class ArticleController extends BaseController
public function showBySlug($slug)
// Slug lookup. I'm assuming the slug is an attribute in the model.
$article_id = Article::where('slug', '=', $slug)->pluck('id');
// This is the last route, throw standard 404 if slug is not found.
if (!$article_id)
App::abort(404);
// Call the controller's show() method with the found id.
return $this->show($article_id);
public function show($id)
// Your resource controller's show() code goes here.
上面的代码假定您将整个 URI 存储为 slug。当然,您始终可以定制 showBySlug() 以支持更高级的 slug 检查。
额外:
你也可以这样做:
Route::get('category/year/slug', 'ArticleController@showBySlug')->where('slug', '.*');
你的 showBySlug() 只会有额外的参数:
public function showBySlug($category, $year, $slug)
// code
显然你可以扩展到月和日,或其他适应。
【讨论】:
谢谢。我希望有一个解决方案,我可以重用我的资源控制器的show()
方法,而不是定义一个新方法。我可以这样做,但我觉得它不“正确”。【参考方案3】:
一个简单的解决方案是为您的要求再创建一条路线,并在那里进行处理以将其链接到主路线。所以,例如:
//routes.php
Route::get('/arical/date/indentifier/slug', array (
'uses' => 'ArticleController@findArticle'
));
//ArticleContoller
public function findArticle($date,$slug)
$article = Article::where('slug','=','something')->first(); //maybe some more processing;
$article_id = $article->id;
/*
Redirect to a new route or load the view accordingly
*/
希望这是有用的。
【讨论】:
谢谢。我希望有一个解决方案,我可以重用我的资源控制器的show()
方法,而不是定义一个新方法。我可以这样做,但我觉得它不“正确”。以上是关于多个路由到同一个 Laravel 资源控制器操作的主要内容,如果未能解决你的问题,请参考以下文章
Laravel 5.7 使用某些命名空间的资源控制器路由名称是啥?