[英]Laravel 8 routes to controllers. SEO friendly URL structure
I am trying to figure out how to achieve a specific URL structure in a Laravel 8 project and the necessary route to achieve this.我试图弄清楚如何在 Laravel 8 项目中实现特定的 URL 结构以及实现这一目标的必要途径。 What I want is:
我想要的是:
// 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
This is because we don't want the strings “directory” or “blog” contained in the url for every listing or blog post.这是因为我们不希望每个列表或博客文章的 url 中都包含字符串“directory”或“blog”。 Search engine results work better without it.
没有它,搜索引擎结果会更好。
So far I am using a catch-all route {any} at the bottom of the web.php routes file to “catch all” routes that get that far.到目前为止,我在 web.php 路由文件的底部使用了一个包罗万象的路由 {any} 来“捕获所有”到达那一步的路由。 I then manipulate the string provided by the path to get the ID and single character token from the end of the urls.
然后我操作路径提供的字符串以从 url 的末尾获取 ID 和单个字符标记。 I then have these 2 variables but can figure out how to pass these onto the right controllers!
然后我有这两个变量,但可以弄清楚如何将它们传递给正确的控制器!
Or am I being really dumb and there is a much better way of achieving this?还是我真的很笨,有更好的方法来实现这一目标?
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;
}
});
I would split the path into 2 variables ( $slug
and $id
) and directly pass it to the controller.我会将路径拆分为 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+)']);
And in your controllers在你的控制器中
class DirectoryController
{
public function show(string $slug, int $id) {}
}
class PostController
{
public function show(string $slug, int $id) {}
}
I can see two ways of achieving this result:我可以看到实现这一结果的两种方法:
Route::get('{path}', 'CheckPathController@redirect')
Then in your CheckPathController
you do all the checks and your call the proper controller action:然后在您的
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);
}
see: https://laravel.com/docs/8.x/routing#parameters-regular-expression-constraints见: https : //laravel.com/docs/8.x/routing#parameters-regular-expression-constraints
I'm not a regexp master, this should be a basic was to match any {word}-{word}-...-p{id}.html
pattern but it will break in case of unexpected chars我不是正则表达式大师,这应该是一个基本的匹配任何
{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$']);
Note that in this case, you controller will receive the pull $path
string, so you will need to extract the id there.请注意,在这种情况下,您的控制器将收到 pull
$path
字符串,因此您需要在那里提取 id。
You can match the slug using regex您可以使用正则表达式匹配 slug
Route::get('/{any}', 'YourController@methodName')->where(['any' => '.*(-d(.*?)\.).*']);
Repeated with p
与
p
重复
Then when you pickup your $site in your controller method you can use regex to grab the site.然后,当您在控制器方法中获取 $site 时,您可以使用正则表达式来获取站点。
public function methodName($site)
{
preg_match('/.*(-(d(.*?))\.).*/', $site, $parts); //or something similar, $parts[2] will have what you want
}
OR或者
This will give your controller method d{number} or p{number}这会给你的控制器方法 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.