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() { . . } . .
最后我们运行全部测试:
推荐文章: