Laravel validation unique with where closure - php

I have a table called taxonomy. It's columns are id, name, slug, type (tag, category). I have created a separate controller for tag and category.
Now I need to apply a unique validation rule on slug:
where type = tag

Unique rule with the additional where clause
'slug' => Rule::unique('taxonomy')->where(function ($query) {
return $query->where('type', 'tag');
})

You can apply unique rule like this for insert and update both in single validation function.
public function validateTaxonomy(Request $request){
if(isset($request->id) && $request->id){
$id = ','.$request->id.',id,type,'.$request->tag;
}else{
$id = ',Null,id,type,'.$request->tag;
}
$rules = [
'slug' => 'required|unique:taxonomy,slug'.$id,
];
return Validator::make($request->all(), $rules);
}
Example to call from store function
public function store(Request $request)
{
$validator = $this->validateTaxonomy($request);
if($validator->fails()){
return redirect()->back()->withErrors($validator)->withInput();
}
...
}

Try this:
'postData' => 'unique:table_name,column_name'
see more validation here:
Validation Laravel

Unique rule with the additional where clause
'slug' => Rule::unique('taxonomy')->where('type', 'tag')

Related

Laravel Validations where one filed is unique where other filed must have some id

I want to pass $params['user_id'] to $fieldValidations and check if the hour is unique for specific user_id not for all hours hour in the database table
I created a model post
class Post extends Model
{
protected $fillable = ['user_id', 'hour'];
public static $fieldValidations = [
'user_id' => 'required',
'hour' => 'required|date_format:Y-m-d H:i:s|unique:post,hour,NULL,user_id,'
];
}
and a controller post
class PostController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$params = $request->all();
$params['user_id'] = 12;
$validator = Validator::make($params, Post::$fieldValidations);
if ($validator->fails()) {
return Response::json($validator->errors()->all(), 422);
}
}
}
I don't think you can do this using the unique validation rule. From Laravel 5.7 documentation:
The field under validation must be unique in a given database table.
Note it says table and not column.
You may have to just query the database and return a JSON response error if it fails. Also, in your current code inside the validation rules, you are specifying that user_id is the primary id key column in the post table. I think that is likely an error and should be removed, even though it's irrelevant given that you can't accomplish what you want using the unique rule. Also, you ended the rule with a comma.
if (Post::where(['user_id' => $params['user_id'], 'hour' => $params['hour']])->exists()) {
return response()->json(['status' => 'error', 'msg' => 'Error', 'errors' => ['hour_error' => ['That hour already exists on the user!']]], 422);
}
Lastly, instead of using $params = $request->all(), I prefer to use the request() helper function and just inline it into the rest of the code. But, that's up to you.

how to make unique rule with where() in laravel

hi guys i'm new in laravel and for my question i searched many post but cannot find any solution for that i'm be thankful if you have any guide or solution.
i made a unique rule with where but its not work and return null value so how i do this in right way?
in my case i need to check column 'last_ingameChange' value must lower than time() else validation need to return error message "you just have 1 week to make change your in-game username"
public function validator(array $data, array $rules)
{
return Validator::make($data, $rules);
}
public function updateUserAccount(Request $request, $id)
{
$rules = [
'required|min:5|max:255|unique:users,ingame_name,'.$id.'|'.Rule::unique('users')->where('last_ingameChange', '<', time())
];
$rr = $this->validator([$request->input('ingame_name')], $rules);
dd($rr);
}
but the initialRules is:
"ingame_name" => "required|min:5|max:255|unique:users,ingame_name,1|unique:users,NULL,NULL,id"
What you are doing will simply not work because:
You need to provide a validation field
The Rule::unique will return a Rule instance and not a string so you can't concatenate that to another string or you may force it to coerce to a string which will obviously lose any information you had in the where.
You can use an array to contain the rules:
$rules = [
'ingame_name' => [ //Field name
"required",
"min:5",
"max:255",
"unique:users,ingame_name,$id",
Rule::unique('users', 'ingame_name')
->using(function ($q) { $q->where('last_ingameChange', '<', time()); })
]
];
$this->validator($request->all(), $rules);
As #MikeFoxtech suggested it is preferable to use a before rule however
Try this
Rule::unique('users')->ignore($id, 'ingame_name')->where(function ($query) {
return $query->where('last_ingameChange', '<', time());
})

rules() function in Laravel Request doesn't create unique slugs

I'm trying to make simple unique slugs. The slugs are saved correctly in database, so the function is working. I have problems with making them unique.
I have this rule in TagCreateRequest.php
public function rules()
{
$rules = [
'tag' => 'required|min:3',
'tag_slug' => 'required|alpha_dash|unique:tag,tag_slug,'
];
$rule = 'unique:tag';
$segments = $this->segments();
$id = intval(end($segments));
if ($id != 0) {
$rule .= ',tag_slug,' . $id;
}
$rules['tag_slug'][] = $rule;
return $rules;
}
and this in my store function in the controller
public function store(TagCreateRequest $request)
{
$tag = new Tag();
foreach (array_keys($this->fields) as $field) {
$tag->$field = $request->get($field);
}
$tag->save();
return redirect()->route('tags');
}
The error is about trying to add duplicate value
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'unique slug' for key 'tags_tag_unique'
Can someone help me to fix this issue?
You can access the id field magically. ID must be the same route parameter used in your route.
If you use id parameter like as Route::put('post/{id}/update') then you can magically access the id parameter inside your form request. Otherwise, if you call the parameter of {post} Route::put('post/{post}/update'), in your form request you must be call $this->post instead of $this->id, ok?
Please try it:
public function rules()
{
$rules = [
'tag' => 'required|min:3'
];
$slugRule = 'required|alpha_dash|unique:tag_slug';
if (! empty($this->id)) {
$slugRule = 'required|alpha_dash|unique:tag_slug,'.$this->id;
}
$rules['tag_slug'] = $slugRule;
return $rules;
}
This FormRequest will work fine on the store() and update() methods if you inject him in both methods.
See it:
// Your store route
Route::post('/post/store', ['as' => 'post.store', 'uses' => 'YourController#store']);
// YourController store method
public function store(NameSpaced\FormRequest $request)
{
// ...
}
// Your update route
Route::post('/post/{id}/update', ['as' => 'post.update', 'uses' => 'YourController#store']);
// YourController update method
public function update(NameSpaced\FormRequest $request)
{
// ...
}
$rules = [
'tag' => 'required|min:3',
'tag_slug' => 'required|alpha_dash|unique:[table name],[column name]'
];
Try this the first is table name and the second is column name that you wanted to unique, write without adding square braces. or you just pass table name like this,
$rules = [
'tag' => 'required|min:3',
'tag_slug' => 'required|alpha_dash|unique:[table name]'
];
laravel auto checks for the column.
I hope it helps.
I would suggest that you automatically generate a new slug whenever you are creating a tag. I got myself in same issues that you have listed here, so i decided on automatically generating whenever i am creating a new item. I used laravel-sluggable. It automatically generates unique slugs.
As per your question, i have defined a unique slug rule in one of my demo apps like this:
public function rules()
{
return [
'name' => 'required|string|max:255',
'slug' => 'required|string|max:255|unique:categories,slug,'.$this->segment(3),
];
}
Please note that $this->segment(3) refers to the id of the model being updated in the backend pages, it can be different in your application.

L5.3 - Validator - Get DB record when 'unique' si triggered

I'm using Validator to validate the input:
$validator = Validator::make($request->all(), [
'short' => 'required',
'name' => 'required|unique:type_event,name'
]);
if ($validator->fails()) {
// fails validation
}
When the unique check is fired, is there a way to receive the id or the record that already exists into the DB? Or I've to call the Model for example with:
$data = TypeEventModel::where('name', '=', $request->input('name'))->firstOrFail();
Thank you.
First you need a custom validation rule. Add the following code to app/Providers/AppServiceProvider.php in boot() method:
Validator::extend('unique_with_id', function ($attribute, $value, $parameters, $validator) {
// First we query for an entity in given table, where given field equals the request value
$found = DB::table($parameters[0])
->where($parameters[1], $value)
->first();
// then we add custom replacer so that it gives the user a verbose error
$validator->addReplacer('unique_with_id', function ($message, $attribute, $rule, $parameters) use ($found) {
// replace :entity placeholder with singularized table name and :id with duplicate entity's id
return str_replace([':entity', ':id'], [str_singular($parameters[0]), $found->id], $message);
});
// finally return wether the entity was not found (the value IS unique)
return !$found;
});
Then add the following validation message to resources/lang/en/validation.php
'unique_with_id'=>'Same :entity exists with ID :id',
Finally you can use
$validator = Validator::make($request->all(), [
'short' => 'required',
'name' => 'required|unique_with_id:type_event,name'
]);

Making unique field validation while updating

I am trying to validate for the unique record While editing but it always displays the field must be unique. basically i need to ignore the value of that id. id is the primary key.
$validator=Validator::make($request->all(),[
'name'=>'required',
'telephone'=>'required|unique:telephone',
'email'=>'unique:telephone',
'altemail'=>'unique:telephone',
'image'=>'image',
]);
if($validator->fails()){
return redirect('/telephone/addview')
->withErrors($validator);
}
use additional arguments for unique rule
$validator=Validator::make($request->all(),[
'name'=>'required',
'telephone'=>'required|unique:telephone,telephone,'.$yourMdelInstance->id,
'email'=>'unique:telephone,email,'.$yourMdelInstance->id,
'altemail'=>'unique:telephone,altemail,'.$yourMdelInstance->id,
'image'=>'image',
]);
You can see in the docs you can exclude a value in your unique validation.
Example:
// YourController.php
publiuc function postUpdate(Request $request)
{
// Get your resource first.
$model = Model::find($request->input('id'));
// Check if exists
if (!$model) \App::abort(404);
// Validate
$this->validate($request, [
'...'
'telephone' => 'required|unique:yourtablename,telephone,'.$model->telephone,
'...'
]);
}

Categories