Laravel unique validation of two columns when validating against an array - laravel

I can validate two table columns for uniqueness by customizing the where query like this.
'email' => [
'required',
Rule::unique('users')->where(function ($query) {
return $query->where('account_id', $this->request('account_id'));
})
]
How would i do a similar thing when validating an array of data?
'email.*' => [
'required',
Rule::unique('users')->where(function ($query) {
// How can i customize the query per array element?
})
]

2022 Update
Laravel 9 now has functionality for this exact problem.
https://laravel.com/docs/9.x/validation#accessing-nested-array-data
Ended up with the following, though i was hoping there was a way to access the current index of the currently validated array element from within the function params themself.
$i = 0;
'email.*' => [
'required',
Rule::unique('users')->where(function ($query) use (&$i) {
return $query->where('account_id', $this->request('account_id')[$i]);
$i += 1;
})
]

Related

make better code in laravel many to many relation

hi i wrote this code and it works just fine but i think its not the best way to do it!
i want to get all the jobs for 1 company.
each company can have many addresses and each address can have many jobs
here is my code:
$company = Company::find($id)->with('addresses.jobDetails.job')->first();
$jobs = [];
foreach ($company->addresses as $address) {
foreach ($address->jobDetails as $detail) {
array_push($jobs, [
'id' => $detail->job->id,
'title' => $detail->job->title,
'country' => $detail->job->country,
'city' => $detail->job->city,
'type' => $detail->job->type,
'work_types' => JobType::where('job_id',$detail->job->id)->pluck('title'),
'income' => $detail->income,
]);
}
}
return $jobs;
can anyone help me to change this to better code please
thank you in advance
You do the opposite and start with JobDetails
$jobDetails = JobDetail::whereHas('address.company', function($companyQuery) use($id) {
$companyQuery->where('id', $id);
})->whereHas('jobs', function($jobQuery) {
$jobQuery->where('is_active', 1);
})->with('jobs')->get();
foreach ($jobDetails as $detail) {
array_push($jobs, [
'id' => $detail->job->id,
'title' => $detail->job->title,
'country' => $detail->job->country,
'city' => $detail->job->city,
'type' => $detail->job->type,
'work_types' => JobType::where('job_id',$detail->job->id)->pluck('title'),
'income' => $detail->income,
]);
}
return $jobs;
EDIT:
In your query
Company::find($id)->with('addresses.jobDetails.job')->first();
You run 4 queries with eager loading. one for each model. You can check in the result that you got that all the data is present in the variable $company.
The example I gave you it runs only two queries, the first one (job_details) will use joins to filter the Job results by the id of the companies table (you can make it faster by using the field company_id in the addresses table)
The second one is for the jobs relation using eager loading.

How to validate array values as part of a unique set of values in Laravel?

I have a days table with day, start_time, end_time columns. I've set these 3 columns as a unique set of values in my migration $table->unique(['start_time', 'end_time', 'day']).
Currently I'm validating them like this:
'day.*.day' => [
'required',
],
'time.*.start_time' => [
'required', 'different:time.*.end',
],
'time.*.end_time' => [
'required', 'different:time.*.start',
]
But I also want to add Rule::unique() validation rule so each set of values are different from each other. I've done similar validation but not to an array value.
I've tried tinkering with it for hours, I did try to loop some stuff but unfortunately it doesn't work that way.
foreach ($schedule->days as $day) {
$time = request()->validate([
"day" => [
'required',
Rule::unique('days')
->where('day', request('day')[$day->id]['day'])
->where('start_time', request('time')[$day->id]['start_time'])
->where('end_time', request('time')[$day->id]['end_time'])
],
// and so on ...
Just modify a little part from this
Validator::make($data, [
'data.ip' => [
'required',
Rule::unique('servers')->where(function ($query) use($ip,$hostname) {
return $query->where('ip', $ip)
->where('hostname', $hostname);
}),
],
],

Problems with Laravel data validation

I'm having some problems with validations in my api.
I need to send a json array like this:
[
{
"acktime": "2021-09-25 08:45:07",
"temp": 15.6
},
{
"acktime": "2021-09-25 08:45:07",
"temp": 15.6
}
probably more array....
]
I would like to vaidate one by one array and store only the valid data returning error for unvalid data, I have tried a foreach cylce but it convert the array to object but the validate::make want only array.
I have tried this:
$validator = Validator::make($request->all(), [
'*.acktime' => 'required',
'*.temp' => 'required|numeric'
]);
$validatedData = $validator->validated();
var_dump($validatedData);
return response()->json($validatedData);
But If I send wrong data I get only error without having valid data, so I've tried this way:
foreach($datas as $data){
$arr = (array)$data;
$validator = Validator::make($arr, [
'acktime' => 'required',
'temp' => 'required|numeric'
]);
if ($validator->fails()) {
continue;
} else {
$newrawData = new rawData([
'acktime' => $data->acktime,
'temp' => $data->temp,
'synctime' => now()
]);
$newrawData->save();
}
}
return response('OK', 200); //or error if some data are not ok
}
In this way it work, bot I have no idea about get, a probable, validation error..(for the moment there's a continue for continue the cycle) any suggestion?
There are two ways for approaching this kind of validation:
make a custom rule in laravel validation from below and put your validation code in it and this will work:
https://laravel.com/docs/8.x/validation#custom-validation-rules
easier way:
$data = [ 'data' => $requests->all() ];
$validator = Validator::make($data, [
'data.*.name' => 'required|string',
'data.*.' => 'required|string'
]);

Laravel - Unique Request Rules allows duplicate

In Laravel-5.8 I applied Rules Request for multiple fields as shown below:
public function rules()
{
return [
'goal_type_id' => [
'required',
Rule::unique('appraisal_goals')->where(function ($query) {
return $query
->where('employee_id', 1)
->where('appraisal_identity_id', 1);
})
],
'appraisal_doc' => 'nullable|mimes:doc,docx,xls,xlsx,ppt,pptx,pdf,jpg,jpeg,bmp,png,|max:5000',
'weighted_score' => 'required|numeric|min:0|max:500',
];
}
This is mysql query:
ALTER TABLE appraisal_goals
ADD CONSTRAINT appraisal_goals_uniq1 UNIQUE KEY(goal_type_id,appraisal_identity_id,employee_id);
This is meant for create. From the code the combination of goal_type_id, employee_id and appraisal_identity_id are unique.
When I click on submit in create blade, it allows duplicate.
How do I resolve this?
Also, how do I write the one for update?
Please note that my route is appraisal_goal
Thank you
Try this code for update
public function rules()
{
$appraisal_goal_id = 'take your appraisal_goals id here from request';
return [
'goal_type_id' => [
'required',
Rule::unique('appraisal_goals')->ignore($appraisal_goal_id, 'id')->where(function ($query) {
return $query
->where('employee_id', 1)
->where('appraisal_identity_id', 1);
})
],
'appraisal_doc' => 'nullable|mimes:doc,docx,xls,xlsx,ppt,pptx,pdf,jpg,jpeg,bmp,png,|max:5000',
'weighted_score' => 'required|numeric|min:0|max:500',
];
}

Right way to handle this situation using Laravel validation

i am new in Laravel and I would like to have some directive on how to handle this situation.
I have two entities: Ad and Nomination. Ad can have many Nominations.
In a controller i receive two external inputs: [ad_id] and [nomination_id] both required.
What i have to do with these two inputs is:
Check if [ad_id] is an existing Ad entity and his attribute "active" is true.
Check [nomination_id] is an existing Nomination entity.
Only if [ad_id] was an existing Ad and [nomination_id] was an existing Nomination check if this Nomination belongs to this Ad.
Can you show me an example about how to manage this using only validation class?
You can write your validation rules like this
public function rules()
{
return [
'ad_id' => [
'bail',
'required',
Rule::exists('ads')->where(function ($query) use ($request) {
$query->where([
['active' => 1],
['id' => $request->ad_id]
]);
}),
],
'nomination_id' => [
'bail',
'required',
Rule::exists('nominations')->where(function ($query) use ($request) {
$query->where([
['ad_id' => $request->ad_id],
['id' => $request->nomination_id]
]);
}),
],
];
}
Assuming you have ads and nominations are tables name and primary key field is id and ad_id as foreign key in nominations table.
It's pretty straightforward - you can write validation rules just as you listed them in your question:
$validator = Validator::make($request->only('ad_id', 'nomination_id'), [
'ad_id' => 'required|exists:ads,id,active,1',
'nomination_id' => 'required|exists:nominations,id,ad_id,' . $request->ad_id,
]);
if ($validator->fails()) {
...
}
$inputAd = <some_value>;
$inputNomination = <some_value>;
$nomination = Nomination::where(['id' => $inputNomination])->with(['ads'])->first();
if(!$nomination || !($nomination->ad_id == $inputAd)) {
// not the same
}
// same
To validate the ad_id and nomination_id, you can use laravel in rule.
FormRequest Class
public function rules()
{
return [
'ad_id' => [
'required',
Rule::in(Ad::where('active', true)->pluck('id')->toArray()),
],
'nomination_id' => [
'required',
Rule::in(Nomination::where('id', $this->nomination_id)->where('ad_id', $this->ad_id)->pluck('id')->toArray()),
],
];
}
The Rule::in(Ad::where('active', true)->pluck('id')->toArray()), rule will check if the ad_id is present in the array of ids of Ad which have active field is true.
The Rule::in(Nomination::where('id', $this->nomination_id)->where('ad_id', $this->ad_id)->pluck('id')->toArray()), rule will check if the nomination_id is present in the array of ids of Nomination which is related to Ad.

Resources