Composite Unique Validation in Laravel - laravel

How I can use composite unique validation for two columns.
Like I have tow columns clinicName and datefield.
Example.
Hclinic, 07-2019
Hclinic, 08-2019
$this->validate($request, [
'clinicName'=> 'unique:hospital',
'dates'=> 'unique:hospital',
]);
My aim is to use Composite Unique Validation.

According to Laravel Docs you can do it by defining the rule this way:
Adding Additional Where Clauses:
You may also specify additional query constraints by customizing the
query using the where method. For example, let's add a constraint that
verifies the account_id is 1:
'email' => Rule::unique('users')->where(function ($query) {
return $query->where('account_id', 1);
})
So you can change your code to:
$this->validate($request, [
'clinicName' => Rule::unique('hospital')->where(function ($query) {
return $query->where('dates', Request::get('dates'));
]);
This will check uniqueness of your clinicName where dates is equal to the given dates of your request.

Related

Laravel validation for option list: if value is not in DB then give error

I have an option list in my front end and the data is retrieved from the DB table, named countries and nicename column.
Trying to prevent the user request for value which is not in countries table and in nicename column. I have created custom validation, which works fine but it looks like it's not too professional way of doing this control. I have seen somewhere that there is shorter way of doing this validation by in:table_name,column_name. But it did not work for me Maybe I am doing something wrong?
$rules = [
'shop_country' => [
'required',
function ($attribute, $value, $fail ) {
$found_country = '';
$countries = Country::get()->toArray();
foreach ($countries as $country) {
if ($country['nicename'] === $value) {
$found_country= $country['nicename'];
}
}
if($found_country === ''){
$fail('The country is not valid!');
}
}],
]
You can define it as:
'shop_country' => ['required|exists:table_name,column']
See docs
You may use the exists validation rule:
The field under validation must exist in a given database table.
$rules = [
'shop_country' => ['required', 'exists:countries,nicename']
];
In the above example, the table name is assumed to be countries.
You should be able to achieve this by using the exists validation rule.
You can check it in the official laravel documentation.
Also this is an example they provide
'state' => 'exists:states'
You can validate nicename as string
'shop_country' => 'required|string|exists:countries,nicename',
Or validate country id itself
'country_id' => 'required|integer|exists:countries,id',

Laravel, unique columns

I need validate if field already exist, throws error, but with this code no errors are triggered
Laravel 7
table: departamento
column: id int incremental
column: departamento varchar(150)
column: idPais int
store method
$this->validate($request, ['departamento' => Rule::unique('departamento','idPais')->where('departamento',$request->depto)->where('idPais',$request->pais)]);
Try with this too
$rules = [
'depto' => [Rule::unique('departamento')->where(function ($query) use ($request) {
return $query->where('departamento','=', $request->depto)->where('idPais','=', $request->pais);
}),]
];
$this->validate($request,$rules);
with this code, throws this error
$rules = [
'depto' => [Rule::unique('departamento')->where(function ($query) use ($request) {
return $query->where('departamento','=', $request->depto)->where('idPais','=', $request->pais);
}),]
];
$this->validate($request,$rules);
Thanks!!!
EDIT:
My bad, I need check two fields , departamento and idPais, thanks.
This is happening because of your field name. The unique rule will try to find a record with that column name set to the request value (in your case, depto, but your column name is departamento). When you are customising the query you are not overriding it, you are adding on top of this default behaviour. From the laravel docs:
By default, the unique rule will check the uniqueness of the column matching the name of the attribute being validated. However, you may pass a different column name as the second argument to the unique method:
With that in mind, you could either change the unique rule to set the column to departamento and not depto as per below, or change the request to send departamento attribute instead of depto:
$rules = [
'depto' => [Rule::unique('departamento', 'departamento')->where(function ($query) use ($request) {
return $query->where('idPais','=', $request->pais);
}),]
];

Laravel Rule::unique not working as expected

This is my migration:
Schema::create('coupons', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->unique();
});
And this is my custom request:
use Illuminate\Validation\Rule;
public function rules()
{
return [
'name' => [
'required', 'string',
Rule::unique('coupons')
->where(function ($q) {
$q->where('name', 'OFFER-2020');
})
]
}
I am trying to block requests where coupon name field already exists in database table. Since OFFER-2020 row already exists in coupons table, it should block the request instead it passes validation.
Update
My input was OFFER 2020. And OFFER-2020 is value after transformation. I thought laravel was checking unique with OFFER-2020. Instead it was checking with both OFFER 2020 and OFFER-2020 by a and query. And that's why my unique was not working.
If you input is OFFER-2020. You will only need to set the correct column name which is the second parameter of the unique rules. This will check the coupons table, for a row with the same name as the input.
Rule::unique('coupons', 'name')
To make your input slugified, you can utilise the form request method prepareForValidation(), this can transform your data.
function prepareForValidation() {
$this->merge(['name' => Str::slug($this->get('name'))]);
}
Why did the previous version fail? As you can see here in the Unique class. If you do not provide a column it will default to id. So you previous query would end up looking something similar to this.
select * from coupons where id = 'OFFER-2020' and name = 'OFFER-2020'

Duplicate on 2 fields

I looking a way to avoid the duplicates in Laravel. For example, I have a table with 2 fields which are name and firstname.
How to manage the duplicates on the Controller? I am newbie...
Here is my function store().
public function store(Request $request)
{
$request->validate([
'name' => 'required|string|max:25',
'firstname' => 'required|string|max:25'
]);
$exists = Auteur::where('name', $request->get('name'))->where('firstName', $request->get('firstName'))->count();
if (!$exists){
Auteur::create($request->all());
return redirect()->route('auteurs.index')
->with('success', 'save');
}
}
I thank you for your help and your explanations.
If it were one field, you could use validation, or make that field unique and that would take care of it with a little error handling. However, with two fields to have to check against, it might be easiest to check if the element is already in the database and deduplicate from there. So in the store() method:
$exists = Auteur::where('name', $req->get('name'))->where('firstname', $req->get('firstname')->count();
if (!$exists){
// create the new model, now that we know there is no duplicate in the database
Auteur::create($request->all());
}
Just add unique in your validation rule. If you would like to check unique validation each field separately.
$request->validate([
'name' => 'required|unique:auteurs,name|string|max:25',
'firstname' => 'required|unique:auteurs,firstname|string|max:25'
]);
Here I hope the table name is `auteurs`

Laravel 4: Unique Validation for Multiple Columns

I know this question has been asked earlier but i did not get relevant answer.
I want to know that how can i write a rule to check uniqueness of two columns. I have tried to write a rule like:
public $rules = array(
"event_id"=>"required",
"label"=>"required|unique:tblSection,label,event_id,$this->event_id",
"description"=>"required"
);
In my example i need to put validation so that one label could be unique for a single event id but may be used for other event id as well. For Example i want to achieve:
id event_id label description
1 1 demo testing
2 2 demo testing
In the rule defined above, somehow i need to pass current selected event_id so that it could check whether the label does not exist in the database table for selected event_id but i am getting syntax error like:
{"error":{"type":"Symfony\\Component\\Debug\\Exception\\FatalErrorException","message":"syntax error, unexpected '\"'","file":"\/var\/www\/tamvote\/app\/modules\/sections\/models\/Sections.php","line":39}}
Note: I don't want to use any package but simply checking if laravel 4 capable enough to allow to write such rules.
The answer from Mohamed Bouallegue is correct.
In your controller for the store method you do:
Model::$rules['label'] = 'required|unique:table_name,label,NULL,event_id,event_id,' .$data['event_id'];
where $data is your POST data.
And for the update method you do:
$model = Model::find($id);
Model::$rules['label'] = 'required|unique:table_name,label,NULL,event_id,event_id,'.$data['event_id'].',id,id'.$model->id;
where $data is your PUT/PATCH data, $model is the record you are editing and id is the table primary key.
I didn't try this before but I think if you get the event_Id before validating then you can do it like this:
'label' => 'unique:table_name,label,NULL,event_id,event_id,'.$eventId
//you should get the $eventId first
If you want to declare your validation rules statically you can do this as well. It's not the most efficient since it checks the database for each value.
protected $rules = [
'user_id' => 'unique_multiple:memberships,user_id,group_id',
'group_id' => 'unique_multiple:memberships,user_id,group_id',
]
/**
* Validates that two or more fields are unique
*/
Validator::extend('unique_multiple', function ($attribute, $value, $parameters, $validator)
{
//if this is for an update then don't validate
//todo: this might be an issue if we allow people to "update" one of the columns..but currently these are getting set on create only
if (isset($validator->getData()['id'])) return true;
// Get table name from first parameter
$table = array_shift($parameters);
// Build the query
$query = DB::table($table);
// Add the field conditions
foreach ($parameters as $i => $field){
$query->where($field, $validator->getData()[$field]);
}
// Validation result will be false if any rows match the combination
return ($query->count() == 0);
});
Like Sabrina Leggett mentioned, you need to create your own custom validator.
Validator::extend('uniqueEventLabel', function ($attribute, $value, $parameters, $validator) {
$count = DB::table('table_name')->where('event_id', $value)
->where('label', $parameters[0])
->count();
return $count === 0;
}, 'Your error message if validation fails.');
You can call your validator by adding the following line to your rules:
'event_id' => "uniqueEventLabel:".request("label")
If you need more fields, you could add a new where clause to the sql statement.
(Source: edcs from this answer)
As you I was looking for hours to do that but nothing worked, I test everything ... suddenly the randomness of the doc I came across this:
'email' => Rule::unique('users')->where(function ($query) {
return $query->where('account_id', 1);
})
https://laravel.com/docs/5.5/validation#rule-unique
and it works perfectly and moreover it is very flexible :)

Resources