[英]Laravel 8 routes to controllers. SEO friendly URL structure
我試圖弄清楚如何在 Laravel 8 項目中實現特定的 URL 結構以及實現這一目標的必要途徑。 我想要的是:
// Example urls to listings in the business directory.
// These urls should be routed to the directory controller.
www.domain-name.com/example-business-name-d1.html
www.domain-name.com/example-business-name-d15.html
www.domain-name.com/example-business-name-d100.html
www.domain-name.com/example-business-name-d123.html
www.domain-name.com/example-business-name-d432.html
// Example urls to articles/posts in the blog.
// These urls should be routed to the posts controller.
www.domain-name.com/example-post-name-p5.html
www.domain-name.com/example-post-name-p11.html
www.domain-name.com/example-post-name-p120.html
www.domain-name.com/example-post-name-p290.html
www.domain-name.com/example-post-name-p747.html
// We want to avoid the more traditional:
www.domain-name.com/directory/example-business-name-1.html
www.domain-name.com/blog/example-post-name-5.html
這是因為我們不希望每個列表或博客文章的 url 中都包含字符串“directory”或“blog”。 沒有它,搜索引擎結果會更好。
到目前為止,我在 web.php 路由文件的底部使用了一個包羅萬象的路由 {any} 來“捕獲所有”到達那一步的路由。 然后我操作路徑提供的字符串以從 url 的末尾獲取 ID 和單個字符標記。 然后我有這兩個變量,但可以弄清楚如何將它們傳遞給正確的控制器!
還是我真的很笨,有更好的方法來實現這一目標?
Route::get('{any}', function($any = null){
// Break up the url into seperate parts.
$pieces = explode("-", $any);
$pieces = array_reverse($pieces);
$piece = $pieces[0];
// Remove the .html
$piece = substr($piece, 0, -5);
// Get the two parts of the identifier.
$id = substr($piece, 1);
$token = substr($piece, 0, 1);
// Call correct controller based on the token.
switch ($token) {
case "d":
// HERE I WANT TO PASS THE ID ON TO THE SHOW ACTION OF THE DIRECTORY CONTROLLER
break;
case "p":
// HERE I WANT TO PASS THE ID ON TO THE SHOW ACTION OF THE POSTS CONTROLLER
break;
default:
return abort(404);
break;
}
});
我會將路徑拆分為 2 個變量( $slug
和$id
)並將其直接傳遞給控制器。
Route::get('{slug}-d{id}.html', 'DirectoryController@show')
->where(['slug' => '([a-z\-]+)', 'id' => '(\d+)']);
Route::get('{slug}-p{id}.html', 'PostController@show')
->where(['slug' => '([a-z\-]+)', 'id' => '(\d+)']);
在你的控制器中
class DirectoryController
{
public function show(string $slug, int $id) {}
}
class PostController
{
public function show(string $slug, int $id) {}
}
我可以看到實現這一結果的兩種方法:
Route::get('{path}', 'CheckPathController@redirect')
然后在您的CheckPathController
您執行所有檢查並調用正確的控制器操作:
public function redirect(Request $request, $path) {
// Your checks on $path, extract $id and content type
if($isPost) {
$controller = resolve(PostController::class);
return $controller->show($request, $id);
}
if($isBusiness) {
$controller = resolve(BusinessController::class);
return $controller->show($request, $id);
}
// No matches, error 404
abort(404);
}
見: https : //laravel.com/docs/8.x/routing#parameters-regular-expression-constraints
我不是正則表達式大師,這應該是一個基本的匹配任何{word}-{word}-...-p{id}.html
模式但它會在意外字符的情況下中斷
Route::get('{path}', 'PostController::show')
->where(['path' => '([\w]*-)*p[0-9]+\.html$']);
Route::get('{path}', 'BusinessController::show')
->where(['path' => '([\w]*-)*d[0-9]+\.html$']);
請注意,在這種情況下,您的控制器將收到 pull $path
字符串,因此您需要在那里提取 id。
您可以使用正則表達式匹配 slug
Route::get('/{any}', 'YourController@methodName')->where(['any' => '.*(-d(.*?)\.).*']);
與p
重復
然后,當您在控制器方法中獲取 $site 時,您可以使用正則表達式來獲取站點。
public function methodName($site)
{
preg_match('/.*(-(d(.*?))\.).*/', $site, $parts); //or something similar, $parts[2] will have what you want
}
或者
這會給你的控制器方法 d{number} 或 p{number}
Route::get('/{site}', function($site) {
$code = preg_match('/.*(-(d(.*?)|p(.*?))\.).*/', $site, $parts) ? $parts[2] : null;
$controllerName = 'ControllerA';
if(isset($code) && !is_null($code) && Str::contains($code, 'p')) {
$controllerName = 'ControllerB';
}
$controller = app()->make('App\Http\Controllers\Application\\' . $controllerName);
return $controller->callAction('methodName', $params = ['code' => $code]);
})->where(['site' => '.*(-(d|p)(.*?)\.).*']);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.