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); }
再次运行测试:
推荐文章: