composite-unique-key-validation - laravel - php

seems it's not possible with built-in validators, how I should implement this feature in the model?
$rules = [
'user_id' => 'required|unique:service_details,user_id',
'service_id'=>'required|unique:service_details,service_id'
];
above will prevent duplicacy of user_id and service_id independently which is not my requirement
it will reject
(1,2)
(1,3)
because 1 is duplicate but it should be accepted as i want composite unique key

Composite unique field validation is provided out-of-the-box in 5.0+. I can't speak for earlier versions.
You can essentially specify a where clause for when your unique validation rule applies. E.g.
'term' => 'unique:terms,term,NULL,id,taxonomy,category'
This rule says that term should be unique on the terms table but only where the taxonomy is equal to "category".
For example, it will prevent a "news" category being duplicated but I can still have a "news" tag.
I don't know your schema but in your case it'd be something like this:
$user_id = Request::get('user_id', $default);
$service_id = Request::get('service_id', $default);
// or another way of specifying the accompanying service/user ID for the where clauses
$rules = [
'user_id' => 'unique:service_details,user_id,NULL,id,service_id,' . $service_id;
'service_id' => 'unique:service_details,service_id,NULL,id,user_id,' . $user_id;
];

My solution
Laravel 5.3 and 5.4
Note: Without model binding
Store
'required',
Rule::unique('service_details','service_id')->where(function ($query) {
$query->where('user_id', $this->request->get('user_id'));
})
Update
'required',
Rule::unique('service_details','service_id')->ignore($this->route()->id)->where(function ($query) {
$query->where('user_id', $this->request->get('user_id'));
})

This is not possible out of the box in Laravel. You would either have to write a custom validator or use a package for that.
Here is one that should do what you need:
- https://github.com/felixkiss/uniquewith-validator
With this package, your rules could look like the following:
$rules = array(
'user_id' => 'required|unique_with:service_details,service_id',
'service_id' => 'required',
);
It works for both Laravel 4 and 5.

With the help of this link , I am able to achieve composite validation from out of the box laravel 5.3. I knew it is old question and answered already. In my case vendor and client combination is unique.
My sample code is below
$this->validate($request, [
'Vendor'=> 'bail|required|int',
'Client'=> 'bail|required|int',
'discount'=> 'required|numeric',
'Client'=>'unique:billings,client_id,vendor_id'.$request->Vendor
]);

Related

Laravel Eloquent - bulk update with whereIn array

I'm working on a project where I need to update many rows at once per coin Id.
in order to update all coins values, Im getting them all from the API, so for example I have back:
$coinsList= [[id="bitcoin", symbol="btc", name="Bintcoin"],[id="etherium", symbol="eth", name="Etherium"]];
and the database table columns is the following:
**| id | coin_id | symbol | name |**
now, I want to update all values to the database, according to the id only, so this is what I did:
// first get ids from my table
$exist_ids = Coinlist::all('coin_id')->pluck('coin_id')->toArray();
//get all ids to update (to ignore other ids):
$updatable_ids = array_values(array_intersect($exist_ids, $allCoinIds));//result for example is: array("bitcoin","etherium");
//and now, update the database:
Coinlist::whereIn('coin_id', $updatable_ids)
->update([
'symbol' => $coinsList[$key]['symbol'],
'name' => $coinsList[$key]['name'],
'updated_at' => now()
]);
the problem is, I don't have the "$key" in order to update the right row, what am I missing here?
Thanks!
Here is a good way to solve it:
in the beginning, I used this library: https://github.com/mavinoo/laravelBatch
to update many dynamic rows, but it was really slow, then thanks to Yasin, I moved to: https://github.com/iksaku/laravel-mass-update and now it works way better.
the implementation is simple, add a simple code to the Model class, then add:
User::massUpdate(
values: [
['username' => 'iksaku', 'name' => 'Jorge González'],
['username' => 'gm_mtz', 'name' => 'Gladys Martínez'],
],
uniqueBy: 'username'
);
while uniqueBy is the key for the row, and add other columns values to change them dynamically.

Laravel Validate if there is already a record with similar combination of two columns

For example, I have an auction where Users can bid on items.
When a user creates a new bid I want to be sure that this user didn't bid on this item before.
The BID table structure is id, item_id, user_id, price. So basically I need to check if there is a record that has same item_id and same user_id at the same time.
Is there any way to do this using Laravels Validator?
$validator = Validator::make($request->all(), [
'item_id' => 'unique:item_id,user_id,NULL,id,'. auth()->user()->id,
'price' => 'required|integer'
]);
The error I have:
Undefined offset: 1
According to Laravel docs:
[
'item_id' => 'unique:bids,item_id,null,id,user_id,' . auth()->id(),
]
Create a model for Users table.
Now,
$itemIds= User:: where ('user_id',$userId)->pluck('item_Id');
foreach($itemIds as $itemId){
if ($itemId == $newItemId) {
// write code if item id is already present
}
else {
// write code if item id is not present
}
}
you can use laravel unique validation as
'user_id' => 'unique:item_id,user_id,NULL,id,'.$user->id

Is there a way to check if a couple of inputs are unique in laravel 5.2?

update
What I have is a table with these columns:
- ID
- production_year
- type
If the type is already present in the table with the value the user wants to pass, check if production_year is already present too, but fail the validation ONLY if these values are present in the same record. Otherwise let the user to store this record.
I'm trying to check the uniqueness of a couple of fields in the same record...
I've seen the documentation about the conditional validation, but I didn't quite find the answer there.
the code
public function rules()
{
return [
// I'd like to check the uniqueness of both of them. In the same record
'production_y' => 'required|unique',
'fk_type' => 'required|unique',
];
}
Any idea? Thanks!
Laravel 5.3 Update:
Now, you can generate the same rule fluently using the Rule (\Illuminate\Validation\Rule) class.
NULL,id part of the string way is no more required. See:
public function rules()
{
$type = $this->get('fk_type');
return [
'production_y' => [
'required',
Rule::unique('your_table', 'production_year')->where(function($query) {
$query->where('type', $type);
}),
],
];
}
Original Answer
Can't test right now, can you try:
public function rules()
{
$type = $this->get('fk_type');
return [
'production_y' => "required|unique:your_table,production_year,NULL,id,type,{$type}",
// ...
];
}
Explaination:
unique:your_table Set the table for the unique check.
,production_year This matches with production_y.
,NULL,id check all the records.
3.1. if you use like {$id},id it will check uniqueness except the record with the {$id},
,type,{$type} and the type should be {$type}
That will produce sth. like (not exact query, just to express the idea):
select count(*) from your_table where production_year = $product_y and where type = $type and where id <> null
if someone cames from laravel 8, i tried this and it worked !!
for me i need to check the uniqueness of (category_id,subcategory_id) which mean you can find (1,2),(1,3),(2,1),(2,3) but you cant find similar couple !!
'category' => "required|unique:tickets,category_id,NULL,id,subcategory_id,{$request->input('subcategory')}"

Laravel 5 multiple table unique validation

For example, I have 2 tables : sites1 and sites2
I need to check that field url which is comes from my html form is unique.
Here my validation rule :
public function rules()
{
return [
'url' => unique:sites1|unique:sites2'
];
}
Unfortunately, this rule applies only for sites2 table. Is there any possible ways to validate both tables?
Your validation rule seems ok. Just make sure that both sites1 and sites2 table has field name url and both in same database.
Your unique:sites1 rule will be translated into SQL
select count(*) as aggregate from `sites1` where `url` = ?
While unique:sites2 rule will be translated into SQL
select count(*) as aggregate from `sites2` where `url` = ?
See if first SQL does return result. Long URL may result non unique if used with limited index length. It may be better if you could store hash value of URL so you can compare url just by using hash.
No need to maintain the same name in two different tables
In laravel 4.2
Validator::make(Input::all, [
'url' => 'unique:site1,your_column_name|unique:site2:your_column_name_2'
]);
Laravel 5.*:
$this->validate($request,[
'url' => 'unique:site1,your_column_name|unique:site2:your_column_name_2'
]);
Hopefully it's working fine.
In the above answer i think you can't use custom error message, you can do in another way just copy the filed in another field for the two checks.
public function validator(array $data)
{
$data = ['url2' => $data['email']];
$rules = [
'url' => 'unique:sites1',
'url2' => 'unique:sites2',
];
$messages = [
'url.unique' => 'url unique in site 1',
'url2.unique' => 'url unique in site 2',
];
return $validator = Validator::make($data, $rules, $messages);
}
if ($validator->fails()) {
if(!empty($validator->errors()->get('url2'))) {
$validator->errors()->add("url", 'url unique in site 2');
}
}

Cache to Avoid Database calls in validator : Laravel 5.2

What I am doing ?
I am fetching the records from database in 2 ways.
Approach 1
Imposing the validation before saving the record
$v = \Validator::make($request->all(), [
'Category' => 'required|unique:tblcategory|max:25|min:5'
]);
if ($v->fails()) {
return \Redirect::back()
->withErrors($v)
->withInput();
}
Approach 2
Fetching the records from database
$Categories = \App\Models\Skill\Category_Model::all();
What's the question ?
In Approach 2, I could avoid database calls by implementing the cache with below code \Cache::put('Categories', $Categories, 60);
How can I avoid Database calls in case of Approach 1
you could retrieve the categories. and then use it like so:
$cats = implode(',', $Categories);
$v = \Validator::make($request->all(), [
'Category' => 'required|not_in:'.$cats.'|max:25|min:5'
]);
You have a validator rule unique:tblcategory. unique rule will check the database if the category (I suppose, the id) exists. You can't really have that validation and expect it not to check the database.
Caching the unique rule would be quite a weird way to go since you REALLY don't want the values to duplicate which could happen if you cache the categories.

Categories