Menu

78.最佳回复(一)

本节说明

  • 对应视频教程第 78 小节:Mark the Best Reply: Part 1

本节内容

本节我们开始开发最佳回复的功能。首先我们新增一个测试:
forum\tests\Unit\ReplyTest.php

    .
    .
    /** @test */
    public function it_knows_if_it_is_the_best_reply()
    {
        $reply = create('App\Reply');

        $this->assertFalse($reply->isBest());

        $reply->thread->update(['best_reply_id' => $reply->id]);

        $this->assertTrue($reply->isBest());
    }
}

接着我们增加isBest()方法:
forum\app\Reply.php

    .
    .
    public function isBest()
    {
        return $this->thread->best_reply_id == $this->id;
    }
}

然后我们还要修改迁移文件增加best_reply_id字段:
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->unsignedInteger('best_reply_id')->nullable();
            $table->timestamps();
        });
    }
    .
    .

我们运行测试:
file
接下来我们为最佳回复功能新建一个测试文件:
forum\tests\Feature\BestReplyTest.php

<?php

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class BestReplyTest extends TestCase
{
    use DatabaseMigrations;

    /** @test */
    public function a_thread_creator_may_mark_any_reply_as_the_best_reply()
    {
        $this->signIn();

        $thread = create('App\Thread',['user_id' => auth()->id()]);

        $replies = create('App\Reply',['thread_id' => $thread->id],2);

        $this->assertFalse($replies[1]->isBest());

        $this->postJson(route('best-replies.store',[$replies[1]->id]));

        $this->assertTrue($replies[1]->fresh()->isBest());
    }
}

添加路由:
forum\routes\web.php

.
Route::post('/threads/{channel}/{thread}/replies','RepliesController@store');

Route::post('/replies/{reply}/best','BestRepliesController@store')->name('best-replies.store');

Route::patch('/replies/{reply}','RepliesController@update');
.

新建控制器:

$ php artisan make:controller BestRepliesController

添加store()方法:
forum\app\Http\Controllers\BestRepliesController.php

<?php

namespace App\Http\Controllers;

use App\Reply;

class BestRepliesController extends Controller
{
    public function store(Reply $reply)
    {
        $reply->thread->update(['best_reply_id' => $reply->id]);
    }
}

我们运行测试:
file
接下来我们新增一个测试,确保只有话题的创建者才能标记最佳话题:
forum\tests\Feature\BestReplyTest.php

    .
    .
    /** @test */
    public function only_the_thread_creator_may_mark_a_reply_as_best()
    {
        $this->withExceptionHandling()->signIn();

        $thread = create('App\Thread',['user_id' => auth()->id()]);

        $replies = create('App\Reply',['thread_id' => $thread->id],2);

        $this->signIn(create('App\User'));

        $this->postJson(route('best-replies.store',[$replies[1]->id]))
            ->assertStatus(403);

        $this->assertFalse($replies[1]->fresh()->isBest());
    }
}

我们在控制器应用授权策略即可:
forum\app\Http\Controllers\BestRepliesController.php

    .
    .
    public function store(Reply $reply)
    {
        $this->authorize('update',$reply->thread);

        $reply->thread->update(['best_reply_id' => $reply->id]);
    }
    .
    .

运行测试:
file
最后,我们来做点小小的重构,将与数据库交互的动作放到模型文件中:
forum\app\Http\Controllers\BestRepliesController.php

    .
    .
    public function store(Reply $reply)
    {
        $this->authorize('update',$reply->thread);

        $reply->thread->markBestReply($reply);
    }
    .
    .

forum\app\Thread.php

    .
    .
    public function markBestReply(Reply $reply)
    {
        $this->update(['best_reply_id' => $reply->id]);
    }
}

运行测试:
file

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


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

维护者