Laravel unique validation on multiple columns - php
I have 2 columns in table servers.
I have columns ip and hostname.
I have validation:
'data.ip' => ['required', 'unique:servers,ip,'.$this->id]
This working only for column ip. But how to do that it would work and for column hostname?
I want validate data.ip with columns ip and hostname.
Because can be duplicates in columns ip and hostname, when user write ip.
You can use Rule::unique to achieve your validation rule
$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
);
edit: Fixed message assignation
The following will work on the create
'data.ip' => ['required', 'unique:servers,ip,'.$this->id.',NULL,id,hostname,'.$request->input('hostname')]
and the following for the update
'data.ip' => ['required', 'unique:servers,ip,'.$this->id.','.$request->input('id').',id,hostname,'.$request->input('hostname')]
I'm presuming that id is your primary key in the table. Substitute it for your environment.
The (undocumented) format for the unique rule is:
table[,column[,ignore value[,ignore column[,where column,where value]...]]]
Multiple "where" conditions can be specified, but only equality can be checked. A closure (as in the accepted answer) is needed for any other comparisons.
Laravel 5.6 and above
Validation in the controller
The primary key (in my case) is a combination of two columns (name, guard_name)
I validate their uniqueness by using the Rule class both on create and on update method of my controller (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');
}
}
Notice in the update method i added an additional query constraint [ whereNotIn('id', [$permission->id]) ] to ignore the current model.
resources/lang/en/messages.php
<?php
return [
'permission' => [
'error' => [
'unique' => 'The combination [":name", ":guard_name"] already exists',
],
'flash' => [
'updated' => '...',
'created' => '...',
],
]
]
The flash() method is from the laracasts/flash package.
Table
server
Field
id primary key
ip should be unique with hostname
hostname should be unique with ip
Here I validate for Ip and the hostname should be unique.
use Illuminate\Validation\Rule;
$ip = '192.168.0.1';
$host = 'localhost';
While Create
Validator::make($data, [
'ip' => [
'required',
Rule::unique('server')->where(function ($query) use($ip,$host) {
return $query->where('ip', $ip)->where('hostname', $host);
});
],
]);
While Update
Add ignore after 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);
],
]);
This works for me for both create and update.
[
'column_1' => 'required|unique:TableName,column_1,' . $this->id . ',id,colum_2,' . $this->column_2
]
Note: tested in Laravel 6.
Try this rule:
'data.ip' => 'required|unique:servers,ip,'.$this>id.'|unique:servers,hostname,'.$this->id
With Form Requests:
In StoreServerRequest (for Create)
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',
];
}
In UpdateServerRequest (for Update)
Just Add ignore at the end
public function rules() {
'ip' => [
'required',
Rule::unique('server')->where(function ($query) {
$query->where('ip', $this->ip)
->where('hostname', $this->host);
})->ignore($this->server->id)
],
}
This is the demo code. It would help you much better. I tried covering both insert and update scenarios.
Inside 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;
});
Inside 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'
];
}
Inside 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'
];
}
Inside resources/lang/en/validation.php
'unique_of_multiple' => 'The :attribute has already been taken under it\'s parent.',
Here in this code, the custom validation used is uniqueOfMultiple. The first argument passed is the table_name i.e menus and all other arguments are column_name and are comma-separated. The columns are used here, name (primary column), location_id, language_id and one except-for column for the update case, except-id. The value passed for all three is - separated.
This works for me for both create and update.
in your ServerUpdateRequest or 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,
];
}
This command run background a aggregate Sql like this
select
count(*) as aggregate
from
`TableName`
where
`column_1` = <postedColumn1Value>
and `id` <> idValue
and `column_2` = <postedColumn2Value>
and `column_3` = <postedColumn3Value>
tested in Laravel 9. and it works
Note: if you want to see background sql for debugging (For example, to check if the request values are empty[$this->]) , especially you have to write wrong code, For example, you may enter a filed name incorrectly.
for me laravel 8 this works
$req->validate([
'house_no' => [
Rule::unique('house')
->where('house_no', $req->input('house_no'))
->where('ward_no', $req->input('ward_no'))
],
]);
The following code worked nicely for me at Laravel 8
Create:
'required|unique:TableName,column_1,' . $this->column_1 . ',id,colum_2,' . $this->column_2,
Example:
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,
]);
}
Update:
'required|unique:TableName,column_1,' . $this->id . ',id,colum_2,' . $this->column_2,
Example:
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,
]);
}
Simple solution with call back query
Rule::unique('users')->where(fn ($query) => $query->where(['project_id'=> request()->project_id, 'code'=> request()->code ])),
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.',
]
);
Related
Rule::unique not working while update | Laravel
Hi I am using Request to validate my form. listingId = 20 categoryType ='listing-category' I have tried two ways to validate the form. First is 'title' => 'required|min:2|max:255|unique:terms,title,'.$listingId.',id,type,'.$categoryType, And the second one is if($this->method() != 'PUT') { $uniqueTitleValidation = Rule::unique('terms')->where('type', $categoryType); } else { $uniqueTitleValidation = []; $uniqueTitleValidation = Rule::unique('terms')->ignore($listingId)->where('type', $categoryType); } and in validation 'title' => [ 'required', 'min:2', 'max:255', $uniqueTitleValidation ], while creating a new entry it Is working fine. But ignoring the type I guess while updating and throw me already exists error. This is my DB table Now as you can see I want to check for listing-category. But I think it also checking for category type. Note: I am using laravel 5.8
Try below example is cleaner and should work. $uniqueTitleValidation = Rule::unique('terms') ->where(function ($query) use($categoryType, $listingId){ if($this->method() != 'PUT') { return $query->where('type', '=', $categoryType); } return $query->where([ ['type', '=', $categoryType], ['id', '<>', $listingId] // ignore this id and search for other rows ]); });
Create a rule in your UpdateRequest under App\Http\Requests Just add the below code. public function rules() { return [ 'title' => [ 'required', 'string', Rule::unique('terms', 'title')->whereNull('deleted_at')->ignore($this->listing), ], ]; }
Laravel form validation using where clause
I'm working on a small project using Laravel and everything is ok with me just i would like to know how can i add a where clause in my validation rule this my code : public function rules() { return [ 'number' => 'required|integer|unique:apartments,number', ]; } i have a table called peoples, contain 3 fields (id, number, room) how i can add a where clause including room field, where number is unique and room != 5,
If you using Laravel 7 you can handle it like this use Illuminate\Validation\Rule; public function rules() { return [ 'number' => [ 'required', 'integer', Rule::unique('apartments', 'number')->where(function ($query) { return $query->where('room', '!=', 5); }) ] ]; } Source
use Illuminate\Validation\Rule; public function rules() { return [ 'number' => [ 'required', 'integer', Rule::unique('apartments')->where(function ($query) { return $query->where('room', '!=', 5); }) ] ]; }
Concaternate Array value with Ternary Operator result
I'm using PHP 7 and Laravel 6. I got errors when I made a user request rule and used it in user controller. The request rule I made is to be reusable in create and update function, so if i pass the id of user, it will validate the unique of user except that id. But if not, it will search all the ids and validate if it's unique. I follow BaM solution, here: https://stackoverflow.com/a/24205849 This my UserRequest.php: public static function rules ($id=0, $merge=[]) { return array_merge( [ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users' . ($id ? ",$id" : ''), 'phone_number' => 'required|string|min:9|max:10|unique:users' . ($id ? ",$id" : ''), 'user_img' => 'required|mimes:jpeg,jpg,png,gif|max:10000', ], $merge); } This is my UserController: public function store(Request $request) { $extend_rules = [ 'pass' => 'required|string|min:8', ]; $validator = Validator::make($request->all(), UserRequest::rules($extend_rules)); if ($validator->fails()) { return redirect()->back(); } $user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->pass), 'phone_number' => $request->phone_number, 'user_img' => $request->user_image->store('user_img'), ]); $user->save(); Session::flash('message', 'Your account is successfully created !'); Session::flash('alert-class', 'alert alert-success'); return redirect()->route('users.index'); } And I got this errors: ErrorException: Array to string conversion I tried to search for solutions but couldn't seem to find anything much my case. If anyone know, please help me!
That's because you're just passing an array while the method accept two different type of parameter $validator = Validator::make($request->all(), UserRequest::rules(0, $extend_rules)); // <-- you need to either pass 1 or 0 for the id and then $extended rules // here is your method signature public static function rules ($id=0, $merge=[]) {
Laravel Complex Conditional Validation
I'm trying to create a validator that require at least one of three input. I tried this protected function validateFundingSource (): array { return request()->validate([ 'title' => 'required', 'description' => 'required', 'national' => 'nullable', 'province' => Rule::requiredIf(!request('national')), 'url' => [ 'required_without_all:phone,email', 'active_url' ], 'phone' => [ 'required_without_all:url,email|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im' ], 'email' => [ 'required_without_all:url,phone|email:rfc,dns' ], 'categories' => 'exists:categories,id' ]); } But it was was forcing only the first field (url). So I tried with Complex Conditional Validation. protected function validateFundingSource () { $v = Validator::make(request()->all(), [ 'title' => 'required', 'description' => 'required', 'national' => 'nullable', 'categories' => 'exists:categories,id', ]); $v->sometimes('province', 'required', function ($input) { return ($input->national === null) ; }); $v->sometimes('url', 'required|active_url', function ($input) { return (($input->phone === null) && ($input->email === null)); }); $v->sometimes('phone', 'required|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im', function ($input) { return (($input->url === null) && ($input->email === null)); }); $v->sometimes('email', 'required|email:rfc,dns', function ($input) { return (($input->url === null) && ($input->phone === null)); }); return $v; } But still no luck... Now it's never required I can submit all three empty field and it's working... Any clues to help me please ? Thank you !
You code is working fine. you just forget to check if validate pass or not. because when you use Validator::make you need to manually check it. for request()->validate laravel will do it for you. inside your validateFundingSource () function just check it pass validate or not before return like this: private function validateFundingSource () { $v = Validator::make(request()->all(), [ 'title' => 'required', 'description' => 'required', 'national' => 'nullable', 'categories' => 'exists:categories,id', ]); $v->sometimes('province', 'required', function ($input) { return ($input->national === null) ; }); $v->sometimes('url', 'required|active_url', function ($input) { return (($input->phone === null) && ($input->email === null)); }); $v->sometimes('phone', 'required|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im', function ($input) { return (($input->url === null) && ($input->email === null)); }); $v->sometimes('email', 'required|email:rfc,dns', function ($input) { return (($input->url === null) && ($input->phone === null)); }); // check if validae failed if($v->fails()) { dd('fail', $v); // do something when it failed } } also sorry for my bad English & hope it help
If you're looking for "at least one of" url, phone, or email then you want to use required_without. This rule means the field is required when any of the specified fields are missing; required_without_all means it's required when all of the specified fields are missing. You are also confusing rule syntax, you must use either array or pipe-delimited string syntax, not both at once. You may want to improve your phone number regex as well; + -. (000-111.9999 #8 is not a great phone number, but would pass your validation. I'd suggest sanitizing your value to remove everything except digits and a leading +, then using a better pattern on what's left. And, it's just a cosmetic change but you can replace Rule::requiredIf(!request('national')), with a simple required_if rule like the others. Changing to a form request validation, this would look like: <?php namespace App\Http\Requests; use Illuminate\Foundation\Http\FormRequest; class StoreFundingsource extends FormRequest { /** * Determine if the user is authorized to make this request. * * #return bool */ public function authorize() { return true; } /** * Prepare the data for validation. * * #return void */ protected function prepareForValidation() { $phone = preg_replace("/[^0-9]/", "", $this->phone); if (strpos($this->phone, "+") === 0) { $phone = "+$phone"; } $this->merge(["phone"=>$phone]); } /** * Get the validation rules that apply to the request. * * #return array */ public function rules() { return [ 'title' => ['required'], 'description' => ['required'], 'national' => ['nullable'], 'province' => ['required_if,national,'], 'categories' => ['exists:categories,id'] 'url' => [ 'required_without:phone,email', 'active_url' ], 'phone' => [ 'required_without:url,email', 'regex:/^\+?1?[2-9][0-9]{5,14}$/' ], 'email' => [ 'required_without:url,phone', 'email:rfc,dns' ], ]; } }
Laravel: Validation unique on update
I know this question has been asked many times before but no one explains how to get the id when you're validating in the model. 'email' => 'unique:users,email_address,10' My validation rule is in the model so how do I pass the ID of the record to the validation rule. Here is my models/User protected $rules_update = [ 'email_address' => 'required|email|unique:users,email_address,'.$id, 'first_name' => "required", 'last_name' => "required", 'password' => "required|min:6|same:password_confirm", 'password_confirm' => "required:min:6|same:password", 'password_current' => "required:min:6" ]; models/BaseModel protected $rules = array(); public $errors; /* * #data: array, Data to be validated * #rules: string, rule name in model */ public function validate($data, $rules = "rules") { $validation = Validator::make($data, $this->$rules); if($validation->passes()) { return true; } $this->errors = $validation->messages(); return false; }
Just a side note, most answers to this question talk about email_address while in Laravel's inbuilt auth system, the email field name is just email. Here is an example how you can validate a unique field, i.e. an email on the update: In a Form Request, you do like this: public function rules() { return [ 'email' => 'required|email|unique:users,email,'.$this->user->id, ]; } Or if you are validating your data in a controller directly: public function update(Request $request, User $user) { $request->validate([ 'email' => 'required|email|unique:users,email,'.$user->id, ]); } Update: If you are updating the signed in user and aren't injecting the User model into your route, you may encounter undefined property when accessing id on $this->user. In that case, use: public function rules() { return [ 'email' => 'required|email|unique:users,email,'.$this->user()->id, ]; } A more elegant way since Laravel 5.7 is: public function rules() { return [ 'email' => ['required', 'email', \Illuminate\Validation\Rule::unique('users')->ignore($this->user()->id)] ]; } P.S: I have added some other rules, i.e. required and email, in order to make this example clear for newbies.
One simple solution. In your Model protected $rules = [ 'email_address' => 'sometimes|required|email|unique:users', .. ]; In your Controller, action:update ... $rules = User::$rules; $rules['email_address'] = $rules['email_address'] . ',id,' . $id; $validationCertificate = Validator::make($input, $rules);
There is an elegant way to do this. If you are using Resource Controllers, your link to edit your record will look like this: /users/{user}/edit OR /users/1/edit And in your UserRequest, the rule should be like this : public function rules() { return [ 'name' => [ 'required', 'unique:users,name,' . $this->user ], ]; } Or if your link to edit your record look like this: /users/edit/1 You can try this also: public function rules() { return [ 'name' => [ 'required', 'unique:users,name,' . $this->id ], ]; }
From Laravel 5.7, this works great use Illuminate\Validation\Rule; Validator::make($data, [ 'email' => [ 'required', Rule::unique('users')->ignore($user->id), ], ]); Forcing A Unique Rule To Ignore A Given ID:
Test below code: 'email' => 'required|email|unique:users,email_address,'. $id .'ID' Where ID is the primary id of the table
If i understand what you want: 'email' => 'required|email|unique:users,email_address,'. $id .'' In model update method, for exemple, should receive the $id with parameter. Sorry my bad english.
Here is the solution: For Update: public function controllerName(Request $request, $id) { $this->validate($request, [ "form_field_name" => 'required|unique:db_table_name,db_table_column_name,'.$id ]); // the rest code } That's it. Happy Coding :)
The Best Option is here try just once no need more code when unique validation on updating data 'email' => 'unique:users,email_address,' . $userId, hereemailis field name and users is table name and email_address is table attribute name which you want unique and $userid is updating row id
public function rules() { switch($this->method()) { case 'GET': case 'DELETE': { return []; } case 'POST': { return [ 'name' => 'required|unique:permissions|max:255', 'display_name' => 'required', ]; } case 'PUT': case 'PATCH': { return [ 'name' => 'unique:permissions,name,'.$this->get('id').'|max:255', 'display_name' => 'required', ]; } default:break; } }
an even simpler solution tested with version 5.2 in your model // validator rules public static $rules = array( ... 'email_address' => 'email|required|unique:users,id' );
You can try this. protected $rules_update = [ 'email_address' => 'required|email|unique:users,email_address,'. $this->id, 'first_name' => "required", 'last_name' => "required", 'password' => "required|min:6|same:password_confirm", 'password_confirm' => "required:min:6|same:password", 'password_current' => "required:min:6" ];
In Laravel 8.x you can use Rule::unique method as well Forcing A Unique Rule To Ignore A Given ID: use Illuminate\Validation\Rule; public function update(Request $request, Post $post) { $validatedData = $request->validate([ 'name' => ['required', 'max:60', Rule::unique('posts')->ignore($post->id)], ]); $post->update($validatedData); return redirect(route('posts.index'))->with('status', 'post updated successfully'); }
Do One step in controller Works Fine with Laravel 9 $request->validate([ 'name'=>'required|unique:categories,name,'.$id, ]);
If you have a separate rules method. You can use easier the following syntax. public function rules() { return [ 'email' => "required|unique:users,email,{$this->id}" ]; }
$rules = [ "email" => "email|unique:users, email, '.$id.', user_id" ]; In Illuminate\Validation\Rules\Unique; Unique validation will parse string validation to Rule object Unique validation has pattern: unique:%s,%s,%s,%s,%s' Corresponding with: table name, column, ignore, id column, format wheres /** * Convert the rule to a validation string. * * #return string */ public function __toString() { return rtrim(sprintf('unique:%s,%s,%s,%s,%s', $this->table, $this->column, $this->ignore ?: 'NULL', $this->idColumn, $this->formatWheres() ), ','); }
There is a simple and elegant way to do this. If you are passing the user_id in a body request or through a query parameter. e.g /update/profile?user_id= Then in your request rules public function rules(Request $request) { return [ 'first_name' => 'required|string', 'last_name' => 'required|string', 'email' => ['required','email', 'string', Rule::unique('users')->ignore($request->user_id )], 'phone_number' => ['required', 'string', Rule::unique('users')->ignore($request->user_id )], ]; } Better Still, you can pass in auth->id() in place of $request->user_id to get the login user id.
Found the easiest way, working fine while I am using Laravel 5.2 public function rules() { switch ($this->method()) { case 'PUT': $rules = [ 'name' => 'required|min:3', 'gender' => 'required', 'email' => 'required|email|unique:users,id,:id', 'password' => 'required|min:5', 'password_confirmation' => 'required|min:5|same:password', ]; break; default: $rules = [ 'name' => 'required|min:3', 'gender' => 'required', 'email' => 'required|email|unique:users', 'password' => 'required|min:5', 'password_confirmation' => 'required|min:5|same:password', ]; break; } return $rules; }
i would solve that by doing something like this public function rules() { return [ 'name' => 'required|min:2|max:255|unique:courses,name,'.\Request::get('id'), ]; } Where you get the id from the request and pass it on the rule
You can also use model classpath, if you don't want to hard code the table name. function rules(){ return [ 'email' => ['required','string', Rule::unique(User::class,'email')->ignore($this->id)] ]; } Here $this->id is either 0 or the record Id to be updated.
Use for Laravel 6.0 use Illuminate\Validation\Rule; public function update(Request $request, $id) { // Form validation $request->validate([ 'category_name' => [ 'required', 'max:255', Rule::unique('categories')->ignore($id), ] ]); }
After researching a lot on this laravel validation topic including unique column, finally got the best approach. Please have a look In your controller use Illuminate\Http\Request; use Illuminate\Support\Facades\Validator; class UserController extends Controller { public function saveUser(Request $request){ $validator = Validator::make($request->all(),User::rules($request->get('id')),User::$messages); if($validator->fails()){ return redirect()->back()->withErrors($validator)->withInput(); } } } saveUser method can be called for add/update user record. In you model class User extends Model { public static function rules($id = null) { return [ 'email_address' => 'required|email|unique:users,email_address,'.$id, 'first_name' => "required", 'last_name' => "required", 'password' => "required|min:6|same:password_confirm", 'password_confirm' => "required:min:6|same:password", 'password_current' => "required:min:6" ]; } public static $messages = [ 'email_address.required' => 'Please enter email!', 'email_address.email' => 'Invalid email!', 'email_address.unique' => 'Email already exist!', ... ]; }
This is what I ended up doing. I'm sure there is a more efficient way of doing this but this is what i came up with. Model/User.php protected $rules = [ 'email_address' => 'sometimes|required|email|unique:users,email_address, {{$id}}', ]; Model/BaseModel.php public function validate($data, $id = null) { $rules = $this->$rules_string; //let's loop through and explode the validation rules foreach($rules as $keys => $value) { $validations = explode('|', $value); foreach($validations as $key=>$value) { // Seearch for {{$id}} and replace it with $id $validations[$key] = str_replace('{{$id}}', $id, $value); } //Let's create the pipe seperator $implode = implode("|", $validations); $rules[$keys] = $implode; } .... } I pass the $user_id to the validation in the controller Controller/UserController.php public function update($id) { ..... $user = User::find($user_id); if($user->validate($formRequest, $user_id)) { //validation succcess } .... }
While updating any Existing Data Write validator as following: 'email' => ['required','email', Rule::unique('users')->ignore($user->id)] This will skip/ignore existing user's id's unique value matching for the specific column.
Test below code: $validator = Validator::make( array( 'E-mail'=>$request['email'], ), array( 'E-mail' => 'required|email|unique:users,email,'.$request['id'], ));
Since you will want to ignore the record you are updating when performing an update, you will want to use ignore as mentioned by some others. But I prefer to receive an instance of the User rather then just an ID. This method will also allow you to do the same for other models Controller public function update(UserRequest $request, User $user) { $user->update($request->all()); return back(); } UserRequest public function rules() { return [ 'email' => [ 'required', \Illuminate\Validation\Rule::unique('users')->ignoreModel($this->route('user')), ], ]; } update: use ignoreModel in stead of ignore
Very easy to do it , Write it at your controller $this->validate($request,[ 'email'=>['required',Rule::unique('yourTableName')->ignore($request->id)] ]); Note : Rule::unique('yourTableName')->ignore($idParameter) , here $idParameter you can receive from get url also you can get it from hidden field. Most important is don't forget to import Rule at the top.
If a login user want to update the email then auth() helper function will give us the login user id auth()->user()->id Laravel helpers#method-auth Validator::make($data, [ 'email' => [ 'required', Rule::unique('users')->ignore(auth()->user()->id), ], ]); if Admin want to change the specific user information from User list then validation will be like this : Validator::make($data, [ 'email' => [ 'required', Rule::unique('users')->ignore($request->user), ], Laravel validation#rule-unique $request object contain the current route related model objects. Which gives the model. Try dd($request)
Most answers to this question refer to email_address, but in Laravel's inbuilt authentication system, the email field name is just email. Here is an example of validating a unique field, i.e. an email on the update: Form Requests look like this: public function rules() { return [ 'email' => [ 'required','email', Rule::unique('users')->ignore($this->id ?? 0)]]; } ?? 0 If you use this then if hare id does not exist this request will not give you an error Save Whenever you access the id property of $this->user, you may encounter an undefined property if you haven't injected the User model into your route. If that is the case, use: public function rules() { return [ 'email' => 'required|email|unique:users,email,'.$this->user()->id ?? 0, ]; } ?? 0 If you use this then if hare id does not exist this request will not give you an error
My solution: $rules = $user->isDirty('email') ? \User::$rules : array_except(\User::$rules, 'email'); Then in validation: $validator = \Validator::make(\Input::all(), $rules, \User::$messages); The logic is if the email address in the form is different, we need to validated it, if the email hasn't changed, we don't need to validate, so remove that rule from validation.
For unique rule in the controller - which obviously will be different for the store method and the update method, I usually make a function within the controller for rules which will return an array of rules. protected function rules($request) { $commonRules = [ 'first_name' => "required", 'last_name' => "required", 'password' => "required|min:6|same:password_confirm", 'password_confirm' => "required:min:6|same:password", 'password_current' => "required:min:6" ]; $uniqueRules = $request->id //update ? ['email_address' => ['required', 'email', 'unique:users,email' . $request->get('id')]] //store : ['email_address' => ['required', 'email', 'unique:users,email']]; return array_merge($commonRules, $uinqueRules); } Then in the respective store and update methods $validatedData = $request->validate($this->rules($request)); This saves from defining two different rule sets for store and update methods. If you can afford to compromise a bit on readability, it can also be protected function rules($request) { return [ 'first_name' => "required", 'last_name' => "required", 'password' => "required|min:6|same:password_confirm", 'password_confirm' => "required:min:6|same:password", 'password_current' => "required:min:6", 'email_address' => ['required', 'email', 'unique:users,email' . $request->id ?: null] ]; }