77.生成话题的 Slug(三)

未匹配的标注

本节说明

  • 对应视频教程第 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!'); } . .

现在我们运行测试:
file
由于我们修改了逻辑,所以我们上一节建立的测试需要进行修改:
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() { . . } . .

最后我们运行全部测试:
file

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~