3分鐘短文:Laravel slug,讓你的url地址更“好記”

ragus發表於2020-10-05

引言

網路資源訪問,路由是多麼重要不消多言了。而友好的url地址更是能讓人一目瞭然,增加使用者的好感。同時對於爬蟲也是好的示例,搜尋引擎可以友好地展開工作了。

img

本文就來講講,如何在laravel中構造友好的url路由。

啥是slug?

在早期的網際網路時代,為了在頁面之間傳遞資料,複雜的互動一般都會使用cookie等本地快取,但是瀏覽器版本的約束,使得伺服器端互動仍然需要即時訪問。所以各種各樣的url地址,帶引數跳轉的,表單提交的,混為一談,製作出符合統一規範的路由很不容易。

比如下面的路由,訪問一個地址,並且攜帶querystring引數:

http://example.com/events.php?id=42

相應地,不同的使用者,這個id也不相同。不同的頁面,也不相同。像這樣帶參傳遞的路由地址,是最為原始的。我們在之前的章節已經使用laravel Route功能,重新構造了url,所以訪問起來像是連貫的:

http://example.com/events/42

直接使用位置引數繫結的方式傳遞。因為數字42對使用者而言沒有實際意義,而對資料庫來說是索引欄位。如果使用如下方式,效果要友好的多:

http://example.com/events/laravel-hacking-and-coffee

這種基於字串位置引數繫結的URL方式,被稱為 slug。有一個第三方類庫專門用於url的友好化。使用 composer 安裝:

composer require cviebrock/eloquent-sluggable:^4.3

模型引入 Slug 功能

引入 eloquent-sluggable 類庫,只需要在laravel模型檔案內引入對應trait,並過載實現sluggable方法:

use Cviebrock\EloquentSluggable\Sluggable;
class Event extends Model {
    use Sluggable;
    public function sluggable()
    {
        return [
            'slug' => [
                'source' => 'name'
            ]
        ];
    }
}

上述 sluggable 方法指定了,哪個欄位用於slug搜尋,(此處是 slug)。以及slug欄位對應的資料庫表的欄位來源,此處是 name 欄位。

接著我們需要修改 events 表,為其追加 slug 欄位。命令列建立遷移檔案:

php artisan make:migration add_slug_column_to_events_table --table=events

執行成功返回:

Created Migration: 2020_10_04_225240_add_slug_column_to_events_table

然後手動實現遷移檔案的 up 方法:

public function up()
{
    Schema::table('events', function (Blueprint $table) {
        $table->string('slug')->nullable();
    });
}

以及回滾使用的 down 方法:

public function down()
{
    Schema::table('events', function (Blueprint $table) {
        $table->dropColumn('slug');
    });
}

在命令列執行遷移成功後,資料庫表events就會追加上slug欄位了。

如果原來資料庫表內已經又生產資料,此時我們需要手動更新一下。使用 tinker 快捷操作:

namespace App;
$events = Event::all();
foreach($events as $event) {
    $event->save();
}

資料量不大,我們也不考慮效率不效率的問題了。foreach迴圈直接用了。

建立基於 slug 的模型查詢

資料庫準備好了,模型準備好了,現在讓我們把slug功能用起來。

如果你有印象的話,應該會記得laravel模型的find等方法,是基於primary key進行索引,以便加快查詢速度。拿到模型的ID,查詢該條目資料,然後返回模型例項。這是基於ID這個integer型別的查詢。

而slug查詢,是基於字串的,如果要使用slug此功能,需要改寫預設的列名。在模型檔案內手動重寫如下方法:

public function getRouteKeyName()
{
    return 'slug';
}

返回字串,就是查詢所依據的“欄位名”。這樣預設的查詢就不走預設的 $primaryKey = ‘id’ 這個欄位,而是使用手動指定的 slug欄位了。

當然了,如果沒有使用路由引數繫結,eloquent-sluggable類庫也為我們提供了友好的trait,在模型檔案內直接引入就好了:

use Cviebrock\EloquentSluggable\Sluggable;
use Cviebrock\EloquentSluggable\SluggableScopeHelpers;
class Event extends Model
{
    use Sluggable, SluggableScopeHelpers;
}

從名字你就能猜測的到,SluggableScopeHelpers 是一個全域性作用域檔案,這是我們上一章所講內容,不再贅述。

完成引入後,在使用模型進行查詢時,就可以這樣使用了:

$event = Event::findBySlug('laravel-hacking-and-coffee');
$event = Event::findBySlugOrFail('laravel-hacking-and-coffee');

歸根結底,就是使用slug欄位記錄查詢的字串,而slug欄位在對應關係中定義為 source => ‘name’ 欄位,所以SQL查詢仍然是根據slug欄位嚴格匹配約束返回資料集。

資料量大了之後,這種等於的WHERE子句效能必然不如ID欄位的主鍵索引來的快。所以在資料庫層面也同樣需要優化。

寫在最後

本文介紹了在模型檔案內,引入slug的功能,並通過修改模型的查詢方式,讓模型的預設查詢方式修改為通過字串進行查詢,從而可以在路由檔案內構造更友好的查詢url。

Happy coding :-)

我是@程式設計師小助手,專注程式設計知識,圈子動態的IT領域原創作者

本作品採用《CC 協議》,轉載必須註明作者和本文連結
write-less-do-more-make-you-out-of-door

相關文章