Laravel教程 七:表单验证 Validation

JellyBool

JellyBool

终于要更新这个Laravel系列教程的第七篇了,期间去写了一点其他的东西。

就不
说废话了吧,直接进入Form Validation的部分吧。几乎在每一个web应用当中都会有表单,而有表单基本就离不开表单验证。在laravel中,其实可以说是有两种方式来进行表单验证:使用Request和使用Validation。下面将分开讲这两部分的内容,而且我会更着重第一种,也更推荐大家使用第一种

Request表单验证

为什么说是会把精力都放在讲解第一种验证方式呢?因为个人觉得第一种方式在相同的验证条件下,更加易于维护和可以进行代码重用。而且写代码的形式
更适
用于Laravel和我个人的使用习惯:可以使用命令行来生成代码。也就是可以使用artisan这个工具:

替代文字

php artisan make:request StoreArticleRequest

在项目目录下使用artisan的make:request命令就可以生成一个用于表单验证Request类了,这个类我们在这里命名为StoreArticleRequest,你也可以以你自己喜欢的方式来命名,但我还是推荐大家在命名的时候尽量使得名字比较人性化一点,这样会比较对于后期再看代码的时候有很多好处。这个命令生成的文件位于app/Http/Requests/这个文件夹当中,我们打开这个文件来看:

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

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            //
        ];
    }
}

实现验证

可以看到里面会有两个方法:authorize()rules()authorize()可以这样简单地理解:我们在处理这个表单请求(通常是一个post请求)的时候是否是需要进行身份验证,这种验证是指:比如A发表的评论,B能不能进行编辑。如果不能,则保留返回false,如果可以,则修改返回true。那么我们这里的逻辑是:既然是发表文章,在我们这个站点注册的用户(如果开放注册的话)都是可以发表文章的,所以我们首先修改authorize()方法,将其返回值改为:return true;

然后对于rules()方法,我们需要在这里设置我们的验证规则,比如我们可以设置下面这个的验证规则:

public function rules()
    {
        return [
            'title' => 'required',
            'content' => 'required'
        ];
    }

因为我们在创建文章的时候,我们会有两个提交过来的字段:titlecontent。这是我们在设计articles表的时候设置的两个字段。

然后,上面的验证规则是:对于titlecontent两个字段,我们需要用户为其填充内容,不能为空。

既然这里的规则设置好之后,我们该怎么应用起来呢?也就是我们怎么在将文章存入数据库之前进行验证呢?很简单,我们只需要稍微修改ArticleControllerstore()方法:

替代文字

public function store(Requests\StoreArticleRequest $request)
    {
        $input = $request->all();
        //下面增加两行,顺便看看Request::get的使用
        $input['intro'] = mb_substr($request->get('content'),0,64);
     }   

我们将整个StoreArticleRequest类的实例以$request变量传入store()方法,这个时候,laravel
就会自动检查我们是否需要进行表单验证(rules方法有没有定义验证规则),如果有需要验证的话,laravel会首先走验证这条路,如果验证没有通过,store()方法内的代码不会被执行,而是直接跳转到提交表单的页面,这里是:http://blog.dev/article/create 这个页面。如果所有的验证都通过之后,才会执行store()内部的代码,也就是才会执行到$input = $request->all();这里以及往下的代码。。。比如我们来试试留空的时候是什么样的情况:

替代文字

反馈错误

上面的图片中好像没有什么变化,但其实是已经提交了一次了,但是又马上跳转回来了。我们可以使用下面的方式来验证一下:

@if($errors->any())
        <ul class="alert alert-danger">
            @foreach($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
@endif

create.blade.php这个视图文件中增加上面的代码,我这里是放在{!! Form::close() !!}后面。这里的意思大概就是,如果有任何表单验证的错误消息,我们就讲这个信息打印出来反馈给用户。如果没有,则不会显示信息。我们再来试一下:

替代文字

这时候可以看到,我们在表单验证没有通过的时候,在页面显示了相对应的错误信息。如果没有错误,就创建一篇文章。

tips:如果你不想错误信息为英文,可以到resources/lang/en/validation.php修改,或者你直接创建一个新的语言文件包。

多个验证规则

OK,这里,我们基本是将这个这个验证流程走通了。但是,在实际的开发中,我们的验证并不都是这个简单:要是我们要对一个字段设置多个验证规则呢?比如我们希望文章的title最少不能少于三个字节长度呢?我们可以这样,在rules()方法中:

'title' => 'required|min:3',

在laravel中,我们使用|将多个规则分开,:表示规则的值。其实这里你也可以使用数组的,但是我还是推荐大家像上面这样写,简洁明了。

其他常用验证规则

至于更多地验证规则,比如注册的时候,验证一个email和确认密码的时候,我们怎么需要怎么写的呢?

'email'=>'required|email',
'password'=>'required|min:6|confirmed',
'password_confirmation' => 'required|min:6'

上面我直接给出这两个常用场景的最常见的写法,email就代表验证所填的信息是否是一个正确地邮箱格式了,至于确认密码就使用confirmed来指定,这里注意是confirmed而不是confirme。而且第二次输入密码的字段需要写成password_confirmation这个形式,也就是在视图中,我们会有类似这样的input表单:

<input type="password" name="password" />
<input type="password" name="password_confirmation" />

关于更多验证规则,参考官方文档:

http://laravel.com/docs/5.1/validation

使用Validation

使用这个之前可以将store(Requests\StoreArticleRequest $request)中的变量去掉

使用Validation的时候,多用于验证一些简单的表单验证。这里演示直接写于ArticleController当中,直接使用Validator::make(),使用方式为Validator::make(array $request,array $rules),比如说我们的例子可以在store()中写成:

$input = Request::all();
$validator = Validator::make($input, [
    'title' => 'required|min:3',
    'body' => 'required',
]);   

然后可以使用下面这样的方式来检查验证有没有通过:

 if ($validator->fails()) 
 {
           
 }

验证通过之后,我们才进行下一步操作,比如将数据存入数据库。一个基本的Validation流程就完成了,而且关于Validation的部分,我也只想介绍到这里,因为我会安利大家使用第一种方式:Request。

tips:这两种方式的背后都是使用一样的验证机制。

总结

这里就基本将基础的表单验证说完了,下一节我准说说queryScope和SetAttributes的使用,这两个对于我们的数据入库的预处理和代码重用都很有帮助,所以下次会先说这两个知识点:我们会先对published_at这个字段的设置和使用发挥出来,到时候你就知道设置这个字段的好处了。

最后:Happy Hacking

本文由 JellyBool 创作, 转载和引用遵循 署名-非商业性使用 2.5 中国大陆 进行许可。

共有 42 条评论

openwrtmail

@jelly
你以前就写过laravel的教程?
[教程里面的图片都是jellybool](http://www.jb51.net/article/60293.htm)

JellyBool

@openwrtmail 这个是之前写的一个小教程,当时还是Laravel 4.2的时候

JellyBool

@openwrtmail 这些都是没有通知的转载,真的比较无耻

lyon

#####错误反馈中的如下代码中,li标签没有内容,应该改成

  • error</li>@foreach(error </li> @foreach(errors->all() as $error)
  • @endforeach @endif

    lyon

    错误通知的提示框,还有注册成功的动画效果,有点像 semantic - ui 。可是看类又不是,博主自己修改了?

    JellyBool

    @lyon 哪个动画效果?

    lyon

    @JellyBool 我记错了那个是[http://t4t5.github.io/sweetalert/] ,智商出错了,想到semantic-ui 去了

    JellyBool

    @lyon 对,用的是sweetalert。其实semantic-ui我在之前的项目都用

    yanjiadong

    验证错误信息代码中忘记显示了,应该加上<li>{ $error }</li>

    @if($errors->any())        
        	<ul class="alert alert-danger">            
    	    	@foreach($errors->all() as $error)                
    	    	<li>{ $error }</li>
    	    	@endforeach        
        	</ul>
        @endif
    
    JellyBool

    其实我加了的,不过在markdown转义的时候貌似直接过滤了 @lyon @yanjiadong

    zhengmin4516

    你好,我
    $data=Request::all();
    // echo $data[‘title’];
    // $page=new Page;
    // page>title=page->title=data[‘title’];
    // page>body=page->body=data[‘body’];
    // $page->slug=mb_substr(Request::get(‘body’),0,64);
    // page>save();Page::create(page->save(); Page::create(data);
    return redirect(’/’);

    我用create提示MassAssignmentException in Model.php line 404:
    _token,用注释的那种方法可以

    JellyBool

    看看这个视频 @zhengmin4516

    https://laravist.com/lesson/13

    zhengmin4516

    @JellyBool 解决了,多谢

    haoran

    楼主用的什么编辑工具,可以说下么?跪求

    haoran

    楼主,看啦你的教程重燃啦我对laravel学习的信心本来都想放弃啦,感谢!

    JellyBool

    恩恩,也挺好的 @haoran

    anqmkd1

    你的这个博文页面是如何换行的,比如我把本篇教程的内容存进数据表的时候,指定是类似于你现在显示的格式。但我从数据表里读出来显示在页面的时候,确实一整段输出。如何解决

    inlofter

    @JellyBool 使用Request表单验证时,有什么方法可以自定义Error Messages,修改语言文件的话,大多数情况下没这个必要。还有直接写在StoreArticleRequest的方法吗?

    我看了文档,貌似只有使用validation的方法才可以,如下:

    $messages = [
        'required' => 'The :attribute field is required.',
    ];
    
    $validator = Validator::make($input, $rules, $messages);
    
    inlofter

    另外,使用Validator::make(array $request,array $rules)时,会提示:

    FatalErrorException in PostController.php line 51:
    Class 'App\Http\Controllers\Validator' not found
    

    不行啊,我用的是官方文档的下面这个可以:

    $this->validate($request, $rules, $messages);
    

    是哪里错了?@JellyBool

    JellyBool

    你引入这个Validator类了? @inlofter

    dudushuang

    @JellyBool
    我的代码出现了问题。提交表单后,store页面提示我 Forbidden
    我估计就是StoreArticleRequest $request这个参数的问题,但是目前没有解决思路,请指教

    dudushuang

    @JellyBool 问题找到了
    artisan 自动生成的文件里面authorize默认返回false。手动改为true就ok了。
    大家难道都没有遇到这个问题吗

    dotasfans

    看完一节,感谢博主无私分享!祝博主在大神的道路上越走越远!

    Jabbowocking

    @dudushuang 我遇到过

    Anonymous

    终于更新了,楼主加油!thanks!

    Anonymous

    请问use Request到底在用哪个命名空间?
    和Illuminate\Http\Request、App\Http\Requests到底什么关系?
    怎么根空间的定义在哪里实现的?
    谢谢。。。。实在是晕了

    Anonymous

    楼主非常厉害,能将一些复杂的东西用实例体现出来,博文非常有质量,赞!期待你的后续博文!!!

    Anonymous

    可以到我的新站点看看,上面有视频教程 https://laravist.com/

    Anonymous

    按照官方文档来说,推荐的用法应该是:

    $this->validate($request, [
            'title' => 'required|unique:posts|max:255',
            'body' => 'required',
        ]);
    

    不过楼主的方式也可,只是不推荐。

    Anonymous

    在新建文章并反馈错误时,提示:
    Undefined variable: errors (View: /home/…/views/articles/create.blade.php)

    Anonymous

    Undefined variable: errors (View: /opt/lampp/htdocs/mylaravel/resources/views/articles/create.blade.php)
    我用laravel 5.2 版本 ,怎么破?

    Anonymous

    反馈错误时,Undefined variable: errors,这个跟 laravel的版本有关吗?我的版本跟博主的一样 是5.1呀。

    Anonymous

    Undefined variable: errors,这个错误的可以参考一下这里 :http://stackoverflow.com/questions/34454081/undefined-variable-errors-in-laravel

    hlhsbczd123

    跳转页面显示Forbidden怎么解决???
    authorize()忘记设置renturn true了 GG

    harryliuj

    你好,我的路由如下
    Route::get(’/patients’,‘PatientController@index’);
    Route::get(’/patients/create’,‘PatientController@create’);
    Route::post(’/patients/store’,‘PatientController@store’);
    在create.blade.php代码如下,
    {!! Form::open([‘action’=>‘PatientController@store’,‘method’=>‘post’]) !!}


    {!! Form::label(‘name’,‘Name:’) !!}
    {!! Form::text(‘name’,null,[‘class’=>‘form-control’]) !!}

        <div class="form-group">
            {!! Form::label('gender','Gender:') !!}<br>
            Male:   {!! Form::radio('gender','1',['class'=>'form-control','checked'=>'']) !!}<br>
            Female: {!! Form::radio('gender','0',['class'=>'form-control','checked'=>'']) !!}
        </div>
    
        <div class="form-group">
            {!! Form::label('phone','Phone:') !!}
            {!! Form::text('phone',null,['class'=>'form-control']) !!}
        </div>
    
        <div class="form-group">
            {!! Form::label('email','Email:') !!}
            {!! Form::text('email',null,['class'=>'form-control']) !!}
        </div>
    
        <div class="form-group">
            {!! Form::label('age','Age:') !!}
            {!! Form::text('age',null,['class'=>'form-control']) !!}
        </div>
    
        <div class="form-group">
            {!! Form::label('surgeon','Surgeon:') !!}
            {!! Form::text('surgeon',null,['class'=>'form-control']) !!}
        </div>
    
        <div class="form-group">
            {!! Form::submit('Add Patient',['class'=>'btn btn-success form-control']) !!}
        </div>
    {!! Form::close() !!}
    

    在提交这个表单的时候无法使用Request获取数据,获取的数据是空array
    class PatientController extends Controller
    {
    public function index()
    {
    $patients = Patient::latest()->get();
    return view(‘patients/index’,compact(‘patients’));
    }

    public function show($id)
    {
        $patient = Patient::findOrFail($id);
        return view('patients/show',compact('patient'));
    }
    public function create()
    {
        return view('patients/create');
    }
    public function store()
    {
        $request = new Request;
        $input = $request->all();
        print_r($input);
        print_r($request->url());
        print_r($request->method());
        return $request->getContent();
    }
    

    结果如下
    Array ( ) http://:GET_token=yA68V9qgYCW6xPwCViWdwx3jXx2Bpn0sz9gW7pjW&name=p2&gender=0&phone=6476436543&email=p2%40test.com&age=22&surgeon=1

    非常困惑,谢谢啦

    JellyBool 回复 harryliuj

    有表单的 method 是 get 的吧

    harryliuj 回复 JellyBool

    后来改成public function store(Request $request)
    {
    $input = $request->all();

    很奇怪问题就没了

    Nixus

    @JellyBool StoreArticleRequest $request如果在API中这么使用时,验证不过会跳转到首页,这个有没有办法,在验证不过的时候,返回错误信息

    bingo8

    “Class App\Http\Controllers\Requests\StoreArticleRequest does not exist” 老是报错