78.最佳回复(一)
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 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();
});
}
.
.
我们运行测试:
接下来我们为最佳回复功能新建一个测试文件:
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]);
}
}
我们运行测试:
接下来我们新增一个测试,确保只有话题的创建者才能标记最佳话题:
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]);
}
.
.
运行测试:
最后,我们来做点小小的重构,将与数据库交互的动作放到模型文件中:
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]);
}
}
运行测试: