87.锁定话题(四)
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 87 小节:An Administrator May Lock Any Thread: Part 4
本节内容
本节我们来实现锁定话题功能的 Ajax
提交。首先我们点击 Lock 按钮时触发lock
方法:
forum\resources\views\threads\show.blade.php
.
.
<thread-view :thread="{{ $thread }}" inline-template>
.
.
<p>
<subscribe-button :active="{{ json_encode($thread->isSubscribedTo)}}" v-if="signedIn"></subscribe-button>
<button class="btn btn-default" v-if="authorize('isAdmin')" @click="lock">Lock</button>
</p>
.
.
</thread-view>
.
.
添加lock
方法:
<script>
import Replies from '../components/Replies';
import SubscribeButton from '../components/SubscribeButton';
export default {
props: ['thread'],
components: { Replies,SubscribeButton},
data() {
return {
repliesCount:this.thread.replies_count,
locked:this.thread.locked
};
},
methods: {
lock() {
this.locked = true;
axios.post('/locked-threads/' + this.thread.slug);
}
}
}
</script>
在话题详情页面进行验证:
现在我们的锁定话题功能已经开发完成,与之相对应,我们还应该有一个解锁功能。我们来新建一个测试:
forum\tests\Feature\LockThreadsTest.php
.
.
/** @test */
public function administrators_can_lock_threads()
{
$this->signIn(factory('App\User')->states('administrator')->create());
$thread = create('App\Thread',['user_id' => auth()->id()]);
$this->post(route('locked-threads.store',$thread));
$this->assertTrue($thread->fresh()->locked);
}
/** @test */
public function administrators_can_unlock_threads()
{
$this->signIn(factory('App\User')->states('administrator')->create());
$thread = create('App\Thread',['user_id' => auth()->id(),'locked' => true]);
$this->delete(route('locked-threads.destroy',$thread));
$this->assertFalse($thread->fresh()->locked);
}
/** @test */
public function once_locked_thread_may_not_receive_new_replies()
{
$this->signIn();
// 注意,我们在此处进行了修改
$thread = create('App\Thread',['locked' =>true]);
$this->post($thread->path() . '/replies',[
'body' => 'Foobar',
'user_id' => auth()->id()
])->assertStatus(422);
}
}
在这里我们需要将locked
进行属性类型转换:
forum\app\Thread.php
.
.
protected $guarded = [];
protected $with = ['creator','channel'];
protected $appends = ['isSubscribedTo'];
protected $casts = [
'locked' => 'boolean'
];
.
.
另外需要注意地是,我们移除了lock()
方法的调用,因为 Laravel 已经在 forum\vendor\laravel\framework\src\Illuminate\Database\Query\Builder.php 中提供了lock()
方法,为了避免歧义,我们删掉Thread
模型文件中lock()
的定义,改为在控制器中直接更新。由于lock()
方法已经删除,我们在ThreadTest.php
测试文件中的a_thread_can_be_locked
测试也就无需存在了,我们删除该测试。
接下来我们增加locked-threads.destroy
路由:
forum\routes\web.php
.
.
Route::post('locked-threads/{thread}','LockedThreadsController@store')->name('locked-threads.store')->middleware('admin');
Route::delete('locked-threads/{thread}','LockedThreadsController@destroy')->name('locked-threads.destroy')->middleware('admin');
.
.
然后我们需要修改store()
方法,并添加destroy()
方法:
forum\app\Http\Controllers\LockedThreadsController.php
<?php
namespace App\Http\Controllers;
use App\Thread;
class LockedThreadsController extends Controller
{
public function store(Thread $thread)
{
$thread->update(['locked' => true]);
}
public function destroy(Thread $thread)
{
$thread->update(['locked' => false]);
}
}
我们运行该测试:
接下来我们进行前端功能的完善。首先我们根据话题locked
与否显示不同的按钮:
forum\resources\views\threads\show.blade.php
.
.
<p>
<subscribe-button :active="{{ json_encode($thread->isSubscribedTo)}}" v-if="signedIn"></subscribe-button>
<button class="btn btn-default" v-if="authorize('isAdmin')" @click="toggleLock" v-text="locked ? 'Unlock' : 'Lock'"></button>
</p>
.
.
接下来我们点击不同的按钮实现不同的功能:
forum\resources\assets\js\pages\Thread.vue
.
.
data() {
return {
repliesCount:this.thread.replies_count,
locked:this.thread.locked
};
},
methods: {
toggleLock() {
axios[this.locked ? 'delete' : 'post']('/locked-threads/' + this.thread.slug);
this.locked = ! this.locked;
}
}
.
.
我们在详情页面进行尝试:
运行全部测试: