Laravel - 如何将参数传递给路由?有更好的做法吗?
Laravel - how to pass a parameter to a route? Is there a better practice?
简化的场景如下:
我在数据库中有几页(最好不超过 10-20,但没有硬性限制)。它们都有一些内容和一个 "slug"(如果重要的话,有一些包含正斜杠的 slug)。我正在尝试将这些 slug 的路由注册到显示给定页面内容的 PageController
。以下是我对该方法的看法:
- 注册一条 "catch 'em all" 路线(这应该是最后注册的路线)。这绝对是糟糕的。
- 查询数据库中的所有链接并向它们注册单独的路由。这很简单,但我必须查询数据库(这可能不是最优的)并注册数十条,可能是数百条路线。
- 我也尝试过:注册一个 HTTP 中间件,使用
$request->path()
获取查询参数,检查这是否是现有的 slug,如果是,则将其传递给 PageController
。我通过简单地调用 Route::get($request->path(), 'PageController@show')
来实现这一点。
最后两种方法似乎都有效,但有一个问题:如何告诉控制器显示哪个页面?
或者有更好的方法吗?
提前致谢
编辑:我绝对不想使用 'prefix' 并将 slug 作为参数添加到它。定义的 slug 应该与页面完全相同 URL。
您列出的所有方法都可以是解决此问题的有效方法(如果您在路线上附加 where
条件,即使是第一个)。然而,在我看来,性能方面最好的方法是基于第二种解决方案,并且会在需要时生成路由并将其写入文件,然后缓存它们。所以这就是我要做的事情:
Warning: This approach only works if you don't have any Closure based routes
1. 创建一个单独的路由文件,您将在其中存储页面路由,假设在 app/Http/Routes/page.php
中。这是您将为页面编写路由定义的地方。您还需要将其添加到 App\Providers\RouteServiceProvider
class:
的 map
方法中
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routes.php');
require app_path('Http/Routes/page.php');
});
}
2. 然后您需要生成页面的路由定义并将其写入该文件。这样的东西应该足够了:
$path = app_path('Http/Routes/page.php');
$definition = "Route::get('%s', 'PageController@show');\n";
// Remove the routes file so you can regenerate it
if (File::exists($path)) {
File::delete($path);
}
// Write the new routes to the file
foreach (App\Page::all() as $page) {
File::append(sprintf($definition, $page));
}
// Rebuild Laravel's route cache so it includes the changes
Artisan::call('route:cache');
上面的代码应该在特定的 events 上执行,您可以附加到 Page
模型:created
、deleted
、updated
(但是仅当 slug 在更新期间被修改时)。
3. 要访问控制器中的页面详细信息,您只需使用请求的 path
,因为那是您的 slug。所以这样做:
public function show(Request $request)
{
// You need to prepend the slash for the condition since
// the path() method returns the request path without one
$page = App\Page::where('slug', '/' . $request->path())->get();
// Do your stuff...
}
好了,现在所有页面都有路由定义了。而且它们被缓存的事实减轻了当有很多路由时你会得到的任何性能损失,并且你只在对这些路由进行更改时才接触数据库,而不是在每个请求时。
简化的场景如下:
我在数据库中有几页(最好不超过 10-20,但没有硬性限制)。它们都有一些内容和一个 "slug"(如果重要的话,有一些包含正斜杠的 slug)。我正在尝试将这些 slug 的路由注册到显示给定页面内容的 PageController
。以下是我对该方法的看法:
- 注册一条 "catch 'em all" 路线(这应该是最后注册的路线)。这绝对是糟糕的。
- 查询数据库中的所有链接并向它们注册单独的路由。这很简单,但我必须查询数据库(这可能不是最优的)并注册数十条,可能是数百条路线。
- 我也尝试过:注册一个 HTTP 中间件,使用
$request->path()
获取查询参数,检查这是否是现有的 slug,如果是,则将其传递给PageController
。我通过简单地调用Route::get($request->path(), 'PageController@show')
来实现这一点。
最后两种方法似乎都有效,但有一个问题:如何告诉控制器显示哪个页面?
或者有更好的方法吗?
提前致谢
编辑:我绝对不想使用 'prefix' 并将 slug 作为参数添加到它。定义的 slug 应该与页面完全相同 URL。
您列出的所有方法都可以是解决此问题的有效方法(如果您在路线上附加 where
条件,即使是第一个)。然而,在我看来,性能方面最好的方法是基于第二种解决方案,并且会在需要时生成路由并将其写入文件,然后缓存它们。所以这就是我要做的事情:
Warning: This approach only works if you don't have any Closure based routes
1. 创建一个单独的路由文件,您将在其中存储页面路由,假设在 app/Http/Routes/page.php
中。这是您将为页面编写路由定义的地方。您还需要将其添加到 App\Providers\RouteServiceProvider
class:
map
方法中
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routes.php');
require app_path('Http/Routes/page.php');
});
}
2. 然后您需要生成页面的路由定义并将其写入该文件。这样的东西应该足够了:
$path = app_path('Http/Routes/page.php');
$definition = "Route::get('%s', 'PageController@show');\n";
// Remove the routes file so you can regenerate it
if (File::exists($path)) {
File::delete($path);
}
// Write the new routes to the file
foreach (App\Page::all() as $page) {
File::append(sprintf($definition, $page));
}
// Rebuild Laravel's route cache so it includes the changes
Artisan::call('route:cache');
上面的代码应该在特定的 events 上执行,您可以附加到 Page
模型:created
、deleted
、updated
(但是仅当 slug 在更新期间被修改时)。
3. 要访问控制器中的页面详细信息,您只需使用请求的 path
,因为那是您的 slug。所以这样做:
public function show(Request $request)
{
// You need to prepend the slash for the condition since
// the path() method returns the request path without one
$page = App\Page::where('slug', '/' . $request->path())->get();
// Do your stuff...
}
好了,现在所有页面都有路由定义了。而且它们被缓存的事实减轻了当有很多路由时你会得到的任何性能损失,并且你只在对这些路由进行更改时才接触数据库,而不是在每个请求时。