簡體   English   中英

Laravel 8 路由到控制器。 SEO友好的URL結構

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM