Laravel 5x 自定义数据验证

2017-01-09  本文已影响1250人  kylesean

Laravel本身内置了许多好用的数据校验规则,拿来即用,但这远远不够,我们需要自定义自己的验证规则是必要的,先看一个简单的示例:

简单验证

直接在 app\Providers\AppServiceProvider.php 里扩展 Validator

打开 app\Providers\AppServiceProvider.php ,在 boot()方法里添加我们自己的验证规则,比方说我们需要一个验证是祖国的手机号码(+86):

namespace App\Providers;
 
use Illuminate\Support\ServiceProvider;
use Validator;
 
class AppServiceProvider extends ServiceProvider
{
 
    public function boot()
    {
        Validator::extend('cn_phone', function($attribute, $value, $parameters) {
            return substr($value, 0, 3) == '+86';
        });
    }
 
}

参考文档我们发现,自定义验证器闭包接收四个参数,分别是要验证的属性名称、属性值、传递给规则的参数数组以及 Validator 实例。

这里:cn_phone 是我们将在验证请求类中使用的规则名称,验证通过返回 TRUE , 失败返回 FALSE,参数 $attribute 是要验证的字段的名称,参数 $parameters 用于更复杂的验证规则,像 Laravel 中默认存在的 min:xsame:field 这种。

下面演示:
定义一个 /form_store 路由指向 FormControllerpostForm 方法,再定义个请求类 CreateUserRequest 依赖注入。

public function postForm(CreateUserRequest $request)
{
    return "Success!";
}

app\Http\Requests\CreateUserRequest.php

<?php 
namespace App\Http\Requests;
 
class CreateUserRequest 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 [
            'phone' => 'required|cn_phone',
        ];
    }
}

我就用自带的 welcome.blade.php 模板页面给大家演示一下:

<div class="content">
    <div class=title m-b-md>
        @if(count($errors) > 0)
            @foreach($errors->all() as $error)
                <li>{{ $error }}</li>  
            @endforeach
        @endif
        <form action="{{ url('form_store') }}" method="post">
            {{ csrf_field() }}
            <input type="text" name="phone">
            <input type="submit" value="确认">
        </form>
    </div>
</div>

preview:

image

好像出错提示出来了,有木有,但是这不是我们想要的,我们要自定义一个错误消息。打开 resources/lang/en/validation.php 找到

'custom' => [
        'attribute-name' => [
            'rule-name' => 'custom-message',
        ],
    ],

按照此格式要求,改写成我们定义的验证字段和对应的返回错误消息提示:

'custom' => [
        'phone' => [
            'zn_phone' => '请加手机号的国际区号+86',
        ],
    ],

再次验证:


image

这还远远不够,对于复杂的数据验证呢?

复杂验证

自定义的 Validator
假设有这么个验证要求,是 phoneemail 当输入手机号时,邮箱就不能同时输入(什么奇葩需求),来看如何定义自己的验证类:

首先我们想到的是这个自定义验证类放哪里好呢?这里我个人建议在 app 下新建一个目录,我取名为 Librarys ,这里放一些公共函数库,第三方支付模块以及我们的自定义验证类等等。上代码:

app\Providers\MyValidator.php

<?php 
namespace App\Librarys;
 
use Illuminate\Validation\Validator;
 
class MyValidator extends Validator {
 
    public function validateEmptyWith($attribute, $value, $parameters)
    {
        return ($value != '' && $this->getValue($parameters[0]) != '') ? false : true;
    }
}

App\Providers\AppServiceProvider

<?php

namespace App\Providers;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
use App\Librarys;
class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {

        Validator::resolver(function($translator, $data, $rules, $messages)
        {
            return new MyValidator($translator, $data, $rules, $messages);
        });
    }

resources\lang\en\validation.php

'custom' => [
    'phone' => [
        'empty_with' => '只能填一个字段,不能同时',
    ],
],

定义好验证类,这个类只是扩展了 Laravel的内置验证基类,想让我们的验证规则被 Laravel “承认”,必须进入 AppServiceProviderboot 方法启动载入。

分析返回条件,想一想如果达不到上面的“需求”,那意味着:

满足这三个条件即为验证通过,那么取反后判断条件如上,大家不用纠结这个判断,着重看 $this->getValue($parameters[0]) 这个方法,参数数组 $parameters[0] 为对应第一个验证规则,类似 min:xxx, 这里是 empty_with:email,通过该参数获取 email 对应的值传入 getValue() 中再返回 bool 值。问题来了,为什么是 empty_with:email 不是 emptyWith:email 或其他的呢,其实框架内部已经为我们处理好了名称的对应的格式,我们自定义的验证类里的验证方法必须以 validate 开头然后接小驼峰命名,对应验证规则的名称就是下划线的方式。这点要牢记

效果图就不放了,大家可以尝试下,这样,基本上我们单独自定义的验证类结构就比较清晰了,利用面向对象的方式抽离出独立的验证类,更符合单一职责原则,这里其实还可以优化,比如独立出一个 ValidationExtensionServiceProvider extends ServiceProvider:

class ValidationExtensionServiceProvider extends ServiceProvider
{

    public function register() {}

    public function boot()
    {
        $this->app->validator->resolver( function( $translator, $data, $rules, $messages = array(), $customAttributes = array() ) {
            return new ValidatorExtended( $translator, $data, $rules, $messages, $customAttributes );
        } );
    }
}   

然后告诉 laravel 载入该服务,app/config/app.php 里添加进去。这样就更符合 Laravel Way 了。

上一篇下一篇

猜你喜欢

热点阅读