Menu

53.重构垃圾检测机制

本节说明

  • 对应视频教程第 53 小节:Refactoring to Custom Validation

本节内容

目前我们已经实现了检测机制, 但是你是否注意到我们将验证过程分成了两个步骤:首先, 我们触发 Laravel 的内置验证器, 然后我们应用我们的检测机制进行检测。在本节我们将创建一个自定义验证规则, 并通过$this->validate(request(),['body' => 'required|spamfree'])这样的代码即可调用。首先我们新建一个文件:
forum\app\Rules\SpamFree.php

<?php

namespace App\Rules;

use App\Inspections\Spam;

class SpamFree
{
    public function passes($attribute,$value)
    {
        try {
            return ! resolve(Spam::class)->detect($value);
        }catch (\Exception $e){
            return false;
        }
    }
}

注:在 Laravel 5.5 中,你可以更加方便地进行自定义规则的编写,详见 自定义验证规则

接着,我们需要对规则进行注册:
forum\app\Providers\AppServiceProvider.php

    .
    .
    public function boot()
    {
//        Carbon::setLocale('zh');
        \View::composer('*',function ($view){
            $channels = \Cache::rememberForever('channels',function (){
               return Channel::all();
            });
           $view->with('channels',$channels);
        });

        \Validator::extend('spamfree','App\Rules\SpamFree@passes');
    }
    .
    .

现在我们可以简化我们的控制器代码了:
forum\app\Http\Controllers\RepliesController.php

<?php

namespace App\Http\Controllers;

use App\Reply;
use App\Thread;

class RepliesController extends Controller
{
   .
   .
    public function store($channelId,Thread $thread)
    {
        try{
            $this->validate(request(),['body' => 'required|spamfree']);

            $reply = $thread->addReply([
                'body' => request('body'),
                'user_id' => auth()->id(),
            ]);
        }catch (\Exception $e){
            return response(
                'Sorry,your reply could not be saved at this time.',422
            );
        }

        return $reply->load('owner');
    }

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

        try{
            $this->validate(request(),['body' => 'required|spamfree']);

            $reply->update(request(['body']));
        }catch (\Exception $e){
            return response(
                'Sorry,your reply could not be saved at this time.',422
            );
        }
    }
    .
    .
}

forum\app\Http\Controllers\ThreadsController.php

<?php

namespace App\Http\Controllers;

use App\Filters\ThreadsFilters;
use App\Channel;
use App\Thread;
use Illuminate\Http\Request;

class ThreadsController extends Controller
{
    .
    .
    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'),
        ]);

        return redirect($thread->path())
            ->with('flash','Your thread has been published!');
    }
    .
    .
}

现在我们尝试发布话题:
file
消息提示不友好,我们进行友好化处理:
forum\resources\lang\en\validation.php

.
.
'unique'               => 'The :attribute has already been taken.',
'uploaded'             => 'The :attribute failed to upload.',
'url'                  => 'The :attribute format is invalid.',
'spamfree'             => 'The :attribute contains spam.',
.
.

注:在 Laravel 5.5 中,你可以通过重写messages()方法很方便地自定义消息提示,详见 自定义错误消息

现在我们再次尝试:
file
最后我们运行全部测试:
file
有一个测试未通过,我们来看一下那个未通过的测试:

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

    $thread = create('App\Thread');
    $reply = make('App\Reply',[
       'body' => 'something forbidden'
    ]);

    $this->expectException(\Exception::class);

    $this->post($thread->path() . '/replies',$reply->toArray());
}

因为我们已经更改了处理逻辑,所以这个测试需要更新:

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

    $thread = create('App\Thread');
    $reply = make('App\Reply',[
       'body' => 'something forbidden'
    ]);

    $this->post($thread->path() . '/replies',$reply->toArray())
        ->assertStatus(422);
}

再次运行测试:
file

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


zh117