编程

Laravel Sluggable

7 2026-07-21 21:42:00

Nuno Maduro 发布了 Laravel Sluggable,这是一个用于在 Eloquent 模型上自动生成缩略名(slug)的包。该包不依赖于 trait 或基类,而是直接在模型上使用一个 PHP 注解 #[Sluggable]

除了基础知识外,它还涵盖了在实际应用中可能出现的边缘情况:碰撞处理、作用域唯一性(每个租户、每个语言环境)、多列源、软删除记录碰撞,以及完整的 Unicode 和 CJK 音译。

开始

Composer 安装

composer require nunomaduro/laravel-sluggable

注意:此包需要 PHP 8.5+ 和 Laravel 13.5+

配置模型的最快方法是通过内置的 make:sluggable Artisan 命令:

php artisan make:sluggable Post

它会读取你的模型的表结构,选择最可能的源列(titlenameheadlinesubject),将 #[Sluggable] 注解添加到模型类中,并在 database/migrations 目录下创建一个迁移文件:

use NunoMaduro\LaravelSluggable\Attributes\Sluggable;
 
#[Sluggable(from: 'title')]
class Post extends Model
{
}
Schema::table('posts', function (Blueprint $table) {
    $table
        ->string('slug')
    //  ->nullable()
        ->unique()
        ->after('id');
});

在运行迁移之前,请先对其进行审查。如果在运行 php artisan migrate 之前表中已有行,则可能需要将该列设为可空。

之后,将自动生成 slug

$post = Post::create(['title' => 'Laravel News Rocks']);
$post->slug; // "laravel-news-rocks"

配置

所有选项都存在于注解本身。fromto 参数控制读取和写入的列,当你想合并多个列时,from 参数接受一个数组:

#[Sluggable(from: ['first_name', 'last_name'], to: 'slug')]
class Author extends Model {}
 
$author = Author::create(['first_name' => 'John', 'last_name' => 'Tolkien']);
$author->slug; // "john-tolkien"

对于多租户应用或任何具有按作用域唯一性的情况,请传递一个作用域(scope)列(或列数组):

#[Sluggable(from: 'title', scope: 'team_id')]

其他值得注意的选项包括 maxLength(用于限制 slug 长度)、separator(用于替换破折号)和 onUpdating(用于在源列更改时重新生成 slug)。默认情况下,slug 在创建后会被锁定——无论此设置如何,手动分配的 slug 值始终会保留。

错误处理

如果无法生成 slug,该包会抛出一个 CouldNotGenerateSlugException异常。在 HTTP 上下文中,该异常会自动渲染为带有验证式错误有效负载的 422 响应,因此无需额外操作即可纳入现有的错误处理机制。错误键默认为源列名,但可通过 errorKey 进行覆盖。由于该异常扩展自 ValidationException,因此不会出现在应用日志中。

Unicode 支持

该管道可将非拉丁文字转写为可读的拉丁字母形式,并且具有领域感知能力——看起来像主机名或文件路径的值会保持其点号不变,而不会被替换为破折号。

你可以在项目的 GitHub 仓库中了解更多关于 Laravel Sluggable 的信息。