53.重构垃圾检测机制
- 本系列文章为
laracasts.com
的系列视频教程——Let's Build A Forum with Laravel and TDD 的学习笔记。若喜欢该系列视频,可去该网站订阅后下载该系列视频, 支持正版 ;- 视频源码地址:github.com/laracasts/Lets-Build-a-...;
- 本项目为一个 forum(论坛)项目,与本站的第二本实战教程 《Laravel 教程 - Web 开发实战进阶》 类似,可互相参照。
本节说明
- 对应视频教程第 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!');
}
.
.
}
现在我们尝试发布话题:
消息提示不友好,我们进行友好化处理:
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()
方法很方便地自定义消息提示,详见 自定义错误消息
现在我们再次尝试:
最后我们运行全部测试:
有一个测试未通过,我们来看一下那个未通过的测试:
/** @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);
}
再次运行测试: