【问题标题】:Validation in controller控制器中的验证
【发布时间】:2015-10-08 00:59:28
【问题描述】:

我是 Laravel 的新手,我需要一些帮助来重构我的代码。 现在,方法没有 100% 覆盖在测试中,因为我无法模拟验证器对象及其响应。 我的控制器中有以下方法

public function store(Request $request)
{
    $data = $request->only([
        'name',
        'email',
        'message',
    ]);

    $validator = Validator::make($data, $this->validatorRules);

    if ($validator->fails()) {
        return $this->response->errorFromValidator($validator);
    }

    $savedItem = $this->repository->store($data);

    if (!$savedItem) {
        return $this->response->error('Cannot save');
    }

    return $this->response->succesItem($savedItem);
}

我尝试在控制器的构造函数中注入验证器:

function __construct(Response $response, Repository $repository, Validator $validator)
{
    $this->response = $response;
    $this->repository = $repository;
    $this->validator= $validator;
}

并在方法中使用它:

$this->validator::make($data, $this->validatorRules);

但我收到语法错误,意外的“::”(T_PAAMAYIM_NEKUDOTAYIM)。 如何在方法之外抽象验证器,以便在测试中模拟验证器?

【问题讨论】:

  • 你不能做$this->validator::make,它是一个对象,而不是一个类......所以你应该做一些更像$this->validator = Validator::make的事情

标签: php validation unit-testing laravel


【解决方案1】:

您为什么使用 Validator 来验证您的数据?

  • 使用 Request 将使您的控制器保持清洁和最小化。但一些 是时候在控制器中使用验证器是明智的,例如,你知道 将只有一个字段需要验证,那么它将是 过度使用 FormRequest。所以这是一个偏好问题。
  • 请求类是验证请求的更好方法,因为它们 帮助从构造方法中提取此功能,该方法 应该尽可能干净。

我建议您使用 Requests 来验证表单数据,而不是在控制器中使用 Validator。从您的代码中我可以注意到您尝试保存联系表格,所以我的建议是:

运行此命令,这将在“Requests”文件夹中创建一个 ContactRequest 文件:

php artisan make:request ContactRequest

联系请求文件:

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class ContactRequest extends Request
{
    /**
     * 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 [
            'name' => 'required|min:5|max:20|alpha',
            'email' => 'required|email',
            'message' => 'required|max:250'
        ];
    }
}

注意:您必须将 autorize 设置为 return true; 以避免出现未授权错误。

你的控制器:

<?php namespace App\Http\Controllers;

use App\Http\Requests\ContactRequest;

class ContactController extends Controller {

function __construct(Repository $repository)
{
    $this->repository = $repository;
}

public function store(ContactRequest $request)
{
    return $this->repository->store($data);
}

}

在您的视图文件中,您可以处理这样的错误:

    @if (count($errors) > 0)
        <div class="alert alert-danger">
        <button class="close" data-close="alert"></button>
                @foreach ($errors->all() as $error)
                    <span>{{ $error }}</span>
                @endforeach
        </div>
    @endif

或者,如果您更喜欢一一显示错误,您可以这样做:

{!! $errors->first('name', '<small class="help-block">:message</small>') !!}
{!! $errors->first('email', '<small class="help-block">:message</small>') !!}
{!! $errors->first('message', '<small class="help-block">:message</small>') !!}

只有在 ContactRequest 验证数据时才会存储您的数据。

现在你的方法应该被测试覆盖了,你可以注意到你的控制器变得多么干净。

【讨论】:

  • 我喜欢使用自定义请求类的方法。控制器确实更清洁。但我正在开发的不是联系表格。字段名称只是一个示例(它们具有误导性)。我正在开发 REST API 应用程序,并且我没有准备任何视图。我已经准备了一些具有errorFromValidator 方法的Reponse 类:return $this-&gt;response-&gt;errorFromValidator($validator); 我在$validator-&gt;fails() 时使用它。该方法将 HTTP Repsonse 设置为“400:错误请求”并显示来自验证器的错误。如何使用您的方法从验证器传递错误?
【解决方案2】:

如果您以这种方式实例化验证器类,则无需使用::

改用$this-&gt;validator-&gt;make($data, $this-&gt;validatorRules);,您应该能够很容易地模拟验证器类的输出。

作为旁注,为什么要模拟您的验证?它是纯代码,不会影响外部服务,因此您应该考虑让这些验证规则在测试期间运行。

【讨论】:

    猜你喜欢
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-17
    相关资源
    最近更新 更多