Menu

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

本文章首发在 Laravel China 社区
上一篇 下一篇
讨论数量: 0
发起讨论


暂无话题~
刻意练习,每日精进。
1
点赞
49
浏览
0
讨论

维护者