Menu

87.锁定话题(四)

本节说明

  • 对应视频教程第 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>

在话题详情页面进行验证:
file
现在我们的锁定话题功能已经开发完成,与之相对应,我们还应该有一个解锁功能。我们来新建一个测试:
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]);
    }
}

我们运行该测试:
file
接下来我们进行前端功能的完善。首先我们根据话题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;
        }
    }
    .
    .

我们在详情页面进行尝试:
file
运行全部测试:
file

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


暂无话题~