本小节介绍下,日常开发中经常遇到的表单验证。基于控制器主要是用来调度各任务的,那么将验证逻辑代码写在控制器就不是好的做法,那样会将控制器变得臃肿,不符合单一职责原则。这里介绍下,利用表单请求来来验证表单数据。

先创建一个请求基类:

>$ php artisan make:request Request
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return true;
}

以用户添加收货地址为例:

>$ php artisan make:request UserAddressRequest
<?php
namespace App\Http\Requests;

class UserAddressRequest 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 [
'province' => 'required',
'city' => 'required',
'district' => 'required',
'address' => 'required',
'zip' => 'required',
'contact_name' => 'required',
'contact_phone' => 'required',
];
}

public function attributes()
{
return [
'province' => '省',
'city' => '城市',
'district' => '地区',
'address' => '详细地址',
'zip' => '邮编',
'contact_name' => '姓名',
'contact_phone' => '电话',
];
}
}

其中,authorize() 是校验执行者是否有权限执行该动作,比如用户只能修改自己的收货地址;rules() 具体的验证规则,key是form表单里的name字段;attributes() 根据字段自定义错误提示消息。

    使用表单类  

在控制器创建用户收货地址的方法中,使用依赖注入(什么是依赖注入,更多看设计模式)。依赖注入有构造函数、seter方法、接口等实现注入。这里使用常见的构造函数来实现依赖注入。

public function store( UserAddressRequest $request )    
{
$request->user()->addresses()->create($request->only([
'province',
'city',
'district',
'address',
'zip',
'contact_name',
'contact_phone',
]));
return redirect()->route('user_addresses.index'); }

解释下这段代码,首先,有两个模型:User和UserAddress。由于用户和用户收货地址是一对多关系:

// User.php
public function address()
{
return $this->hasMany(UserAddress::class);
}

// UserAddress.php
public function user()
{
return $this->belongsTo(User::class);
}

有了这样的关联关系,就好理解一些了。由于将依赖UserAddressRequest注入到了该方法中,Laravel 会自动调用UserAddressRequest中的 rules() 方法获取校验规则来对用户提交的数据进行校验。

$request->user(): 获取当前登录用户;

user()->address(): 获取当前用户与地址的关联关系(不是获取当前用户的地址列表);

address()->create(): 在关联关系里创建一条新的记录;

$request->only(): 白名单方式从用户提交的数据里获取我们所需要的数据;

redirect()->route('user_addresses.index'): 跳转回地址列表页面。

    汉化错误提示信息

composer安装汉化包:

>$ composer require overtrue/laravel-lang

修改语言配置信息:

// config/app.php
...
'locale' => 'zh_CN',
...
    前端显示验证错误消息
// 只显示第一条错误,或指定字段
$errors->first() or $errors->first('userName')

// 显示全部错误

@foreach ( $errors->all() as $error )
<li><i class="glyphicon glyphicon-remove"></i> {{ $error }}</li>
@endforeach

    表单信息记录功能
<input name='userName' value="{{ old('userName') }}">

这样,当某一项填写有误时,其余正确的项会自动被上一次提交的数据填充,由于这里是闪存数据,只有这一次有效,下次再刷新就没有值了。

至此,一个小小的功能,验证表单的提交已经完成了。我个人是比较喜欢分层的,比如会创建一个 Service 层来处理较复杂的逻辑,Controller 中直接引用 Service 里封装好的代码就好。因为这样,实现解耦的同时,也会让代码看上去不那么凌乱,给单元测试也带来便捷。就像这里使用表单验证类将验证代码从控制器中抽离。编码,思想很重要~

由于能力有限,不足或有不解之处,希望在下方评论区与我讨论,共同提高 。