@jaystabins That's not the same as what I put?
@bashy The difference, I believe one of the examples you placed a colon between the id and the column.
$rules['slug'] = 'required|unique:articles,slug:' . $request->slug;
vs
$rules['slug'] = 'required|unique:articles,slug,' . $request->id;
Note, no colon and using the id of the column.
@jaystabins No no, you actually put ":id", not replacing or changing it to $request->id. AS IS :)
@Kryptonit3 Appears so. I can't find it.
Does it pretty much do the same thing? Seeing how rules with parameters list there parameters prefixed with a colon it seems that an additional colon would conflict with that. Would be curious to see something in the framework that shows how this additional colon on a rule with an existing colon would be processed.
@bashy According to the Docs and what is currently now working in my v5.1.7 app. :P
Forcing A Unique Rule To Ignore A Given ID:
Sometimes, you may wish to ignore a given ID during the unique check. For example, consider an "update profile" screen that includes the user's name, e-mail address, and location. Of course, you will want to verify that the e-mail address is unique. However, if the user only changes the name field and not the e-mail field, you do not want a validation error to be thrown because the user is already the owner of the e-mail address. You only want to throw a validation error if the user provides an e-mail address that is already used by a different user. To tell the unique rule to ignore the user's ID, you may pass the ID as the third parameter:
'email' => 'unique:users,email_address,'.$user->id
Maybe @bashy was referring to an actual SQL query which you would indeed use a colon prefixed word to indicate an value to prevent SQL injections.
$results = DB::select( DB::raw("SELECT * FROM some_table WHERE some_col = :somevariable"), [
'somevariable' => $someVariable,
]);
@Kryptonit3 Indeed, it does just exclude the current ID by the looks of it.
@jaystabins It does the same thing but obviously this is slightly different and isn't documented for whatever reason.
Hello @jaystabins, May I ask you some question?
Does IncomingRequest class and rules function are in App\Http\Requests ?
May I see your code in IncomingRequest ?
I want to make a validation like you.
Thanks.
-- Edited --
I got it!. Just create php artisan make:request IncomingRequest and follow the code by @jaystabins.
Thanks again.
I dont understand the solution to this problem? If you have a create user request that you use for both creating the user and editing the user, and use the same form partial.. how can you bypass the validation for unique checks for updating the user?
EDIT: nevermind, I was trying to use this as like an admin, from an entire list of users, all I needed to do was pass a hidden input in for the user id.. which I would guess is ok, right? Only because these are admin controls, and not anything that a regular user has access to change.
Ok, I have a cuestion, while is true that this methods will avoid return error on the email validation, how handle the case that a user malisius or not, try to change his email to other that alredy exist? I don't like the idea of display a SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry on the App. I will prefer to return the error as a message as always.... thaks for any info about!!!
Saving this thread. Great stuff.
@callam Thankyou :)
I know this is sort of old now. But I encountered this when updating a user profile in the default Laravel Auth setup. I have a Form Request called "UserUpdateRequest", and I got the form to submit, with the same email, by using the following setup:
I have a method in my resource controller like this:
// route method is PUT, route looks like /users/1
public function update(UserUpdateRequest $request, $id)
{
// ... update user with $request->all();
}
// inside UserUpdateRequest
public function rules()
{
return [
'name' => 'required|max:255',
'email' => 'required|email|max:255|unique:users,email,'.$this->users,
];
}
This is strange because $this->users contains the ID of the submission, some posts in here say to use $this->id, but that didn't seem to work for me.
I've read this thread with interest and I would like to offer my solution as well which worked fine:
public function rules()
{
$id = \Route::input('locations');
return [
'name' => 'required|unique:locations,name,'.$id,
'slug' => 'required|unique:locations,slug,'.$id,
'route' => 'required',
'postal_code' => 'required',
'locality' => 'required',
'state' => 'required',
'country' => 'required',
];
}
You can fetch and inspect the current route instance like so:
dd(Route::current());
There you can see the whole instance and with Route::input, you can fetch the parameters you need. It is also possible to use this request to create a new post, if the parameter doesn't exist, it will return null.
br, Marc
Documentation says:
'email' => 'unique:users,email_address,'.$user->id
// ------------------------------------------------------------------------------------------------------------------------------------------//
// If your table uses a primary key column name other than id, you may specify it as the fourth parameter: //
// ------------------------------------------------------------------------------------------------------------------------------------------//
'email' => 'unique:users,email_address,'.$user->id.',user_id'
From the various posts I came up will a solution for using a slug, making use of a mixture of many suggestions. This doesn't require adding an id field to the form. Hope it helps
public function rules()
{
$name_rule = ['required', 'min:6'];
if ($this->method() === 'post')
{
$name_rule = array_add($name_rule, 2, 'unique:collections');
}
else
{
$slug = \Route::input('collections');
$collection = Collection::where('slug', $slug)->firstOrFail();
$name_rule = array_add($name_rule, 2, 'unique:collections,name,' . $collection->id);
}
return [
'name' => $name_rule,
];
}
The above takes the provided slug from the url and applies the exception according to the id gathered from a model find.
Hey guys, i found a solution, but is for Laravel 5.3
Here is my solution:
<?php
namespace App\Http\Requests;
use Auth;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;
class ProveedorFormRequest extends FormRequest
{
/**
* Método utilizado en el formrequest
* @var string
*/
protected $metodo;
/**
* ID del usuario autenticado
* @var integer
*/
protected $user_id;
/**
* Cuenta del proveedor
* @var string
*/
protected $cuenta;
/**
* N.I.F. del proveedor
* @var string
*/
protected $nif;
public function __construct(Request $request)
{
$this->user_id = $request->user()->id;
$this->metodo = $request->method();
$this->cuenta = $request->cuenta;
$this->nif = $request->nif;
}
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::check();
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
switch ($this->metodo) {
case 'POST':
$nifRules = [
'required',
'string',
Rule::unique('proveedores', 'nif')->where('user_id', $this->user_id),
];
$cuentaRules = [
'required',
'numeric',
'between:40000000,40999999',
Rule::unique('proveedores', 'cuenta')->where('user_id', $this->user_id),
];
break;
case 'PATCH':
case 'PUT':
$nifRules = [
'required',
'string',
Rule::unique('proveedores', 'nif')
->where('user_id', $this->user_id)
->ignore($this->nif, 'nif'),
];
$cuentaRules = [
'required',
'numeric',
'between:40000000,40999999',
Rule::unique('proveedores', 'cuenta')
->where('user_id', $this->user_id)
->ignore($this->cuenta, 'cuenta'),
];
break;
default:break;
}
return [
'cuenta' => $cuentaRules,
'nombre' => 'required|string',
'razonSocial' => 'string',
'nif' => $nifRules,
'direccion' => 'string',
'cp' => 'numeric',
'poblacion' => 'string',
'pais' => 'string',
'telefono' => 'numeric',
'fax' => 'numeric',
'email' => 'email',
'web' => 'url|active_url',
'tipoDeGasto' => 'numeric',
'formaDePago' => 'numeric',
'retencion' => 'numeric',
];
}
I hope this can help!!! Regards
Laravel v5.3.18, recently released, has made some changes/improvements on this matter. Witigo mentioned it in his example. For more info see https://laravel-news.com/2016/10/unique-and-exists-validation/
Whoa! This is really handy especially for updating user accounts! Thanks guys.
try use this.. just to be clear, ill show my controller, route and form request
CategoriesController.php
public function update(CategoryFormRequest $request, Categories $categories)
{
// form process
}
route
Route::patch('update/{categories}', [
'as' => 'categories.update',
'uses' => 'CategoriesController@update'
]);
CategoriesFormRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use App\Categories;
class CategoryFormRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'category' => 'required|unique:categories,category,'.$this->categories['id'].'|alpha',
'active' => 'integer',
];
}
}
as you can see i use $this->categories['id']. im using laravel 5.4
@kroos start a new thread if you have a problem you need help with
Here is my solution for FormRequest in 5.4:
public function rules()
{
return [
'name' => [
'required',
'max:100',
Rule::unique('templates')->ignore($this->route('template'))
],
'body' => 'required'
];
}
This works for me:
public function rules()
{
return [
'email' => [
'required',
'email',
( $this->method() == 'POST' )? 'unique:users' : Rule::unique('users')->ignore($this->id)
],
'tags' => 'required'
];
}
I'll chip in on this if it's not too late... I solved it two ways:
Approach 1.
Make a helper. You can also make a ifEdit() helper as well
if (! function_exists('ifCreate')) {
function ifCreate($rule)
{
if ($create = request()->method() === 'POST') {
return $rule;
}
return null;
}
}
then you can use one FormRequest for both create & edit
change the param to whatever rule you like, in this case 'required'...
'photo' => ifCreate('required') . '|more|rules'
Approach 2.
I actually like this approach because it's visually clean in the FormRequest but pollutes your form with a hidden input & separates the logic
\\ in your form.blade
{{-- validation hint... --}}
@if (request()->is('*/create'))
<input type="hidden" name="create" value="true">
@endif
\\ in FormRequest
'photo' => 'required_with:create|more|rules'
That's it.
The whole thing can be cleaned-up further with a custom validation Rule i'd imagine
This is much simplified :)
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
$rules = [
'title' =>'required|string|max:255',
'slug' =>"required|alpha_dash|min:5|max:255|unique:posts,slug",
'image' =>'sometimes|image',
'category_id' =>'required|integer',
'body' =>'required'
];
switch($this->method())
{
case 'GET':
case 'DELETE':
{
return [];
}
case 'POST':
{
return $rules;
}
case 'PUT':
case 'PATCH':
{
// Get the value from url
// see 'route:list' in coulum' Uri' - 'posts/{post}'
$post_id = $this->route('post');
// Add ID in validation 'unique'
$rules['slug'] = $rules['slug'].','.$post_id;
return $rules;
}
default:break;
}
}
My earlier posts about dealing with this on Form Requests.
https://asklagbox.com/blog/form-request-store-update
https://asklagbox.com/blog/lets-do-this-part-3#form-request-for-something-different
It's more simple.
The Laravel documentation says "If your table uses a primary key column name other than id, you may specify it as the fourth parameter":
'email' => 'unique:users,email_address,'.$user->id.',user_id'
If for example, you want to verify if a username exists, but excluding current user ID:
// UpdateUserRequest.php
public function rules() {
//
return [
'username' => 'required|unique:users,username,' . $this->id . ',id',
];
}
source: https://laravel.com/docs/5.2/validation#rule-unique -> Section "Forcing A Unique Rule To Ignore A Given ID"
To keep it simple: 'email' => 'required|unique:users,email,'.($this->user->id ?? null)
Please or to participate in this conversation.
