77.生成话题的 Slug(三)
- 本系列文章为
laracasts.com
的系列视频教程 ——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明#
- 对应视频教程第 77 小节:We Need a Regression Test
本节内容#
本节我们对生成话题 Slug 功能做一些完善。按照上一节的逻辑,对于一个标题为 He is Number 24 的话题而言,我们生成的 Slug 为 he-is-number-24。如果有人再次创建标题为 He is Number 24 的话题,会生成的 Slug 为 he-is-number-25。所以本节我们选择该话题的 id 作为 Slug 的后缀,这样可以确保 Slug 唯一。我们依然从新建测试开始:
forum\tests\Feature\CreateThreadsTest.php
.
.
/** @test */
public function a_thread_with_a_title_that_ends_in_a_number_should_generate_the_proper_slug()
{
$this->signIn();
$thread = create('App\Thread',['title' => 'Something 24']);
$thread = $this->postJson(route('threads'),$thread->toArray())->json();
$this->assertEquals("something-24-{$thread['id']}",$thread['slug']);
}
/** @test */
public function unauthorized_users_may_not_delete_threads()
{
.
.
}
.
.
由于我们生成 Slug 的逻辑改变了,所以我们要进行相应修改:
forum\app\Thread.php
.
.
class Thread extends Model
{
.
.
protected static function boot()
{
parent::boot();
static::deleting(function ($thread) {
$thread->replies->each->delete();
});
static::created(function ($thread) {
$thread->update([
'slug' => $thread->title
]);
});
}
.
.
public function setSlugAttribute($value)
{
$slug = str_slug($value);
if (static::whereSlug($slug)->exists()) {
$slug = "{$slug}-" . $this->id;
}
$this->attributes['slug'] = $slug;
}
}
我们利用模型事件 created
来更新 slug
:当模型实例被创建时,slug
为空;当模型实例被创建后,模型事件更新 slug
。所以我们要设置 slug
字段可以为空:
forum\database\migrations{timestamp}_create_threads_table.php
.
.
public function up()
{
Schema::create('threads', function (Blueprint $table) {
$table->increments('id');
$table->string('slug')->unique()->nullable();
$table->unsignedInteger('user_id');
$table->unsignedInteger('channel_id');
$table->unsignedInteger('replies_count')->default(0);
$table->unsignedInteger('visits')->default(0);
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
.
.
现在我们不用在控制器中保存 slug
,并且可以增加 json
返回:
forum\app\Http\Controllers\ThreadsController.php
.
.
public function store(Request $request)
{
$this->validate($request,[
'title' => 'required|spamfree',
'body' => 'required|spamfree',
'channel_id' => 'required|exists:channels,id'
]);
$thread = Thread::create([
'user_id' => auth()->id(),
'channel_id' => request('channel_id'),
'title' => request('title'),
'body' => request('body')
]);
if (request()->wantsJson()) {
return response($thread,201);
}
return redirect($thread->path())
->with('flash','Your thread has been published!');
}
.
.
现在我们运行测试:
由于我们修改了逻辑,所以我们上一节建立的测试需要进行修改:
forum\tests\Feature\CreateThreadsTest.php
.
.
/** @test */
public function a_thread_requires_a_unique_slug()
{
$this->signIn();
create('App\Thread',[],2);
$thread = create('App\Thread',['title' => 'Foo Title']);
$this->assertEquals($thread->fresh()->slug,'foo-title');
$thread = $this->postJson(route('threads'),$thread->toArray())->json();
$this->assertEquals("foo-title-{$thread['id']}",$thread['slug']);
}
/** @test */
public function a_thread_with_a_title_that_ends_in_a_number_should_generate_the_proper_slug()
{
.
.
}
.
.
最后我们运行全部测试:
推荐文章: