Laravel 5 应用中的动态路由

19

我希望有人可以帮助我处理具有多个段的URL的动态路由。我已经在网上搜索了一些内容,但是没有找到能够帮助我解决特定情况的东西。

一些背景信息......几年前,我开发了一个基于CodeIgniter构建的CMS包,用于客户自定义网站。此CMS包具有几个模块(页面、博客、日历、询问等)。对于页面模块,我将路由缓存到“自定义路由”配置文件中,该文件将页面的完整路由(包括父级、祖先等)与页面的ID关联起来。这样做是为了避免查找要显示的页面时需要执行数据库查询。

目前,我正在使用Laravel(5.1)重新构建此CMS包[同时学习Laravel]。在开始新版本的页面模块之前,我需要解决路由问题。

我知道我可以做类似于......

// routes.php
Route::get('{slug}', ['uses' => 'PageController@view']);

// PageController.php
class PageController extends Controller
{
    public function view($slug)
    {
        // do a query to get the page by the slug
        // display the view
    }
}
如果我不允许嵌套页面,那么这将起作用,但是我允许。我仅根据父级强制唯一性的slug。因此,可能会有多个具有fargo slug的页面...
  • locations/fargo
  • staff/fargo
与我使用CodeIgniter构建的包一样,我希望能够避免额外的数据库查找以找到要显示的正确页面。
我的初始想法是创建一个配置文件,其中包含旧版系统所做的动态路由。路由仅在特定时间更改(在创建页面、修改slug或更改父级时),因此“缓存”它们非常好。但是,我还是Laravel的新手,所以不确定该如何处理这种情况。
我确实设法找出以下路由可行。但是,这是设置这个最好的方法吗?
Route::get('about/foobar', function(){
    return App::make('\App\Http\Controllers\PageController')->callAction('view', [123]);
});

Route::get('foobar', function(){
    return App::make('\App\Http\Controllers\PageController')->callAction('view', [345]);
});
基本上,当创建页面时(或更改slug或parent时),我想将特定路由绑定到特定页面ID。
我是不是过于复杂化了?
非常感谢任何有关此事的帮助或指导。
谢谢!

我是不是把事情想得太复杂了?在我看来,是的。此外,这些路由看起来很静态,如果您不允许任何占位符来代替ID,则没有动态性。每个路由只绑定到一个特定的ID。 - The Alpha
根据我的计划,我认为没有办法使用动态路由来查找正确的页面,而不需要进行额外的数据库查询。我会在其他模块(如博客)中使用动态路由,但对于常规页面,我认为这种方法行不通。 - Becky
2个回答

47

我处理这个问题的方法是使用两个路由,一个用于首页(通常包含更复杂的逻辑,例如新闻、精选文章、横幅等),另一个用于任何其他页面。

路由

// Home page
Route::get('/', [
    'as'      => 'home',
    'uses'    => 'PageController@index'
]);

// Catch all page controller (place at the very bottom)
Route::get('{slug}', [
    'uses' => 'PageController@getPage' 
])->where('slug', '([A-Za-z0-9\-\/]+)');
注意上面的重要部分是路由结尾处链接的->where()方法。这允许您为路由参数声明正则表达式模式匹配。在本例中,我允许字母数字字符、连字符和正斜杠用于{slug}参数。这将匹配像test-pagetest-page/sub-pageanother-page/sub-page这样的主题。

PageController方法

public function index()
{
    $page = Page::where('route', '/')->where('active', 1)->first();

    return view($page->template)
        ->with('page', $page);
}

public function getPage($slug = null)
{
    $page = Page::where('route', $slug)->where('active', 1);

    $page = $page->firstOrFail();

    return view($page->template)->with('page', $page);
}

我在数据库中保存模板文件信息,因为我允许用户在内容管理系统中创建模板。

然后将对数据库的查询响应传递到视图中,可以将其输出到元数据、页面、面包屑等位置。


Slug只是基于标题的页面。您建议的是完整的永久链接,这不是我要找的。 - Becky
你为什么不能同时使用两者呢?在创建页面时保存slug和永久链接。在应用程序中使用永久链接进行路由。 - Jeemusu
3
谢谢你的回答。我花了几个小时来尝试找到一种在Laravel 5.2中动态处理子页面路由的好方法。你提供的建议使用->where()方法并允许斜杠符号在slug中解决了这个问题。虽然它有点不言自明,但我还想补充说,像这样的一个catch-all路由应该(必须?)放在所有其他路由之后,这样例如admin/pages就不会被认为是这个路由的slug。 - vtamm
1
谢谢!->where('slug', '([A-Za-z0-9\-\/]+)')是我拼图中缺失的一块。 - Maksida
1
哦,我的天啊,你真是个天才,你刚刚节省了我的时间,谢谢! :) - Malki Mohamed
显示剩余2条评论

-17
我也在寻找有关在Laravel中创建动态路由的答案,我找到了以下方法: 在routes.php文件中:
<?php


/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/

$str=Request::url();
$del="/public/";
$pos=strpos($str, $del);
$important1=substr($str, $pos+strlen($del), strlen($str)-1);
$important=ucfirst($important1); 
$asif=explode("/", $important);
$asif1=explode("/", $important1);
//echo $important;
$post=$asif1[0];
$post1=$asif1[1];
if(isset($asif1[2]))
{
   $post2=$asif1[2];
}
if(!(isset($post2)))
{
   Route::match(array('GET','POST'),$important1, $asif[0].'Controller@'.$asif[1]);
}
if(isset($post2))
{      Route::match(array('GET','POST'),$post.'/'.$post1.'/{id}',$asif[0].'Controller@'.$asif[1]);
}
Route::get('/', function () {
    return view('welcome');
});

例子

如果你在 Laravel 中有一个名为 PostController 的控制器,并且其中有一个方法叫做 hello。你可以使用这个 URL http://localhost/shortproject/public/post/hello,其中 shortproject 是你的项目文件夹名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接