【问题标题】:Multiple routes to same Laravel resource controller action多个路由到同一个 Laravel 资源控制器操作
【发布时间】: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 匹配记录。

标签: laravel routing


【解决方案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() 方法,而不是定义一个新方法。我可以这样做,但我觉得它不“正确”。
    猜你喜欢
    • 2018-02-18
    • 1970-01-01
    • 1970-01-01
    • 2018-04-16
    • 1970-01-01
    • 1970-01-01
    • 2013-06-04
    • 2014-10-08
    • 1970-01-01
    相关资源
    最近更新 更多