Laravel 对多列进行唯一验证
Laravel unique validation on multiple columns
我在 table 个服务器中有 2 列。
我有列 ip
和 hostname
。
我有验证:
'data.ip' => ['required', 'unique:servers,ip,'.$this->id]
这仅适用于列 ip
。但是如何做到这一点才能在 hostname
列中发挥作用?
我想用 ip
和 hostname
列验证 data.ip。
因为 ip 和 hostname 列可以重复,当用户写 ip.
试试这条规则:
'data.ip' => 'required|unique:servers,ip,'.$this>id.'|unique:servers,hostname,'.$this->id
以下内容适用于创建
'data.ip' => ['required', 'unique:servers,ip,'.$this->id.',NULL,id,hostname,'.$request->input('hostname')]
以及更新内容
'data.ip' => ['required', 'unique:servers,ip,'.$this->id.','.$request->input('id').',id,hostname,'.$request->input('hostname')]
我假设 id
是您在 table 中的主键。将其替换为您的环境。
唯一规则的(未记录的)格式是:
table[,column[,ignore value[,ignore column[,where column,where value]...]]]
可以指定多个"where"条件,但只能检查是否相等。任何其他比较都需要关闭(如已接受的答案)。
您可以使用Rule::unique
来实现您的验证规则
$messages = [
'data.ip.unique' => 'Given ip and hostname are not unique',
];
Validator::make($data, [
'data.ip' => [
'required',
Rule::unique('servers')->where(function ($query) use($ip,$hostname) {
return $query->where('ip', $ip)
->where('hostname', $hostname);
}),
],
],
$messages
);
编辑:固定消息分配
Laravel 5.6及以上
控制器中的验证
主键(在我的例子中)是两列的组合 (name, guard_name)
我通过在 create 和 update[ 上使用 Rule class 来验证它们的唯一性=41=] 我的控制器的方法 (PermissionsController)
PermissionsController.php
<?php
namespace App\Http\Controllers;
use App\Permission;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use App\Http\Controllers\Controller;
class PermissionsController extends Controller
{
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
request()->validate([
'name' => 'required|max:255',
'guard_name' => [
'required',
Rule::unique('permissions')->where(function ($query) use ($request) {
return $query
->whereName($request->name)
->whereGuardName($request->guard_name);
}),
],
],
[
'guard_name.unique' => __('messages.permission.error.unique', [
'name' => $request->name,
'guard_name' => $request->guard_name
]),
]);
Permission::create($request->all());
flash(__('messages.permission.flash.created'))->success();
return redirect()->route('permission.index');
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Permission $permission)
{
request()->validate([
'name' => 'required|max:255',
'guard_name' => [
'required',
Rule::unique('permissions')->where(function ($query) use ($request, $permission) {
return $query
->whereName($request->name)
->whereGuardName($request->guard_name)
->whereNotIn('id', [$permission->id]);
}),
],
],
[
'guard_name.unique' => __('messages.permission.error.unique', [
'name' => $request->name,
'guard_name' => $request->guard_name
]),
]);
$permission->update($request->all());
flash(__('messages.permission.flash.updated'))->success();
return redirect()->route('permission.index');
}
}
在更新方法中注意我添加了一个额外的查询约束 [whereNotIn('id', [$permission->id]) ] 以忽略当前模型。
resources/lang/en/messages.php
<?php
return [
'permission' => [
'error' => [
'unique' => 'The combination [":name", ":guard_name"] already exists',
],
'flash' => [
'updated' => '...',
'created' => '...',
],
]
]
flash() 方法来自 laracasts/flash 包。
Table
server
字段
id primary key
ip should be unique with hostname
hostname should be unique with ip
这里我验证了 Ip,主机名应该是唯一的。
use Illuminate\Validation\Rule;
$ip = '192.168.0.1';
$host = 'localhost';
创建时
Validator::make($data, [
'ip' => [
'required',
Rule::unique('server')->where(function ($query) use($ip,$host) {
return $query->where('ip', $ip)->where('hostname', $host);
});
],
]);
更新时
在RULE
后添加忽略
Validator::make($data, [
'ip' => [
'required',
Rule::unique('server')->where(function ($query) use($ip,$host) {
return $query->where('ip', $ip)->where('hostname', $host);
})->ignore($serverid);
],
]);
这对我来说适用于创建和更新。
[
'column_1' => 'required|unique:TableName,column_1,' . $this->id . ',id,colum_2,' . $this->column_2
]
注意:在 Laravel 6.
中测试
public function store(Request $request)
{
$this->validate($request, [
'first_name' => 'required|regex:/^[\pL\s\-]+$/u|max:255|unique:contacts,first_name, NULL,id,first_name,'.$request->input('last_name','id'),
'last_name'=>'required|regex:/^[\pL\s\-]+$/u|max:255|unique:contacts,last_name',
'email' => 'required|email|max:255|unique:contacts,email',
'job_title'=>'required',
'city'=>'required',
'country'=>'required'],
[
'first_name.regex'=>'Use Alphabets Only',
'email.unique'=>'Email is Already Taken.Use Another Email',
'last_name.unique'=>'Contact Already Exist!. Try Again.',
]
);
这是演示代码。它会帮助你更好。我尝试涵盖插入和更新场景。
里面app/Http/Providers/AppServiceProvider.php
Validator::extend('uniqueOfMultiple', function ($attribute, $value, $parameters, $validator)
{
$whereData = [
[$attribute, $value]
];
foreach ($parameters as $key => $parameter) {
//At 0th index, we have table name
if(!$key) continue;
$arr = explode('-', $parameter);
if($arr[0] == 'except') {
$column = $arr[1];
$data = $arr[2];
$whereData[] = [$column, '<>', $data];
} else {
$column = $arr[0];
$data = $arr[1];
$whereData[] = [$column, $data];
}
}
$count = DB::table($parameters[0])->where($whereData)->count();
return $count === 0;
});
里面app/Http/Requests/Something/StoreSometing.php
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:225|uniqueOfMultiple:menus,location_id-' . $this->get('location_id', 'NULL') . ',language_id-' . $this->get('language_id', 1),
'location_id' => 'required|exists:menu_location,id',
'order' => 'digits_between:0,10'
];
}
里面app/Http/Requests/Something/UpdateSomething.php
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:225|uniqueOfMultiple:menus,location_id-' . $this->get('location_id', 'NULL') . ',language_id-' . $this->get('language_id', 'NULL') . ',except-id-' . $this->route('id', 'NULL'),
'location_id' => 'required|exists:menu_location,id',
'order' => 'digits_between:0,10'
];
}
里面resources/lang/en/validation.php
'unique_of_multiple' => 'The :attribute has already been taken under it\'s parent.',
在此代码中,使用的自定义验证是 uniqueOfMultiple
。传递的第一个参数是 table_name 即 menus
,所有其他参数都是 column_name 并且以逗号分隔。此处使用的列是 name
(主列)、location_id
、language_id
和一个用于更新案例的除外列 except-id
。为所有三个传递的值是 -
分隔的。
有表单请求:
在 StoreServerRequest 中(用于创建)
public function rules() {
'ip' => [
'required',
Rule::unique('server')->where(function ($query) {
$query->where('ip', $this->ip)
->where('hostname', $this->host);
})
],
}
public function messages() {
return [
'ip.unique' => 'Combination of IP & Hostname is not unique',
];
}
在 UpdateServerRequest 中(用于更新)
在最后添加忽略即可
public function rules() {
'ip' => [
'required',
Rule::unique('server')->where(function ($query) {
$query->where('ip', $this->ip)
->where('hostname', $this->host);
})->ignore($this->server->id)
],
}
对我来说laravel 8这很有效
$req->validate([
'house_no' => [
Rule::unique('house')
->where('house_no', $req->input('house_no'))
->where('ward_no', $req->input('ward_no'))
],
]);
以下代码在 Laravel 8
对我来说效果很好
创建:
'required|unique:TableName,column_1,' . $this->column_1 . ',id,colum_2,' . $this->column_2,
示例:
public function store(Request $request)
{
$union = auth()->user()->union_id;
$request->validate([
'holding_no' => 'required|integer|unique:holding_taxes,holding_no,' . $request->holding_no . ',id,union_id,' . $union,
]);
}
更新:
'required|unique:TableName,column_1,' . $this->id . ',id,colum_2,' . $this->column_2,
示例:
public function update(Request $request, $id)
{
$union = auth()->user()->union_id;
$request->validate([
'holding_no' => 'required|unique:holding_taxes,holding_no,' . $id . ',id,union_id,'.$union,
]);
}
这对我来说适用于创建和更新。
在您的 ServerUpdateRequest 或 ServerCreateRequest 中 class
public function rules()
{
return [
'column_1' => 'required|unique:TableName,column_1,' . $this->id . ',id,colum_2,' . $this->column_2 . ',colum_3,' . $this->column_3,
];
}
这个命令运行后台聚合Sql像这样
select
count(*) as aggregate
from
`TableName`
where
`column_1` = <postedColumn1Value>
and `id` <> idValue
and `column_2` = <postedColumn2Value>
and `column_3` = <postedColumn3Value>
在 Laravel 9 中测试。并且有效
注意:如果想看后台sql进行调试(比如检查请求值是否为空[$this->]),尤其是要写错代码,比如,您可能输入了错误的文件名。
我在 table 个服务器中有 2 列。
我有列 ip
和 hostname
。
我有验证:
'data.ip' => ['required', 'unique:servers,ip,'.$this->id]
这仅适用于列 ip
。但是如何做到这一点才能在 hostname
列中发挥作用?
我想用 ip
和 hostname
列验证 data.ip。
因为 ip 和 hostname 列可以重复,当用户写 ip.
试试这条规则:
'data.ip' => 'required|unique:servers,ip,'.$this>id.'|unique:servers,hostname,'.$this->id
以下内容适用于创建
'data.ip' => ['required', 'unique:servers,ip,'.$this->id.',NULL,id,hostname,'.$request->input('hostname')]
以及更新内容
'data.ip' => ['required', 'unique:servers,ip,'.$this->id.','.$request->input('id').',id,hostname,'.$request->input('hostname')]
我假设 id
是您在 table 中的主键。将其替换为您的环境。
唯一规则的(未记录的)格式是:
table[,column[,ignore value[,ignore column[,where column,where value]...]]]
可以指定多个"where"条件,但只能检查是否相等。任何其他比较都需要关闭(如已接受的答案)。
您可以使用Rule::unique
来实现您的验证规则
$messages = [
'data.ip.unique' => 'Given ip and hostname are not unique',
];
Validator::make($data, [
'data.ip' => [
'required',
Rule::unique('servers')->where(function ($query) use($ip,$hostname) {
return $query->where('ip', $ip)
->where('hostname', $hostname);
}),
],
],
$messages
);
编辑:固定消息分配
Laravel 5.6及以上
控制器中的验证
主键(在我的例子中)是两列的组合 (name, guard_name)
我通过在 create 和 update[ 上使用 Rule class 来验证它们的唯一性=41=] 我的控制器的方法 (PermissionsController)
PermissionsController.php
<?php
namespace App\Http\Controllers;
use App\Permission;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
use App\Http\Controllers\Controller;
class PermissionsController extends Controller
{
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
request()->validate([
'name' => 'required|max:255',
'guard_name' => [
'required',
Rule::unique('permissions')->where(function ($query) use ($request) {
return $query
->whereName($request->name)
->whereGuardName($request->guard_name);
}),
],
],
[
'guard_name.unique' => __('messages.permission.error.unique', [
'name' => $request->name,
'guard_name' => $request->guard_name
]),
]);
Permission::create($request->all());
flash(__('messages.permission.flash.created'))->success();
return redirect()->route('permission.index');
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Permission $permission)
{
request()->validate([
'name' => 'required|max:255',
'guard_name' => [
'required',
Rule::unique('permissions')->where(function ($query) use ($request, $permission) {
return $query
->whereName($request->name)
->whereGuardName($request->guard_name)
->whereNotIn('id', [$permission->id]);
}),
],
],
[
'guard_name.unique' => __('messages.permission.error.unique', [
'name' => $request->name,
'guard_name' => $request->guard_name
]),
]);
$permission->update($request->all());
flash(__('messages.permission.flash.updated'))->success();
return redirect()->route('permission.index');
}
}
在更新方法中注意我添加了一个额外的查询约束 [whereNotIn('id', [$permission->id]) ] 以忽略当前模型。
resources/lang/en/messages.php
<?php
return [
'permission' => [
'error' => [
'unique' => 'The combination [":name", ":guard_name"] already exists',
],
'flash' => [
'updated' => '...',
'created' => '...',
],
]
]
flash() 方法来自 laracasts/flash 包。
Table
server
字段
id
primary key
ip
should be unique with hostname
hostname
should be unique with ip
这里我验证了 Ip,主机名应该是唯一的。
use Illuminate\Validation\Rule;
$ip = '192.168.0.1';
$host = 'localhost';
创建时
Validator::make($data, [
'ip' => [
'required',
Rule::unique('server')->where(function ($query) use($ip,$host) {
return $query->where('ip', $ip)->where('hostname', $host);
});
],
]);
更新时
在RULE
Validator::make($data, [
'ip' => [
'required',
Rule::unique('server')->where(function ($query) use($ip,$host) {
return $query->where('ip', $ip)->where('hostname', $host);
})->ignore($serverid);
],
]);
这对我来说适用于创建和更新。
[
'column_1' => 'required|unique:TableName,column_1,' . $this->id . ',id,colum_2,' . $this->column_2
]
注意:在 Laravel 6.
中测试public function store(Request $request)
{
$this->validate($request, [
'first_name' => 'required|regex:/^[\pL\s\-]+$/u|max:255|unique:contacts,first_name, NULL,id,first_name,'.$request->input('last_name','id'),
'last_name'=>'required|regex:/^[\pL\s\-]+$/u|max:255|unique:contacts,last_name',
'email' => 'required|email|max:255|unique:contacts,email',
'job_title'=>'required',
'city'=>'required',
'country'=>'required'],
[
'first_name.regex'=>'Use Alphabets Only',
'email.unique'=>'Email is Already Taken.Use Another Email',
'last_name.unique'=>'Contact Already Exist!. Try Again.',
]
);
这是演示代码。它会帮助你更好。我尝试涵盖插入和更新场景。
里面app/Http/Providers/AppServiceProvider.php
Validator::extend('uniqueOfMultiple', function ($attribute, $value, $parameters, $validator)
{
$whereData = [
[$attribute, $value]
];
foreach ($parameters as $key => $parameter) {
//At 0th index, we have table name
if(!$key) continue;
$arr = explode('-', $parameter);
if($arr[0] == 'except') {
$column = $arr[1];
$data = $arr[2];
$whereData[] = [$column, '<>', $data];
} else {
$column = $arr[0];
$data = $arr[1];
$whereData[] = [$column, $data];
}
}
$count = DB::table($parameters[0])->where($whereData)->count();
return $count === 0;
});
里面app/Http/Requests/Something/StoreSometing.php
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:225|uniqueOfMultiple:menus,location_id-' . $this->get('location_id', 'NULL') . ',language_id-' . $this->get('language_id', 1),
'location_id' => 'required|exists:menu_location,id',
'order' => 'digits_between:0,10'
];
}
里面app/Http/Requests/Something/UpdateSomething.php
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'name' => 'required|max:225|uniqueOfMultiple:menus,location_id-' . $this->get('location_id', 'NULL') . ',language_id-' . $this->get('language_id', 'NULL') . ',except-id-' . $this->route('id', 'NULL'),
'location_id' => 'required|exists:menu_location,id',
'order' => 'digits_between:0,10'
];
}
里面resources/lang/en/validation.php
'unique_of_multiple' => 'The :attribute has already been taken under it\'s parent.',
在此代码中,使用的自定义验证是 uniqueOfMultiple
。传递的第一个参数是 table_name 即 menus
,所有其他参数都是 column_name 并且以逗号分隔。此处使用的列是 name
(主列)、location_id
、language_id
和一个用于更新案例的除外列 except-id
。为所有三个传递的值是 -
分隔的。
有表单请求:
在 StoreServerRequest 中(用于创建)
public function rules() {
'ip' => [
'required',
Rule::unique('server')->where(function ($query) {
$query->where('ip', $this->ip)
->where('hostname', $this->host);
})
],
}
public function messages() {
return [
'ip.unique' => 'Combination of IP & Hostname is not unique',
];
}
在 UpdateServerRequest 中(用于更新)
在最后添加忽略即可
public function rules() {
'ip' => [
'required',
Rule::unique('server')->where(function ($query) {
$query->where('ip', $this->ip)
->where('hostname', $this->host);
})->ignore($this->server->id)
],
}
对我来说laravel 8这很有效
$req->validate([
'house_no' => [
Rule::unique('house')
->where('house_no', $req->input('house_no'))
->where('ward_no', $req->input('ward_no'))
],
]);
以下代码在 Laravel 8
对我来说效果很好创建:
'required|unique:TableName,column_1,' . $this->column_1 . ',id,colum_2,' . $this->column_2,
示例:
public function store(Request $request)
{
$union = auth()->user()->union_id;
$request->validate([
'holding_no' => 'required|integer|unique:holding_taxes,holding_no,' . $request->holding_no . ',id,union_id,' . $union,
]);
}
更新:
'required|unique:TableName,column_1,' . $this->id . ',id,colum_2,' . $this->column_2,
示例:
public function update(Request $request, $id)
{
$union = auth()->user()->union_id;
$request->validate([
'holding_no' => 'required|unique:holding_taxes,holding_no,' . $id . ',id,union_id,'.$union,
]);
}
这对我来说适用于创建和更新。
在您的 ServerUpdateRequest 或 ServerCreateRequest 中 class
public function rules()
{
return [
'column_1' => 'required|unique:TableName,column_1,' . $this->id . ',id,colum_2,' . $this->column_2 . ',colum_3,' . $this->column_3,
];
}
这个命令运行后台聚合Sql像这样
select
count(*) as aggregate
from
`TableName`
where
`column_1` = <postedColumn1Value>
and `id` <> idValue
and `column_2` = <postedColumn2Value>
and `column_3` = <postedColumn3Value>
在 Laravel 9 中测试。并且有效
注意:如果想看后台sql进行调试(比如检查请求值是否为空[$this->]),尤其是要写错代码,比如,您可能输入了错误的文件名。