Menu

55.重构提交回复

本节说明

  • 对应视频教程第 55 小节:Refactoring to Form Requests

本节内容

就现在而言,处理提交新回复的方法看上去仍然有点臃肿,所以在本节中,我们将它重构为一个方法,然后再进行调用。我们将使用 表单请求验证 来进行我们的重构。首先我们创建表单请求类:

$ artisan make:request CreatePostForm

修改内容如下:
forum\app\Http\Requests\CreatePostRequest.php

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class CreatePostRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'body' => 'required|spamfree',
        ];
    }
}

注:我们暂时让authorize()方法返回true,并且将验证规则放在了rules()方法中。

我们需要修改测试:
forum\tests\Feature\ParticipateInForumTest.php

    .
    .
    /** @test */
    public function replies_that_contain_spam_may_not_be_created()
    {
        $this->withExceptionHandling();

        $this->signIn();

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

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

运行测试:
file
我们需要对异常进行处理:
forum\app\Exceptions\Handler.php

    .
    .
    public function render($request, Exception $exception)
    {
        if($exception instanceof ValidationException){
            return response('Validation failed.',422);
        }
        return parent::render($request, $exception);
    }
    .
    .

如果是ValidationException异常,我们返回 422。因为我们已经对异常进行了处理,现在我们的代码可以进行如下修改:
forum\app\Http\Controllers\RepliesController.php

    .
    .
    public function store($channelId,Thread $thread,CreatePostForm $form)
    {
        if(Gate::denies('create',new Reply)) {
            return response(
                'You are posting too frequently.Please take a break.:)',422
            );
        }

        $reply = $thread->addReply([
            'body' => request('body'),
            'user_id' => auth()->id(),
        ]);

        return $reply = $thread->addReply([
                'body' => request('body'),
                'user_id' => auth()->id(),
            ])->load('owner');
    }
    .
    .

运行测试:
file
接下来我们来整理我们的授权策略:
forum\app\Http\Requests\CreatePostRequest.php

<?php

namespace App\Http\Requests;

use App\Exceptions\ThrottleException;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Gate;

class CreatePostRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return Gate::allows('create',new \App\Reply);
    }

    protected function failedAuthorization()
    {
        throw new ThrottleException;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'body' => 'required|spamfree',
        ];
    }
}

我们重写failedAuthorization(),并且定义了一个异常类:ThrottleException。这个异常类现在还没有建立,我们前往建立:
forum\app\Exceptions\ThrottleException.php

<?php

namespace App\Exceptions;

class ThrottleException extends \Exception
{

}

同样地,我们要为这个异常类做处理:
forum\app\Exceptions\Handler.php

    .
    .
    public function render($request, Exception $exception)
    {
        if($exception instanceof ValidationException){
            return response('Validation failed.',422);
        }

        if($exception instanceof ThrottleException){
            return response('You are posting too frequently.',429);
        }

        return parent::render($request, $exception);
    }
    .
    .

既然我们已经将授权策略转移了位置,那么我们的控制器代码就可以进行修改了:
forum\app\Http\Controllers\RepliesController.php

    .
    .
    public function store($channelId, Thread $thread, CreatePostRequest $form)
    {
        return $reply = $thread->addReply([
                'body' => request('body'),
                'user_id' => auth()->id(),
            ])->load('owner');
    }
    .
    .

我们还需要修改我们的测试:
forum\tests\Feature\ParticipateInForumTest.php

    .
    .
    /** @test */
    public function users_may_only_reply_a_maximum_of_once_per_minute()
    {
        $this->withExceptionHandling();
        $this->signIn();

        $thread = create('App\Thread');
        $reply = make('App\Reply',[
            'body' => 'My simple reply.'
        ]);

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

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

如果你观察得足够仔细,你会发现对授权策略的状态码返回,我们本节用的是 429,而上一节用的是 422。这是上一节我们的一个小错误,我们在本节进行修正。如果我们不清楚状态码的具体含义,我们可以在下面的文件中去确认状态码,例如我们现在需要的状态码 429,表示的是 HTTP_TOO_MANY_REQUESTS:
forum\vendor\symfony\http-foundation\Response.php

现在我们来运行全部测试:
file
我们的测试已经通过,但是如果你新建一个不合法的话题:
file
这是因为我们直接抛出了异常,而没有区分应用场合。我们进行下修改:
forum\app\Exceptions\Handler.php

    .
    .
    public function render($request, Exception $exception)
    {
        if($exception instanceof ValidationException){
            if ($request->expectsJson()){
                return response('Validation failed.',422);
            }
        }

        if($exception instanceof ThrottleException){
            return response('You are posting too frequently.',429);
        }

        return parent::render($request, $exception);
    }
    .
    .

如果是Ajax调用,我们直接抛出异常;否则,我们不做处理。我们再次尝试:
file
我们再次运行全部测试:
file
修复未通过的测试:

    .
    .
    /** @test */
    public function replies_that_contain_spam_may_not_be_created()
    {
        $this->withExceptionHandling();

        $this->signIn();

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

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

再次运行全部测试:
file

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


zh117
CreatePostForm 名字错了?
0 个点赞 | 0 个回复 | 问答